我们的 WPF 应用程序中有一个自托管 SignalR 服务器。 WebApp 在应用程序启动时启动。在应用程序退出时,我们会处理 WebApp。
public void Start()
{
myWebApp = WebApp.Start<MyApp>(url);
}
private void Dispose(bool isDisposing)
{
if (disposed) return;
if (isDisposing)
myWebApp.Dispose();
disposed = true;
}
对 myWebApp.Dispose() 的调用引发“System.ObjectDisposeException”。 难道我做错了什么? Microsoft.Owin.* dll 的版本为 2.1.0,SignalR 自主机为 2.0.3
更新:事实证明,这是我在 Visual Studio 中看到的第一次机会异常,因为设置“中断 clr 异常”处于事件状态。这个异常似乎是在内部处理的,不会冒泡到我们的代码中
最佳答案
在探索Katana源代码后,我找到了这个问题的原因。它是 Microsoft.Owin.Host.HttpListener.OwinHttpListener.ProcessRequestsAsync() 方法。它启动 while 循环,其中包含 try-catch 部分中私有(private) HttpListener
实例的 _listener.GetContextAsync()
调用。
该类还实现了 IDisposable
并包含一个 Dispose()
方法。此方法处理私有(private) HttpListener
实例。
当您调用 WebApp.Start()
时,它会返回 IDisposable
的实例,该实例仅具有 Dispose()
方法,该方法可处理 OwinHttpListener
.
因此,当您处置它时,您可以调用其 OwinHttpListener
的 Dispose()
方法,该方法会处置私有(private) HttpListener
。
但同时 ProcessRequestsAsync()
调用 _listener.GetContextAsync()
,但 _listener
已被释放并抛出 ObjectDispositedException
。 catch
block 记录异常并从 ProcessRequestsAsync()
返回。
我认为,ProcessRequestsAsync()
中的双重检查锁可能是一个不错的选择。
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();
}
关于.net - 处置 Microsoft.Owin.Hosting.WebApp 抛出 'System.ObjectDisposedException',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22982278/