简体   繁体   中英

invoke WCF using wsDualHttpBinding

I have a standalone Application which is using WCF with wsDualHttpBinding. This standalone application will randomly send message to any client which has subcribe the service by using the callback behavior of wsDualHttpBinding.

The application subcribe and callback behavior is worked successfully if we use a window application as a client.

Then I want to create an ASP.Net application which use SignalR as server push and subcribe the service provided by the above standalone application. When any message come back from the application, we will use SignalR to push the message and display it in browser.

However, when tried to create such ASP.Net application, whenever the message callback from the standalone Application, the ASP.Net application will be shutdown.

The following is the code for the hub of SignalR

 public class MessageSubcriberHub : Hub
{
    private static readonly Dictionary<string, MessageSubcriber> Subcribers = new Dictionary<string, MessageSubcriber>();

    public bool Subcribe()
    {
        if (Subcribers.Keys.Contains(Context.ConnectionId))
        {
            return true;
        }
        try
        {
            MessageSubcriber sub = new MessageSubcriber();
            sub.ConnectionId = Context.ConnectionId;
            if (sub.Subcribe())
            {
                sub.listener += (string message, DateTime time) =>
                {
                    try
                    {
                        var context = GlobalHost.ConnectionManager.GetHubContext<MessageSubcriberHub>();
                        context.Clients.Client(sub.ConntectionId).MessageReceived(message, time);
                    }
                    catch
                    {
                        if (Subcribers.Keys.Contains(sub.ConntectionId))
                        {
                            Subcribers.Remove(sub.ConntectionId);
                        }
                    }
                };
                Subcribers.Add(Context.ConnectionId, sub);
                return true;
            }
            else
            {
                return false;
            }
        }
        catch (Exception ex)
        {
            return false;
        }
    }

