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.AsyncMessagePump(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.InputQueue1.AsyncQueueReader.Set(Item item) at1.Dispatch() at
System.Runtime.InputQueue
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 completedSynchronously,
Exception exception) at
System.ServiceModel.Channels.ReliableChannelBinder1.InputAsyncResult1.OnInputComplete(IAsyncResult
result) at
System.ServiceModel.Channels.ReliableChannelBinder1.InputAsyncResult1.OnInputCompleteStatic(IAsyncResult
result) at
System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult
result) at System.Runtime.AsyncResult.Complete(Boolean
completedSynchronously) at
System.Runtime.InputQueue1.AsyncQueueReader.Set(Item item) at1.EnqueueAndDispatch(Item item, Boolean
System.Runtime.InputQueue
canDispatchOnThisThread) at
System.Runtime.InputQueue1.EnqueueAndDispatch(T item, Action1.ClientSecurityDuplexSessionChannel.CompleteReceive(IAsyncResult
dequeuedCallback, Boolean canDispatchOnThisThread) at
System.ServiceModel.Security.SecuritySessionClientSettings
result) at
System.ServiceModel.Security.SecuritySessionClientSettings1.ClientSecurityDuplexSessionChannel.OnReceive(IAsyncResult1.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.Security.SecuritySessionClientSettings
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.ReliableChannelBinder1.InputAsyncResult1.OnInputComplete(IAsyncResult
result) at
System.ServiceModel.Channels.ReliableChannelBinder1.InputAsyncResult1.OnInputCompleteStatic(IAsyncResult
result) at
System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult
result) at System.Runtime.AsyncResult.Complete(Boolean
completedSynchronously) at
System.Runtime.InputQueue1.AsyncQueueReader.Set(Item item) at1.Dispatch() at
System.Runtime.InputQueue
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
wsDualHttpBindingbecause 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
wsDualHttpBindingcreated 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 processTo accomplish what you’re describing, you would need to implement an independent
wsDualHttpBindingconnection manager within the ASP.NET context. I think it would be much simpler to avoid using thewsDualHttpBindingbinding altogether and create a simple token-based polling message pattern to simulate the callback mechanism.