WCF JSON服务在Fault上返回XML

时间:2011-06-22 13:29:46

标签: wcf json

我正在运行一个ServiceHost来测试我的一个服务,所有工作正常,直到我抛出一个FaultException - 我得到的是XML而不是JSON

我的服务合同 - 可爱

   /// <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);

主机设置 - scrummy 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();

这是电话 - 腹部疼痛

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;
    }
}

text var包含正确的错误,但序列化为Xml 我在这做错了什么?

6 个答案:

答案 0 :(得分:3)

答案是实现IErrorHandler并支持行为

我发现了iainjmitchell的这篇优秀文章

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

答案 1 :(得分:2)

我很乐意提出解决方案。 我有完全相同的问题,在我用我的端点行为配置搞砸了一点后,我发现了所需的配置元素。 解决方案是强制wcf使用所选格式(json):

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

如您所见,关键是“automaticFormatSelectionEnabled”属性。

再次与wcf玩得很开心

答案 2 :(得分:0)

这可能不会给你“为什么”部分。 看看this question。它允许您在故障作为响应出来之前抓取并重新格式化故障。至少Json-ize你的回答足以让你前进。 this背后也有类似的想法。

答案 3 :(得分:0)

根据MSDN documentation for DataContractJsonSerializer

“如果在服务器上序列化传出回复期间发生错误,或者由于某些其他原因而回复操作引发异常,则可能不会将其作为错误返回给客户端。”

此外,这仅仅是猜测,但它几乎看起来像这个序列化程序序列化为XML,然后将其转换为JSON。那么当你的故障发生时,它会在进程中被中断吗?然后我又完全错了。

祝你好运。

答案 4 :(得分:0)

我不明白你为什么使用WebRequest来调用WCF服务。这有什么特别的原因吗?您如何知道何时处理WebException FaultException<CategoryNotFound>?{。} 如果您使用服务代理,并且您的服务引发FaultException<T>,那么最好像这样编写try-catch

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
}

答案 5 :(得分: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);
}