2011-06-22 17 views
9

estoy corriendo un ServiceHost para probar uno de mis servicios y todo funciona bien hasta que lanzo un FaultException - Bang consigo XML no JSONWCF servicio JSON devuelto XML de Falla

mi contrato de servicio - preciosa

/// <summary> 
    /// <para>Get category by id</para> 
    /// </summary> 
    [OperationContract(AsyncPattern = true)] 
    [FaultContract(typeof(CategoryNotFound))] 
    [FaultContract(typeof(UnexpectedExceptionDetail))] 
    IAsyncResult BeginCategoryById(
     CategoryByIdRequest request, 
     AsyncCallback callback, object state); 

    CategoryByIdResponse EndCategoryById(IAsyncResult result); 

anfitrión Set-up - deliciosos yum

var host = new ServiceHost(serviceType, new Uri(serviceUrl)); 
host.AddServiceEndpoint(
    serviceContract, 
    new WebHttpBinding(), "") 
     .Behaviors.Add(
      new WebHttpBehavior 
          { 
           DefaultBodyStyle = WebMessageBodyStyle.Bare, 
           DefaultOutgoingResponseFormat = WebMessageFormat.Json, 
           FaultExceptionEnabled = true 
          }); 

host.Open(); 

Ésta es la llamada - oo vientre dolor

var request = WebRequest.Create(serviceUrl + "/" + serviceName); 
request.Method = "POST"; 
request.ContentType = "application/json; charset=utf-8"; 
request.ContentLength = 0; 

try 
{ 
    // receive response 
    using (var response = request.GetResponse()) 
    { 
     var responseStream = response.GetResponseStream(); 

     // convert back into referenced object for verification 
     var deserialiser = new DataContractJsonSerializer(typeof (TResponseData)); 
     return (TResponseData) deserialiser.ReadObject(responseStream); 
    } 
} 
catch (WebException wex) 
{ 
    var response = wex.Response; 

    using (var responseStream = response.GetResponseStream()) 
    { 
     // convert back into fault 
     //var deserialiser = new DataContractJsonSerializer(typeof(FaultException<CategoryNotFound>)); 
     //var fex = (FaultException<CategoryNotFound>)deserialiser.ReadObject(responseStream); 

     var text = new StreamReader(responseStream).ReadToEnd(); 
     var fex = new Exception(text, wex);  

     Logger.Error(fex); 
     throw fex; 
    } 
} 

el texto var contiene el error correcto, pero serializado como Xml ¿Qué he hecho mal aquí?

Respuesta

3

La respuesta es poner en práctica un comportamiento IErrorHandler y apoyar

me encontré con este excelente mensaje por iainjmitchell

http://iainjmitchell.com/blog/?p=142

+2

es difícil cómo lanzar una FaultException para clientes SOAP y WebHttpException para clientes REST ... No lo he descifrado. – Junto

+0

@Junto, ¿alguna vez te diste cuenta? ¿Simplemente proporciona un punto final separado para cada cliente con la configuración de comportamiento necesaria para cada uno? –

+0

@MrMoose Tengo una pregunta abierta aquí: http://stackoverflow.com/questions/7188519/wcf-ierrorhandler-to-return-faultexception-to-soap-and-webhttpexception-to-pox-a. ¿Has intentado lanzar una nueva WebHttpException () {...}; y ver qué pasa en el cliente SOAP? – Junto

0

Esto probablemente no le dará la parte de "por qué". Echa un vistazo a this question. Te permite tomar y reformatear las fallas antes de que salgan como respuesta. Esto al menos JSensezará tus respuestas lo suficiente como para ponerte en marcha. this también tiene una idea similar detrás de él.

+0

Gracias por eso, pueda tienen que hacer algo similar, pero parece que están atrapando a cualquier persona mayor.Excepción neta y hacerla JSON: mis excepciones son las FaultExceptions correctas y quiero que la Config defina cómo se devuelven, en este caso JSON, pero puede implementarse en algún lugar que desee xml. Supongo que también puedo codificarlo, pero parece que me falta algo simple que hará que WCF se comporte como lo necesito, de nuevo, gracias por los enlaces –

0

Según MSDN documentation for DataContractJsonSerializer:

"Si se produce un error durante la serialización de una respuesta saliente en el servidor o la operación de respuesta se produce una excepción por alguna otra razón, es posible que no nos devuelve al cliente como un fallo "

Además, y esto es mera especulación, pero casi parece que este serializador se serializa en XML y luego lo convierte en JSON. Entonces, cuando ocurre su falla, ¿se interrumpe a mitad del proceso? Por otra parte, podría estar totalmente equivocado.

