从启用了 ajax 的 WCF 服务传达错误异常详细信息

本文关键字:错误 异常 详细信息 服务 WCF 启用 ajax | 更新日期: 2023-09-27 18:31:24

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

所以!当服务检测到错误的数据协定时,它们会编译 ValidationErrorsSummary 对象中的所有验证错误,并引发 FaultException

我希望客户端能够检索 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 已接受,而客户端没有收到响应正文。我尝试创建附加到服务本身的 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 to Response.Write to the Response stream。这不起作用,因为由于某种原因,响应上限为 10 个字符(即使我将内容长度设置为 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异常,或者至少在我的情况下,确保 ValidationErrorsSummary 继承自该类。这不起作用,因为 GetDetail 使用序列化程序检索详细信息,并且由于自定义派生类不是 ExceptionDetail 类的已知类型,因此序列化将失败。所以你必须坚持使用基类。

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

这真的很糟糕。:(

从启用了 ajax 的 WCF 服务传达错误异常详细信息

由于WebScriptEnablingBehavior类的实现方式,我决定放弃这个想法。我将"利用"它是一个 Web 服务的事实,并将验证错误作为 HTTP 标头而不是 X-Validation-Errors 传达。