【问题标题】:WCF asynchronous callbackWCF 异步回调
【发布时间】:2011-08-24 04:03:13
【问题描述】:

我已经在我的代码中成功实现了 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);
}

为了使用同步回调,我声明了我的通道和端点,如下所示:

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">

我无法正确组合端点和通道来利用异步回调。有人能指出我正确的方向吗?

另外当下面这行代码执行时:

OperationContext.Current.GetCallbackChannel<IAsyncMessageCallback>();

我收到以下错误:

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

【问题讨论】:

    标签: .net wcf asynchronous callback


    【解决方案1】:

    您需要将服务合同 IMessage 的 CallbackContract 属性更改为该类型 (IAsyncMessageCallback)。下面的示例使用异步回调运行。

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

    【讨论】:

    • Figueria - 感谢您的回复,但是当我将客户端放在单独的线程上并调用 AddMessage 时,它​​会在调用 BeginInvoke 时阻塞。
    • 您是否将服务的并发模式设置为 Multiple(或可重入)?您还可以将 [CallbackBehavior] 添加到回调类(在我发布的示例中为 MyClientCallback),以在客户端设置并发模式。尝试将其设置为 Multiple 以查看您看到的是否是死锁。
    • 我试了各种方法都没有成功。让我更清楚一点,在我的架构中,我有一个服务于多个客户端的服务。客户端调用服务端函数 AddMessage,服务可以在函数 OnMessageAdded 上回调客户端(希望是异步的)。所以 AddMessage 在服务端实现, OnMessageAdded 在客户端实现。
    • 我更改了添加的代码以在单独的线程中进行调用,甚至在单独的线程上创建了多个客户端,我仍然没有问题。您可以尝试做的一件事是从一个工作代码开始(我的示例对您有用吗?)然后开始慢慢修改它,直到您遇到它中断的点,这将是一个很好的信息。
    • 谢谢卡洛斯。我会按照你的建议去做。我一直在尝试将您的代码嵌入我的代码中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多