2011-08-25 11 views
16

Mam zestaw webservices SOAP, które są zawijania wyjątki używając IErrorHandler, w szczególności:WCF IErrorHandler wrócić FaultException do SOAP i WebHttpException do POX i JSON punkty końcowe

public sealed class ErrorHandler : IErrorHandler 
{ 
    public bool HandleError(Exception error) 
    { 
     return true; 
    } 

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
     // don't wrap existing fault exceptions 
     if ((error is FaultException)) return; 

     // our basic service fault 
     var businessFault = new BusinessFault { FaultMessage = error.Message, FaultReference = "Internal" }; 

     // Resource based faultReason 
     var faultReason = new FaultReason(Properties.Resources.BusinessFaultReason); 
     var faultcode = FaultCodeFactory.CreateVersionAwareSenderFaultCode(InternalFaultCodes.BusinessFailure.ToString(), Service.Namespace); 

     var faultException = new FaultException<BusinessFault>(
      businessFault, 
      faultReason, 
      faultcode); 

     // Create message fault 
     var messageFault = faultException.CreateMessageFault(); 

     // Create message using Message Factory method 
     fault = Message.CreateMessage(version, messageFault, faultException.Action); 
    } 
} 

Mam teraz dodane dodatkowe punkty końcowe dla Json czy ospy które działają poprawnie, chyba że wystąpi wyjątek. W przypadku punktu końcowego Json wyjątek FaultException jest zwracany jako XML.

Zdaję sobie sprawę z drugiej tak stanowisk, które w przypadku odpoczynku będę lepiej rzuca WebHttpException:

throw new WebFaultException<BusinessFault>(detail, HttpStatusCode.BadRequest); 

lub nadrzędnymi właściwości Komunikat odpowiedzi w ProvideFault, a więc:

var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json); 
fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf); 

var rmp = new HttpResponseMessageProperty 
{ 
    StatusCode = System.Net.HttpStatusCode.BadRequest, 
    StatusDescription = "See fault object for more information." 
}; 
fault.Properties.Add(HttpResponseMessageProperty.Name, rmp); 

Jednak MSDN ma kilka interesujących uwag na temat WebHttpException, mianowicie:

Po śpiewać punkt końcowy REST WCF (WebHttpBinding i WebHttpBehavior lub WebScriptEnablingBehavior) kod statusu HTTP dla odpowiedzi jest ustawiony odpowiednio na . Jednak wyjątek WebFaultException może być używany z punktami końcowymi niebędącymi obiektami REST i zachowuje się jak zwykły wyjątek FaultException.

Podczas korzystania z punktu końcowego usługi WCF REST format odpowiedzi z serializowanego błędu jest określany w taki sam sposób, jak w przypadku odpowiedzi innej niż usterka. Aby uzyskać więcej informacji na temat formatowania REST WCF, zobacz Formatowanie REST WCF.

Byłoby zatem sugerować, że trzeba konwertować mój obecny sposób ProvideFault dostarczenia nowego WebHttpException (zawijania istniejące wyjątki lub FaultExceptions) i następnie SOAP będzie nadal działać, jak również.

Czy ktoś chciałby zabić kogoś, co by to wyglądało (.Net4.0 btw)? Chcę jedną procedurę obsługi błędów, aby rządzić nimi wszystkimi!

+0

nie rozumiem twojego pytania. Czy chcesz mieć unikalną implementację IErrorHandler dla punktu końcowego JSON/POX/SOAP? – Cybermaxs

+1

@Cybermaxs correct. WCF umożliwia prezentowanie wielu punktów końcowych dla różnych typów klientów. Wszystko działa dobrze, dopóki nie musisz podnosić błędów. Jeśli podniosę (ogólnie) błąd SOAP, wówczas klienci HTTP nie będą mądrzejsi. Jeśli zgłoszę usterkę HTTP, klienci SOAP zostaną pozostawieni w ciemności. – Junto

Odpowiedz

0

Byłem pod wrażeniem, że za pomocą webHttpBinding był sposób, aby uzyskać funkcjonalność „all-in-one” z JSON/POX/SOAP w przeciwieństwie do korzystania z oddzielnych powiązania dla każdego (tj wsHttpBinding, basicHttpBinding itd.). Czy nie byłbyś w stanie po prostu rzucić WebHttpException, a następnie uzyskać informacje o wszystkich błędach, które były potrzebne bez względu na technologię?

0

W aplikacji REST nad którą pracuję, stworzyłem nową klasę wywodzącą się z WebFaultException<T>, która dołącza dodatkowe dane do wyjątków złapanych usług. Wywołanie metody CreatingMessageFault() na instancji klasy pochodnej pozwala mi zwrócić wybrane przeze mnie dane wyjątków z metody obsługi błędu w protokole SOAP jako ProvideFault(), pozwalając WCF określić poprawny format komunikatu.

Używam webHttpBinding do wiązania wszystkich, ale niektóre usługi stron trzecich.

Edycja: Dodano przykładowy kod

public class ErrorHandler : IErrorHandler, IServiceBehavior 
{  
    public virtual void ProvideFault(Exception error, MessageVersion version, ref Message fault) 
    { 
     // Include next level of detail in message, if any. 
     MyFaultException myFaultException = 
      ((error is MyFaultException) && 
       ((MyFaultException)error).Detail != null) 
      ? new MyFaultException(error.Message + " - " + 
        ((MyFaultException)error).Detail.Message, error) 
      : new MyFaultException(error.Message, error); 
     MessageFault messageFault = myFaultException.CreateMessageFault(); 
     fault = Message.CreateMessage(version, messageFault, myFaultException.Action); 
    } 
} 

i

/// <summary> 
/// Class used to return exception data from my WCF services. 
/// </summary> 
/// <remarks> 
/// This class is used by a web service to pass exception data back and a 
/// data object to the client. This class inherits WebFaultException, which 
/// is handled specially by the WCF WebServiceHost2 service class and 
/// generates a WebException on the client. 
/// </remarks> 
public class MyFaultException : WebFaultException<BusinessFault> 
{ 
public class MyFaultException : WebFaultException<BusinessFault> 
{ 
    public MyFaultException(string message) 
     : this(HttpStatusCode.BadRequest, message) { } 

    public MyFaultException(HttpStatusCode statusCode, string message) 
     : base(new BusinessFault(message), statusCode) { } 
} 

następnie w swojej służbie, można rzucić wyjątek do przekazywania danych błędów do klienta:

 try 
     { 
      // Successful operation proceeds normally. 
     } 
     catch (ApplicationException e) 
     { 
      // Failure generates MyFaultException. 
      throw new MyFaultException("Operation failed with " + e.Message); 
     } 
+0

Jeśli chciałbyś dodać przykład kodu, mógłbym wypróbować to, co opisałeś. – Junto

+0

Edytowałem swoją odpowiedź, aby dołączyć przykładowy kod. – Suncat2000

+0

Postaram się znaleźć trochę czasu, aby spróbować. Z chęcią odpowiem na twoje pytanie, jeśli chodzi o odpowiedź. Może to trochę potrwać, ponieważ nie pracowałem nad tym projektem przez jakiś czas! – Junto

Powiązane problemy