    public bool Unsubcribe()
    {
        if (Subcribers.Keys.Contains(Context.ConnectionId))
        {
            try
            {
                Subcribers[Context.ConnectionId].Dispose();
                Subcribers.Remove(Context.ConnectionId);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        return true;
    }

    public override Task OnDisconnected()
    {
        //return Clients.All.leave(Context.ConnectionId, DateTime.Now.ToString());
        return new Task(new Action(()=>{
            if (Subcribers.Keys.Contains(Context.ConnectionId))
            {
                try
                {
                    Subcribers[Context.ConnectionId].Dispose();
                    Subcribers.Remove(Context.ConnectionId);
                }
                catch (Exception ex)
                {
                }
            }
        }));            
    }

And the following is the code for the callback client

[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MessageSubcriber : IMessagingServiceCallback, IDisposable
{
    public string ConnectionId;

    MessagingServiceClient client;
    public delegate void MessageReceivedListener(string message, DateTime time);

    public event MessageReceivedListener listener;

    public MessageSubcriber()
    {
        InstanceContext context = new InstanceContext(this);
        client = new MessagingServiceClient(context, "WSDualHttpBinding_IMessagingService");
    }

    public bool Subcribe()
    {
        return client.Subscribe();
    }

    public bool Unsubcribe()
    {
        return client.Unsubscribe();
    }

    public virtual void MessageReceived(string message, DateTime time)
    {
        if (listener != null)
        {
            listener.Invoke(message, time);
        }
    }

    public void Dispose()
    {
        client.Close();
    }
}

I have checked the event viewer after the ASP.net Application shutdown. The following is the message shown in event viewer

An unhandled exception occurred and the process was terminated.

Application ID: 6ccca6be

Process ID: 6184

Exception: System.Runtime.FatalException

Message: Object reference not set to an instance of an object.

StackTrace: at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet) at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext) at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext) at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessageP ump(IAsyncResult result) at System.ServiceModel.Dispatcher.ChannelHandler.OnAsyncReceiveComplete(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.InputQueue 1.AsyncQueueReader.Set(Item item) at System.Runtime.InputQueue 1.Dispatch() at System.ServiceModel.Channels.ReliableDuplexSessionChannel.ProcessDuplexMessage(WsrmMessageInfo info) at System.ServiceModel.Channels.ClientReliableDuplexSessionChannel.ProcessMessage(WsrmMessageInfo info) at System.ServiceModel.Channels.ReliableDuplexSessionChannel.HandleReceiveComplete(IAsyncResult result) at System.ServiceModel.Channels.ReliableDuplexSessionChannel.OnReceiveCompletedStatic(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.AsyncResult.Complete(Boolean completedSynchr onously, Exception exception) at System.ServiceModel.Channels.ReliableChannelBinder 1.InputAsyncResult 1.OnInputComplete(IAsyncResult result) at System.ServiceModel.Channels.ReliableChannelBinder 1.InputAsyncResult 1.OnInputCompleteStatic(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.InputQueue 1.AsyncQueueReader.Set(Item item) at System.Runtime.InputQueue 1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread) at System.Runtime.InputQueue 1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread) at System.ServiceModel.Security.SecuritySessionClientSettings 1.ClientSecurityDuplexSessionChannel.CompleteReceive(IAsyncResult result) at System.ServiceModel.Security.SecuritySessionClientSettings 1.ClientSecurityDuplexSessionChannel.OnReceive(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously, Exception exception) at System.ServiceModel.Security.SecuritySessionClientSettings 1.ClientSecurityDuplexSessionChannel.OnReceive(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously, Exception exception) at System.ServiceModel.Security.SecuritySessionClientSettings 1.ClientSecuritySessionChannel.ReceiveAsyncResult.OnReceive(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously, Exception exception) at System.ServiceModel.Channels.ReliableChannelBinder 1.InputAsyncResult 1.OnInputComplete(IAsyncResult result) at System.ServiceModel.Channels.ReliableChannelBinder 1.InputAsyncResult 1.OnInputCompleteStatic(IAsyncResult result) at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result) at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously) at System.Runtime.InputQueue 1.AsyncQueueReader.Set(Item item) at System.Runtime.InputQueue 1.AsyncQueueReader.Set(Item item) at System.Runtime.InputQueue 1.Dispatch() at System.Runtime.InputQueue`1.OnDispatchCallback(Object state) at System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped) at System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)

InnerException: System.NullReferenceException

Message: Object reference not set to an instance of an object.

StackTrace: at System.Web.HttpApplication.ThreadContext.Enter(Boolean setImpersonationContext) at System.Web.HttpApplication.OnThreadEnterPrivate(Boolean setImpersonationContext) at System.Web.AspNetSynchronizationContext.CallCallbackPossiblyUnderLock(SendOrPostCallback callback, Object state) at System.Web.AspNetSynchronizationContext.CallCallback(SendOrPostCallback callback, Object state) at System.Web.AspNetSynchronizationContext.Post(SendOrPostCallback callback, Object state) at System.ServiceModel.Dispatcher.ThreadBehavior.BindCore(MessageRpc& rpc, Boolean startOperation) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc)

Does anyone have any idea?

Your Windows client works over the wsDualHttpBinding because WCF is able to create a durable session between the client and the WCF service that persist for a given timeout period.

ASP.NET is a server side framework that grabs a thread from a designated app pool to handle an incoming HTTP request, creates an HTTP response and returns that thread to the app pool. The problem you're having is that ASP.NET will tear down any wsDualHttpBinding created session (this is NOT equivalent an ASP.NET session) by the WCF service when called from the ASP.NET code. Basically, ASP.NET apps instantiates a WCF client that persist only for the duration of an HTTP request/response pair and your callback target is removed as a result of the tear down process

To accomplish what you're describing, you would need to implement an independent wsDualHttpBinding connection manager within the ASP.NET context. I think it would be much simpler to avoid using the wsDualHttpBinding binding altogether and create a simple token-based polling message pattern to simulate the callback mechanism.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM