I have a self-hosted WCF Service with a peer-to-peer binding. I'm using a DuplexChannel for getting responses. The connection to the ServiceHost is working, but when the callback is being invoked I get the above mentioned ArgumentException
, even though I'm not using any TransactionFlowProperties.
[ServiceContract(SessionMode = SessionMode.Allowed, CallbackContract = typeof(ICallbackService))]
public interface IService
{
[OperationContract(IsOneWay = true)]
void Login(string email, string password);
[OperationContract(IsOneWay = true)]
void Logout(int userId);
}
[DataContract]
public class User
{
[DataMember]
public string Email {get; set;}
[DataContract]
public string Password {get; set;}
}
My IService implementation :
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Service : IService
{
private static Dictionary<ICallbackService, ICallbackService> pair = new Dictionary<ICallbackService, ICallbackService>();
private static Dictionary<string, ICallbackService> clients = new Dictionary<string, ICallbackService>();
private ICallbackService callback;
public Service(){}
public void Login(string email, string password)
{
// User user = getAllUsers().Find(u => u.Email.ToLower() == email.ToLower() && u.Password == password);
User user = new User(){Email = email, Password = password}; //for testing purposes
callback = OperationContext.Current.GetCallbackChannel<ICallbackService>();
if (user != null)
{
Console.WriteLine("user : " + email + " has logged in");
clients.Add(email, callback);
callback.Authenticate(true);
}
else callback.Authenticate(false);
}
public void Logout(int userId)
{
//TODO
}
}
My callback service :
public interface ICallbackService
{
[OperationContract(IsOneWay = true)]
void Authenticate(bool authenticated);
}
The implementing callback service class in my client application :
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Single, UseSynchronizationContext = false)]
public class Client : Service.ICallbackService,
{
public bool Authentication { get; internal set; }
public Client()
{
}
public void Authenticate(bool authenticated)
{
Console.WriteLine("authentication : " + authenticated);
Authentication = authenticated;
}
}
Proxy class and User class are in a separate client application:
public class Proxy : IService
{
public Proxy(InstanceContext context)
{
init(context);
}
private void init(InstanceContext context)
{
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
binding.Security.Mode = SecurityMode.Transport;
// binding.CloseTimeout = TimeSpan.FromSeconds(1);
// binding.OpenTimeout = TimeSpan.FromSeconds(2);
// binding.ReceiveTimeout = TimeSpan.FromSeconds(15);
// binding.SendTimeout = TimeSpan.FromSeconds(15);
DuplexChannelFactory<IService> channel = new DuplexChannelFactory<IService>(context, binding, new EndpointAddress("net.tcp://localhost:4242"));
service = channel.CreateChannel();
}
public void Login(string email, string password)
{
service.Login(email, password);
}
public void Logout(int id)
{
service.Logout(id);
}
}
public class User
{
Client client;
IService service;
public User()
{
client = new Client();
InstanceContext context = new InstanceContext(client);
service = new Proxy(context);
}
public void Login(string email, string password)
{
service.Login(email, password);
bool valid = client.Authentication;
if(valid) Console.WriteLine("Login successful");
}
}
This is how I start my ServiceHost in my Server application :
public class Server
{
public static void Main(string[] args)
{
Service service = new Service();
ServiceHost host = host = new ServiceHost(service, new Uri("net.tcp://localhost:4242"));
host.Open();
Console.WriteLine("opened server ...");
Console.ReadLine();
}
}
I solved this problem using a NetTcpBinding
. The above code is working now.