2014-04-10 11 views
8

Mamy własny hostowany serwer SignalR w naszej aplikacji WPF. WebApp uruchamia się po uruchomieniu aplikacji. Przy wyjściu aplikacji usuwamy funkcję WebApp.Usuwanie Microsoft.Owin.Hosting.WebApp zgłasza "System.ObjectDisposedException"

public void Start() 
    { 
     myWebApp = WebApp.Start<MyApp>(url); 
    } 

    private void Dispose(bool isDisposing) 
    { 
     if (disposed) return; 

     if (isDisposing) 
      myWebApp.Dispose(); 

     disposed = true; 
    } 

Wezwanie do myWebApp.Dispose() podnosi 'System.ObjectDisposedException'. Czy robię coś nie tak? . W Microsoft.Owin * DLL mieć wersję 2.1.0 i 2.0.3 samodzielne gospodarz SignalR

UPDATE: okazuje jest to pierwszy wyjątek szansa które widzę w visual studio, ponieważ ustawienie „break na Wyjątki clr "jest aktywny. Ten wyjątek wydaje się być obsługiwany wewnętrznie i nie pojawia się w naszym kodzie

+0

Może to być pierwsza szansa w twoim przypadku, ale jeśli używane jest oprogramowanie pośredniczące NLog: 'appBuilder.UseNLog()' loguje wyjątek jako błąd. – SerG

Odpowiedz

3

Po zapoznaniu się z kodem źródłowym Katana, znalazłem przyczynę tego problemu. Jest to metoda Microsoft.Owin.Host.HttpListener.OwinHttpListener.ProcessRequestsAsync(). Zaczyna się while-loop zawierający wywołanie _listener.GetContextAsync() prywatnej instancji HttpListener w sekcji try-catch.

Także urządzenia klasy IDisposable i zawiera metodę Dispose(). Ta metoda udostępnia prywatną instancję HttpListener.

Po wywołaniu WebApp.Start() zwraca instancję IDisposable, że ma tylko Dispose() metodę, która uzdalnia OwinHttpListener.

Po jej usunięciu wywołuje się metodę Dispose() z OwinHttpListener, która udostępnia prywatny HttpListener.

Ale w tym samym czasie ProcessRequestsAsync() dzwoni _listener.GetContextAsync(), ale _listener jest już wyrzucony i wyrzuca ObjectDisposedException. catch blokuj rejestr wyjątków i wraca z ProcessRequestsAsync().

Myślę, że podwójna blokada czeku w ProcessRequestsAsync() może być dobrym rozwiązaniem.

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(); 
} 
+0

Więc nie ma sposobu, aby rozwiązać problem bez przepisywania Katany. Czy to jest poprawne? – SerG

+1

@SerG Tak, jest. Wszystko, co możesz zrobić, to zostawić obiekt, zwrócony przez WebApp.Start(), nieusuwalny. – Tim

+0

Nie jestem pewien, gdzie najlepiej byłoby sprawdzić blokowanie przez podwójne sprawdzenie. Wydaje się jednak, że metoda Dispose powinna zrobić więcej, aby zamknąć proces asynchronizowania, który wciąż próbuje wykonać czynności, gdy pod nim zostanie usunięty słuchacz. –