2011-05-12 18 views
6

Implementé con éxito el patrón de devolución de llamada WCF en mi código y ahora deseo implementar una devolución de llamada asincrónica. Aquí está mi código de la interfaz:Retorno de llamada asincrónico WCF

[ServiceContract(Name = "IMessageCallback")] 
public interface IMessageCallback 
{ 
    [OperationContract(IsOneWay = true)] 
    void OnMessageAdded(string message, DateTime timestamp); 
} 

[ServiceContract(Name="IMessageCallback")] 
public interface IAsyncMessageCallback 
{ 
    [OperationContract(AsyncPattern = true)] 
    IAsyncResult BeginOnMessageAdded(string msg, DateTime timestamp, AsyncCallback callback, object asyncState); 
    void EndOnMessageAdded(IAsyncResult result); 
} 

[ServiceContract(CallbackContract = typeof(IMessageCallback))] 
public interface IMessage 
{ 
    [OperationContract] 
    void AddMessage(string message); 
} 

Para usar la devolución de llamada síncrona declaré mi canal y el punto final, así:

DuplexChannelFactory<IMessage> dcf = new DuplexChannelFactory<IMessage>(new InstanceContext(this), "WSDualHttpBinding_IMessage"); 
<endpoint address="net.tcp://localhost:8731/Message/" 
      binding="netTcpBinding" 
      contract="WCFCallbacks.IMessage" name="WSDualHttpBinding_IMessage"> 

Estoy teniendo problemas para conseguir la combinación correcta de punto final y el canal de utilizar el asíncrona llamar de vuelta. ¿Alguien me puede apuntar en la dirección correcta?

Además, cuando se ejecuta la siguiente línea de código:

OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>(); 

me sale el siguiente error:

Unable to cast transparent proxy to type 'WCFCallbacks.IAsyncMessageCallback' 

Respuesta

10

es necesario cambiar la propiedad CallbackContract de la I-Mensaje contrato de servicio de ese tipo (IAsyncMessageCallback). El siguiente ejemplo se ejecuta con la devolución de llamada asíncrona.

public class StackOverflow_5979252 
{ 
    [ServiceContract(Name = "IMessageCallback")] 
    public interface IAsyncMessageCallback 
    { 
     [OperationContract(AsyncPattern = true)] 
     IAsyncResult BeginOnMessageAdded(string msg, DateTime timestamp, AsyncCallback callback, object asyncState); 
     void EndOnMessageAdded(IAsyncResult result); 
    } 
    [ServiceContract(CallbackContract = typeof(IAsyncMessageCallback))] 
    public interface IMessage 
    { 
     [OperationContract] 
     void AddMessage(string message); 
    } 
    [ServiceBehavior(IncludeExceptionDetailInFaults = true, ConcurrencyMode = ConcurrencyMode.Multiple)] 
    public class Service : IMessage 
    { 
     public void AddMessage(string message) 
     { 
      IAsyncMessageCallback callback = OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>(); 
      callback.BeginOnMessageAdded(message, DateTime.Now, delegate(IAsyncResult ar) 
      { 
       callback.EndOnMessageAdded(ar); 
      }, null); 
     } 
    } 
    class MyClientCallback : IAsyncMessageCallback 
    { 
     public IAsyncResult BeginOnMessageAdded(string msg, DateTime timestamp, AsyncCallback callback, object asyncState) 
     { 
      Action<string, DateTime> act = (txt, time) => { Console.WriteLine("[{0}] {1}", time, txt); }; 
      return act.BeginInvoke(msg, timestamp, callback, asyncState); 
     } 

     public void EndOnMessageAdded(IAsyncResult result) 
     { 
      Action<string,DateTime> act = (Action<string,DateTime>)((System.Runtime.Remoting.Messaging.AsyncResult)result).AsyncDelegate; 
      act.EndInvoke(result); 
     } 
    } 
    static Binding GetBinding() 
    { 
     return new NetTcpBinding(SecurityMode.None); 
    } 
    public static void Test() 
    { 
     string baseAddress = "net.tcp://" + Environment.MachineName + ":8000/Service"; 
     ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress)); 
     host.AddServiceEndpoint(typeof(IMessage), GetBinding(), ""); 
     host.Open(); 
     Console.WriteLine("Host opened"); 

     InstanceContext instanceContext = new InstanceContext(new MyClientCallback()); 
     DuplexChannelFactory<IMessage> factory = new DuplexChannelFactory<IMessage>(instanceContext, GetBinding(), new EndpointAddress(baseAddress)); 
     IMessage proxy = factory.CreateChannel(); 
     proxy.AddMessage("Hello world"); 

     Console.Write("Press ENTER to close the host"); 
     Console.ReadLine(); 
     ((IClientChannel)proxy).Close(); 
     factory.Close(); 
     host.Close(); 
    } 
} 
+0

Figueria - Gracias por la respuesta, pero cuando pongo a mis clientes en un hilo separado y llamo AddMessage bloquea cuando se llama a BeginInvoke. – user481779

+0

¿Está configurando el modo de concurrencia en Múltiple (o reentrada) en su servicio? También puede agregar [CallbackBehavior] a la clase de devolución de llamada (MyClientCallback en el ejemplo que publiqué) para establecer el modo de concurrencia en el cliente. Intente configurarlo en Múltiple para ver si lo que está viendo es un punto muerto. – carlosfigueira

+0

Lo probé de todos modos sin éxito. Permítanme ser más claro que en mi arquitectura tengo un servicio que sirve a múltiples clientes. Los clientes llaman a la función de servicio AddMessage y el servicio puede realizar una devolución de llamada a los clientes (con suerte de forma asíncrona) en la función OnMessageAdded. De modo que AddMessage se implementa o en el lado del servicio y OnMessageAdded en el lado del cliente. – user481779

Cuestiones relacionadas