У меня есть собственная WCF-служба с одноранговой привязкой. Я использую DuplexChannel для получения ответов. Соединение с ServiceHost работает, но когда обратный вызов вызывается, я получаю вышеупомянутый ArgumentException
, хотя я не использую TransactionFlowProperties. РеализацияWCF: ArgumentException: TransactionFlowProperty уже существует
[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;}
}
Мои IService:
[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
}
}
Мой обратный вызов службы:
public interface ICallbackService
{
[OperationContract(IsOneWay = true)]
void Authenticate(bool authenticated);
}
Исполнительное обратного вызова класса обслуживания в моем клиентском приложении:
[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 и класс пользователя находятся в отдельном клиентском приложении:
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");
}
}
Это, как я начинаю ServiceHost в моем приложении сервера:
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();
}
}
Если вы это поняли, лучше всего, если вы опубликуете ответ в качестве ответа и отметьте его, а не отредактируете исходное сообщение и заголовок. – lgaud