我有一个实现异步模式的服务:
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginLoadDocument(Byte[] value, AsyncCallback callback, object state);
Boolean EndLoadDocument(IAsyncResult asyncResult);
“BeginLoadDocument”使用ThreadPool在服务端运行私有方法“CallBack”:
public IAsyncResult BeginLoadDocument(string id, AsyncCallback callback, object state)
{
PendingAsyncResult<string> asyncResult =
new PendingAsyncResult<string>(id, callback, state);
ThreadPool.QueueUserWorkItem(new WaitCallback(Callback), asyncResult);
return asyncResult;
}
Callback方法加载文档并设置“EndLoadDocument”的结果。
到目前为止一切顺利,但我如何处理异常?
如果我在服务器端抛出一个例外,我得到FaultedException'1
未被处理。
我确实尝试使用属性[FaultContract(typeof(InforError))]
,其中“InfoError”是我的术语DataMember,但它不起作用。
我正在使用svcutil / a http:....
构建代理答案 0 :(得分:1)
您可以按如下方式捕获客户端异常:
try {
MyClient.MyCall();
}
catch (FaultException<IOException> exc) {
// Log and handle exception
}
在这个示例中,抛出的真正异常是IOException
。
您在服务界面上还需要FaultContract
,如您所示:
[ServiceContract]
public interface IMyService {
[OperationContract]
[FaultContract(typeof(IOException))]
void MyCall();
}
****编辑****
我对你写的东西有点模糊:
[FaultContract(typeof(InforError))]其中“InfoError”是我的术语DataMember
'DataMember'是什么意思? InfoError
的定义是什么?
[FaultContract]
应该在服务接口方法上定义...在你的帖子中,你听起来像是在试图将它添加到客户端;这是不正确的。如果我修改您的示例代码,它将如下所示:
[ServiceContract]
public interface IMyService {
[OperationContract(AsyncPattern = true)]
[FaultContract(typeof(InfoErrorException))]
IAsyncResult BeginLoadDocument(Byte[] value, AsyncCallback callback, object state);
string EndLoadDocument(IAsyncResult asyncResult);
如果您的服务接口是这样修饰的,那么当您调用FaultException
时,客户端应该能够接收EndLoadDocument
(前提是抛出的异常是InfoErrorException
异常)。
在服务器端,您必须捕获异常,然后将它们包装在FaultException
中,如下所示:
catch (IOException exp) {
InfoErrorException myException = new InfoErrorException();
myException.Reason = "I failed: " + exp.Message;
throw new FaultException<InfoErrorException>(myException);
}
我相信(但必须仔细检查)您还可以在客户端捕获FaultException
而不指定类型...类似于捕获泛型{{ 1}}。
System.Exception
try...catch
的{{1}}应该在您的回调中,围绕要致电FaultException
的声明。
答案 1 :(得分:1)
看起来您正在使用Silverlight。 问题是WCF服务将HTTP Status返回到200,因此浏览器不提供有关Silverlight Runtime响应的其他数据。
解决方案是使用自定义ErrorHandler来提供必要的HTTP代码:
/// <summary>Sets the HTTP code to 200 for faults.</summary>
public class HttpStatusCode200ErrorHandler : IErrorHandler
{
public Type ServiceType { get; set; }
public HttpStatusCode200ErrorHandler(Type serviceType)
{
ServiceType = serviceType;
}
public bool HandleError(Exception error)
{
return false;
}
public virtual void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
fault.Properties[HttpResponseMessageProperty.Name] =
new HttpResponseMessageProperty { StatusCode = System.Net.HttpStatusCode.OK };
}
}
您可以使用以下ServiceBehavior属性将其附加到您的服务:
/// <summary>Applies HttpStatusCode200ErrorHandler.</summary>
[AttributeUsage(AttributeTargets.Class)]
public class HttpStatusCode200BehaviorAttribute : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
dispatcher.ErrorHandlers.Add(new HttpStatusCode200ErrorHandler(serviceDescription.ServiceType));
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
有关详细信息,请查看Understanding WCF Faults in Silverlight。