0

背景 我正在创建一个 ASP.net 应用程序,它使用自定义库(尚未公开发布,但很快)为 jQuery 中的 javascript 客户端提供长轮询处理程序。客户端将调用处理程序,等到处理程序返回一些数据,显示它,然后再次点击处理程序......清洗,冲洗,重复。

处理程序的工作是接受请求,将其放入一个集合(通常是 a List<>)并等待一个事件,其中包含要返回到等待请求的数据。我已经对此进行了测试,在我的服务器上的静态类中使用了一个简单的事件,这一切都很好。

问题 为了让所有客户端都能接收到消息,在我服务器上的所有 AppDomains 中,我创建了一个简单的 C# 控制台应用程序 - 它在后台运行并通过 WCF (NamedPipe) 提供 DataContract。然后我在 ASP.net 中创建了一个客户端对象,它可以通过 WCF 接口与控制台应用程序对话。

我可以同步地将消息拉入/推送到我的缓存中 - 这工作正常。但是,当我尝试在 WCF 合同上使用异步模式时,EndMethod会在我要求它之前触发它,直接在将 IAsyncResult 返回到 BeginMethod 之后。

我看不出有什么问题 - 谷歌有大量资源显示弱示例,但它们无济于事。

我想要的 是他们无论如何都要通过数据合同绑定到 WCF 上的事件吗?这样我就可以附加到事件并完成它。进入缓存的新消息会触发我的事件,这会触发异步处理程序返回所有等待的请求。

这可能吗,如果可以,是否有人有任何示例/教程/示例?

要遵循的代码...

4

1 回答 1

2

我知道这是可能的,因为我已经这样做了,并且知道那里的信息有限(我计划很快创建一篇博客文章)。基本上,您需要创建Subscribe/UnsubscribeWCF 方法,这将使您的端口保持打开状态。

您的服务器代码应如下所示:

[ServiceContract(SessionMode = SessionMode.Required,
    CallbackContract = typeof(IProcessorCallBack))]
public interface IProcessor
{
    [OperationContract]
    Boolean SubscribeToEvents();

    [OperationContract]
    Boolean UnsubscribeToEvents();
}

public interface IProcessorCallBack
{
    [OperationContract(IsOneWay = true)]
    void OnEvent(EventArgs args);
}

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class DDSpeechMikeProcessor:IProcessor
{
    private readonly List<IProcessorCallBack> _eventListeners = 
        new List<IProcessorCallBack>();

    public bool SubscribeToEvents()
    {
        var listenerToCallBacks =    
            OperationContext.Current.GetCallbackChannel<IProcessorCallBack>();
        if(!_eventListeners.Contains(listenerToCallBacks))
            _eventListeners.Add(listenerToCallBacks);
    }

    public bool UnsubscribeToEvents()
    {
        var listenerToCallBacks = 
            OperationContext.Current.GetCallbackChannel<IProcessorCallBack>();
        if (_eventListeners.Contains(listenerToCallBacks))
            _eventListeners.Remove(listenerToCallBacks);
    }

    //This is your server listening for the main event
    //which it will pass on to all listeners
    void OnEvent(EventArgs args)
    {
        foreach(var listener in _eventListeners)
        {
            try
            {
                listener.OnEvent(args);
            }
            catch (Exception exception)
            {
                RemoveListenerIfBadCommunication(listener, exception);
            }
        }
    }

    //If a listener did not unsubscribe before shutting down you will get exceptions
    private void RemoveListenerIfBadCommunication(IProcessorCallBack listener, 
        Exception exception)
    {
        if (exception.GetType() == typeof(CommunicationException)
            || exception.GetType() == typeof(CommunicationObjectAbortedException)
            || exception.GetType() == typeof(CommunicationObjectFaultedException)
        )
           _eventListeners.Remove(listener);
    }
}

在您的客户端代码中:

public class Client : IProcessorCallBack
{
    DuplexChannelFactory<IProcessor> _processorFactory;
    IProcessor _processor
    void OpenProcessor()
    {
        _speechMikeProcessorFactory = new DuplexChannelFactory<IProcessor>(
              this,
              new NetNamedPipeBinding(),
              new EndpointAddress(baseUri + @"/" + HostName));
        _processor = _speechMikeProcessorFactory.CreateChannel();
        _processor.SubscribeToEvents();
    }

    void OnEvent(EventArgs args)
    {
         //Do Stuff
    }
}

如果我需要更详细地解释任何事情,请告诉我

于 2012-06-20T15:39:54.150 回答