从支持Ajax的WCF服务传递FaultException详细信息?

时间:2016-01-21 17:57:56

标签: c# asp.net ajax wcf .net-4.5

我的所有服务都有 enableWebScript 行为配置,因为我认为它是与现有客户端应用程序集成最方便的行为。应用程序由一些相对复杂的表单组成。在客户端上执行基本验证,当服务接收表单数据时,它们执行更全面的验证。

原来如此!当服务检测到错误的数据协定时,它们会编译 ValidationErrorsSummary 对象中的所有验证错误,并抛出 FaultException< ValidationErrorsSummary>

我希望客户能够检索 ValidationErrorsObject ,但由于我还没有启用 includeExceptionDetailInFaults ,他们只会收到:

{"ExceptionDetail":null,"ExceptionType":null,"Message":"The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.","StackTrace":null}

我试过了:

1)通过实现 IErrorHandler 创建自定义错误处理程序,但它似乎与 enableWebScript 一起使用。代码运行,但响应仍然默认默认为 202 Accepted ,而客户端没有收到响应正文。我已经尝试创建附加到服务本身的 IServiceBehavior 属性,并将服务行为配置为 web.config 中的自定义配置元素。

public class ErrorWebHttpBehavior : WebHttpBehavior
{
    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        // clear default error handlers.
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();

        // add our own error handler.
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ValidationErrorHandler());
    }
}

public class ValidationErrorBehaviorAttribute : Attribute, IServiceBehavior
{
    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcherBase channelDispatcher in serviceHostBase.ChannelDispatchers)
        {
            var dispatcher = channelDispatcher as ChannelDispatcher;
            if (dispatcher != null)
                dispatcher.ErrorHandlers.Add(new ValidationErrorHandler());
        }
    }

    // ...
}

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

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        object details;

        var summary = error as FaultException<ValidationErrorsSummary>;
        if (error != null)
            details = summary.Detail.Errors;
        else
            details = "The server was unable to process the request due to an internal error.";

        // create a fault message containing our FaultContract object
        fault = Message.CreateMessage(version, "", details, new DataContractJsonSerializer(details.GetType()));

        // tell WCF to use JSON encoding rather than default XML
        var wbf = new WebBodyFormatMessageProperty(WebContentFormat.Json);
        fault.Properties.Add(WebBodyFormatMessageProperty.Name, wbf);

        // return custom error code.
        var rmp = new HttpResponseMessageProperty();
        rmp.StatusCode = System.Net.HttpStatusCode.BadRequest;
        rmp.StatusDescription = "Bad request";
        fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
    }
}

// ...

var summary = new ValidationErrorsSummary { Errors = validator.Errors };
throw new WebFaultException<ValidationErrorsSummary>(summary, System.Net.HttpStatusCode.BadRequest);

2)拦截请求本身并使用 HttpContext Response.Write 到响应流。这不起作用,因为响应由于某种原因限制为10个字符(即使我将 Content-Length 设置为JSON字符串的长度。

那我该怎么办?有任何想法吗?我希望传达任意异常信息,但我确实希望我的验证摘要能够传达给客户。

我已查看WebScriptEnablingBehavior的源代码,并在 JsonFaultBodyWriter 类中找到了该代码:

if (includeExceptionDetailInFaults)
{
    faultDetail.Message = fault.Reason.ToString();
    if (fault.HasDetail)
    {
        try
        {
            ExceptionDetail originalFaultDetail = fault.GetDetail<ExceptionDetail>();
            faultDetail.StackTrace = originalFaultDetail.StackTrace;
            faultDetail.ExceptionType = originalFaultDetail.Type;
            faultDetail.ExceptionDetail = originalFaultDetail;
        }
        // ...
    }
}
else
{
    faultDetail.Message = System.ServiceModel.SR.GetString(System.ServiceModel.SR.SFxInternalServerError);
}

我可以通过查看源代码做出两个假设:

  • 要填充 ExceptionDetails ,您必须确保在我的 FaultException&lt; ExceptionDetail&gt; 例外,或至少例如,确保 ValidationErrorsSummary 继承自该类。这不起作用,因为 GetDetail 使用序列化程序检索详细信息,并作为自定义派生类不是 ExceptionDetail 类的已知类型,序列化失败。所以你必须坚持使用基类。

  • 如果不启用 includeExceptionDetailInFaults ,则无法接收有关故障的信息。我的意思是,你甚至无法控制错误信息。

这真的很糟糕。 :(

1 个答案:

答案 0 :(得分:0)

由于 WebScriptEnablingBehavior 类的实现方式,我决定放弃这个想法。我和#34;剥削&#34;事实上它是一个Web服务并将验证错误传达为HTTP头而不是 X-Validation-Errors