2012-11-29 29 views
7

Mamy API REST zbudowane z użyciem WCF.Nieprawidłowy wyjątek WebFaultException podczas korzystania ze strumienia i zamykania strumienia.

Załatwiamy wszystkie wyjątki backend z WebFaultException tak:

throw new WebFaultException<string>(e.Message, HttpStatusCode.NotAcceptable); 

to działa dobrze z wyjątkiem jednego scenariusza, w którym robimy Post, ze strumieniem.

Przykładem tego:

[WebInvoke(Method = "POST", UriTemplate = "saveUser?sessionId={sessionId}&userId={userId}", 
     RequestFormat = WebMessageFormat.Json, 
     ResponseFormat = WebMessageFormat.Json,    
     BodyStyle = WebMessageBodyStyle.WrappedRequest)] 
    [OperationContract] 
    string SaveUser(string sessionId, int userId, Stream stream); 

Podczas przenoszenia tego strumienia w użyciu instrukcji, ilekroć my wtedy napotkasz wyjątek my wciąż otrzymuję:

Od Skrzypek:

HTTP/1.1 400 Bad Request 
    <p>The server encountered an error processing the request. The exception message is 'The message object has been disposed.'. See server logs for more details. The exception stack trace is: </p> 
    <p> at System.ServiceModel.Channels.ByteStreamMessage.InternalByteStreamMessage.get_Properties() 
    at System.ServiceModel.OperationContext.get_IncomingMessageProperties() 
    at System.ServiceModel.Dispatcher.WebErrorHandler.ProvideFault(Exception error, MessageVersion version, Message&amp; fault)</p> 

Wygląda na to, że ma coś wspólnego ze strumieniem i StreamRead er jest unieszkodliwiony.

Następnie próbowałem usunąć wszystko, co pozbędzie się StreamReadera, a ten acctualy działa. Kod obsługi to teraz wygląda następująco:

enter image description here

To rozwiązuje problem z wysłaniem poprawne komunikaty o wyjątkach, ale jak źle to wpłynie na nasz wniosek, nie zamykając lub unieszkodliwiania naszą StreamReader? Czy widzisz inne sposoby rozwiązania tego problemu?

Odpowiedz

7

Dzieje się tak, ponieważ StreamReader przejmuje "własność" strumienia. Innymi słowy, odpowiada za zamknięcie strumienia źródłowego. Gdy tylko twój program zadzwoni do dyspozycji Dispose or Close (zostawiając w twoim przypadku zakres instrukcji using), wówczas również wyśle ​​strumień źródłowy. Wzywając sr.Dispose() w twoim przypadku. Strumień pliku jest następnie martwy.

Jeśli nie chcesz tego, możesz utworzyć nową klasę, która dziedziczy z StreamReader i zastępuje metodę Close; wewnątrz metody Close wywołaj Dispose (false), która nie zamyka strumienia.

Można również użyć klasy NonClosingStreamWrapper z biblioteki MiscUtil Jona Skeeta, która służy właśnie temu celowi.

Ale lepiej nie opuszczać StreamReadera bez jego usunięcia, ponieważ nie można wyczyścić żadnych niezarządzanych zasobów.

Powiązane problemy