Search code examples
c#wcfp2pargumentexception

WCF : ArgumentException : TransactionFlowProperty already exists


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();
    }
}

Solution

  • I solved this problem using a NetTcpBinding. The above code is working now.