Buena suerte.

+0

que se devuelve al cliente como un error, simplemente serializado como Xml. Además, no estoy seguro si ocurrió un error en el bit especulativo que mencionas, pero, si lo hiciera, ¿volvería a aparecer? Ta de todos modos –

0

No entiendo por qué está utilizando WebRequest para realizar llamadas a un servicio WCF. ¿Hay una razón específica para esto? ¿Cómo sabes cuando manejas ese WebException que será un FaultException<CategoryNotFound>?
Si utiliza un proxy de servicio, y su servicio arroja FaultException<T>, es probablemente mejor para escribir su try-catch así:

try 
{ 
    //Do service call 
} 
catch (FaultException<CategoryNotFound> fe) 
{ 
    //handle CategoryNotFound 
} 
catch (FaultException<UnexpectedExceptionDetail> fe) 
{ 
    //handle UnexpectedExceptionDetail 
} 
catch (FaultException exc) 
{ 
    //stuf 
} 
catch(Exception general){ 
    //all other stuff that might blow up 
} 
+0

Esto es para probar, pasaré el tipo esperado a la función. La WebRequest está actuando como un cliente JSON –

2

que puede presentar felizmente la solución. Tuve exactamente el mismo problema y después de jugar un poco con la configuración de comportamiento de mi punto final, descubrí el elemento de configuración necesario. La solución es forzar WCF usen el formato seleccionado (JSON):

<behavior name="ExtendedJSONBehavior"> 
    <webHttp defaultOutgoingResponseFormat="Json" defaultBodyStyle="Wrapped" automaticFormatSelectionEnabled="false"/> 
</behavior> 

Como se puede ver, la clave era la "automaticFormatSelectionEnabled" atributo.

Diviértete con WCF nuevo

+2

no funciona para mí, sigue recibiendo XML de nuevo, no JSON –

+0

revisé el atributo de nuevo. Este atributo es compatible con .Net 4.0. ¿Usas 4.0? Y trate de lanzar "WebFaultException" en lugar de FaultException. Estoy usando FaulException de .Net a .Net y WebFaultException de .Net a Browser. – Firzen

+0

Tengo el mismo problema, pero uso .Net 3.5 y sé que estos atributos solo existen en .Net 4.0. ¿Qué puedo hacer para lograr esto en .Net 3.5 (vea mi pregunta al respecto en http://stackoverflow.com/questions/12095621/consume-json-wcf-service-with-net-3-5-client) –

0
//由于调用 ProvideFault 时,客户端处于阻塞状态,不要在这里进行长时间的操作 
public void ProvideFault(Exception error, MessageVersion version, ref Message msg) 
{ 
    //避免敏感信息泄漏,例如:数据库配置, error包含的错误信息应该记录到服务器的日志中,不能显示给客户端 
    // FaultException<int> e = new FaultException<int>(123, error.Message); 
    DateTime now = DateTime.Now; 
    time = now.ToString("yyyyMMddHHmmssfff", DateTimeFormatInfo.InvariantInfo);// "" + now.Year.ToString() + now.Month.ToString() + now.Day.ToString() + now.Hour.ToString() + now.Minute.ToString() + now.Second.ToString() + now.Millisecond.ToString(); 
    string errorMsg = "服务内部错误_" + time; 
    // FaultException fe = new FaultException(errorMsg); 
    // MessageFault mf = fe.CreateMessageFault(); 
    // msg = Message.CreateMessage(version, mf, fe.Action); 

    //The fault to be returned 
    msg = Message.CreateMessage(version, "", errorMsg, new DataContractJsonSerializer(typeof(string))); 

    // tell WCF to use JSON encoding rather than default XML 
    WebBodyFormatMessageProperty wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json); 

    // Add the formatter to the fault 
    msg.Properties.Add(WebBodyFormatMessageProperty.Name, wbf); 

    //Modify response 
    HttpResponseMessageProperty rmp = new HttpResponseMessageProperty(); 

    // return custom error code, 400. 
    rmp.StatusCode = System.Net.HttpStatusCode.InternalServerError; 
    rmp.StatusDescription = "Bad request"; 

    //Mark the jsonerror and json content 
    rmp.Headers[HttpResponseHeader.ContentType] = "application/json"; 
    rmp.Headers["jsonerror"] = "true"; 

    //Add to fault 
    msg.Properties.Add(HttpResponseMessageProperty.Name, rmp); 
} 
+1

Solo la respuesta del código no es o.k., por favor ponga también el texto (inglés) la próxima vez aquí. – peterh

Cuestiones relacionadas