简短版本:在启用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”只是一种通用的错误处理方法,可以显示有关错误的详细信息。
答案 0 :(得分:18)
编辑:使用正确的自定义json错误处理程序更新帖子
<serviceDebug includeExceptionDetailInFaults="true"/>
在您的服务行为中,您将获得所需的所有详细信息。
应用程序中的所有异常都将转换为JsonError
并使用DataContractJsonSerializer
进行序列化。 Exception.Message
直接使用。 FaultExceptions提供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
}
Webbehaviour用于安装上述错误处理程序
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>
答案 1 :(得分:2)
我能够获得异常细节的唯一方法是使用
<serviceDebug includeExceptionDetailInFaults="true"/>
我尝试了扩展HttpWebBehavior的建议方法,但是当它与enableWebScript一起使用时,如下所示:
<behavior name="JsonBehavior">
<myWebHttp/>
<enableWebScript/>
</behavior>
WCF调用将返回状态代码202而没有任何信息。 如果配置变为
<behavior name="JsonBehavior">
<enableWebScript/>
<myWebHttp/>
</behavior>
您将获得格式良好的消息,但您将丢失所有json格式化功能以及从enableWebScript请求参数解析,这完全违背了使用enableWebScript的目的
我也尝试过FaultContract,但它似乎只适用于服务引用而不适用于JQuery的AJAX调用。
能够覆盖WebScriptEnablingBehavior或服务本身来提供自定义错误处理会很好。
答案 2 :(得分:2)
我遇到了与BerndBumüller和user446861相同的问题,在最后,我只是恢复使用我的WCF服务的行为。瞧,你不再需要任何IErrorHandler了。你可以抛出WebFaultException / WebFaultException类型,客户端的一切都很好。
webHttp与enableWebScript(从我理解的webHttp派生的webscript)基本相同,减去ASP.NET Ajax的内容(ScriptManager ServiceReference等等)。由于我使用的是jQuery,因此我不需要自动生成的JS服务代理和其他Ajax.net包。这非常适合我的需求,所以我想发布一条评论,万一其他人还在寻找一些信息。
答案 3 :(得分:0)
区分错误状态的首选方法是通过响应上的http状态代码。这可以在服务方法中手动设置,但我不确定这是否是解决此问题的最佳方法:
[ServiceContract(Namespace = "MyNamespace")]
AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class MyService
{
[OperationContract]
public void DoStuff(string param1, string etc)
{
try
{
//Do some stuff that maybe causes an exception
}
catch(ExceptionType1 ex)
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.BadRequest;
}
catch(ExceptionType2 ex)
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Conflict;
}
... etc.
}
}
答案 4 :(得分:0)
我建议包装异常并让所有异常通过服务包装。您期望的那些将使用有意义的消息过滤掉(如上例所示)。一般情况只会说:
抛出新的ApplicationException(“未知错误”);
通过这种方式,您不会向客户端提供有关服务内部工作方式的信息,但是如果您需要将错误信息传递给客户端(如安全异常等),则可以显示有意义的消息。 / p>