We have a self-hosted SignalR server in our WPF application. The WebApp gets started on application startup. On application exit we dispose of the WebApp.
public void Start()
{
myWebApp = WebApp.Start<MyApp>(url);
}
private void Dispose(bool isDisposing)
{
if (disposed) return;
if (isDisposing)
myWebApp.Dispose();
disposed = true;
}
The call to myWebApp.Dispose() raises a 'System.ObjectDisposedException'. Am I doing something wrong? The Microsoft.Owin.* dlls have the version 2.1.0 and the SignalR self host 2.0.3
UPDATE: Turns out this is the first chance exception which I can see in visual studio because the setting "break on clr exceptions" is active. This exception seems to be handled internally and does not bubble up into our code
After exploring the Katana source code, I found a reason for this problem. It is the Microsoft.Owin.Host.HttpListener.OwinHttpListener.ProcessRequestsAsync()
method. It starts while-loop containing _listener.GetContextAsync()
call of a private HttpListener
instance in try-catch section.
Also class implements IDisposable
and contains a Dispose()
method. This method disposes the private HttpListener
instance.
When you call WebApp.Start()
it returns an instance of IDisposable
, that only has Dispose()
method, that disposes OwinHttpListener
.
So, when you dispose it, you call its Dispose()
method of OwinHttpListener
, which disposes the private HttpListener
.
But at the same time ProcessRequestsAsync()
calls _listener.GetContextAsync()
, but _listener
is already disposed and throws ObjectDisposedException
. catch
block log the exception and returns from ProcessRequestsAsync()
.
I think, that double check lock in ProcessRequestsAsync()
may be a good option.
private async void ProcessRequestsAsync()
{
while (_listener.IsListening && CanAcceptMoreRequests)
{
Interlocked.Increment(ref _currentOutstandingAccepts);
HttpListenerContext context;
try
{
context = await _listener.GetContextAsync();
}
(SOME_OTHER_CATCHES)
catch (ObjectDisposedException ode)
{
// These happen if HttpListener has been disposed
Interlocked.Decrement(ref _currentOutstandingAccepts);
LogHelper.LogException(_logger, "Accept", ode);
return;
}
(SOME_OTHER_CODE)
}
}
public void Dispose()
{
if (_listener.IsListening)
{
_listener.Stop();
}
((IDisposable)_listener).Dispose();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With