小编典典

从启用AJAX的WCF服务返回错误详细信息

ajax

简短版本: 在启用AJAX的WCF服务中引发异常时(除了仅打开闸门并将所有异常详细信息发送回去),是否有建议的方法将错误详细信息返回给客户端?

长版:

我有一个相对简单的启用AJAX的WCF服务,可以使用默认服务代理从客户端调用该服务。我在下面提供了代码段,但我不认为代码本身有什么问题。

我的问题是,如果我在服务中引发异常,则返回给客户端的错误对象总是通用的:

{
    "ExceptionDetail":null,
    "ExceptionType":null,
    "Message":"The server was unable to process the request..."
    "StackTrace":null
}

理想情况下,我想根据出了什么问题在客户端上显示不同的错误消息。

一种选择是允许WCF故障中的异常,这将为我提供完整的堆栈跟踪信息以及所有内容,但是我感谢与此有关的安全问题,实际上,这比我需要的信息多得多。我可以通过发送一个描述问题或某些内容的字符串来解决问题,但是我看不到解决方法。

我的服务代码:

[ServiceContract(Namespace = "MyNamespace")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService
{
    [OperationContract]
    public void DoStuff(string param1, string etc)
    {
        //Do some stuff that maybe causes an exception
    }
}

在客户端上:

MyNamespace.MyService.DoStuff(
    param1,
    etc,
    function() { alert("success"); },
    HandleError);

其中“ HandleError”只是一种通用的错误处理方法,将显示有关该错误的详细信息。


阅读 256

收藏
2020-07-26

共1个答案

小编典典

编辑: 使用适当的自定义json错误处理程序更新了帖子

快速但不推荐的方式。

<serviceDebug includeExceptionDetailInFaults="true"/>

在您的服务行为中会为您提供所需的所有详细信息。

不错的方法

应用程序中的所有异常都将转换为,JsonError并使用进行序列化DataContractJsonSerializer。的Exception.Message是直接使用。FaultException提供FaultCode,而其他异常则以Faultcode
-1威胁为未知。

FaultException是使用HTTP状态代码400发送的,其他异常是HTTP代码500-内部服务器错误。这不是必需的,因为故障代码可用于确定它是否是未知错误。但是在我的应用程序中很方便。

错误处理程序

internal class CustomErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error)
    {
        //Tell the system that we handle all errors here.
        return true;
    }

    public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)
    {
        if (error is FaultException<int>)
        {
            FaultException<int> fe = (FaultException<int>)error;

            //Detail for the returned value
            int faultCode = fe.Detail;
            string cause = fe.Message;

            //The json serializable object
            JsonError msErrObject = new JsonError { Message = cause, FaultCode = faultCode };

            //The fault to be returned
            fault = Message.CreateMessage(version, "", msErrObject, new DataContractJsonSerializer(msErrObject.GetType()));

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

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

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

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

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

            //Add to fault
            fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
        }
        else
        {
            //Arbitraty error
            JsonError msErrObject = new JsonError { Message = error.Message, FaultCode = -1};

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

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

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

            rmp.Headers[HttpResponseHeader.ContentType] = "application/json";
            rmp.Headers["jsonerror"] = "true";

            //Internal server error with exception mesasage as status.
            rmp.StatusCode = System.Net.HttpStatusCode.InternalServerError;
            rmp.StatusDescription = error.Message;

            fault.Properties.Add(HttpResponseMessageProperty.Name, rmp);
        }
    }

    #endregion
}

用于安装上述错误处理程序的Web行为

internal class AddErrorHandlerBehavior : WebHttpBehavior
{
    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        base.AddServerErrorHandlers(endpoint, endpointDispatcher);

        //Remove all other error handlers
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
        //Add our own
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new CustomErrorHandler());
    }
}

json错误数据协定

指定json错误格式。在此处添加属性以更改错误格式。

[DataContractFormat]
public class JsonError
{
    [DataMember]
    public string Message { get; set; }

    [DataMember]
    public int FaultCode { get; set; }
}

使用错误处理程序

自托管

ServiceHost wsHost = new ServiceHost(new Webservice1(), new Uri("http://localhost/json"));

ServiceEndpoint wsEndpoint = wsHost.AddServiceEndpoint(typeof(IWebservice1), new WebHttpBinding(), string.Empty);

wsEndpoint.Behaviors.Add(new AddErrorHandlerBehavior());

App.config

<extensions>  
  <behaviorExtensions>  
    <add name="errorHandler"  
        type="WcfServiceLibrary1.ErrorHandlerElement, WcfServiceLibrary1" />  
  </behaviorExtensions>  
</extensions>
2020-07-26