Wcf异步模式不会抛出Fault Exception

时间:2010-08-24 15:29:02

标签: wcf

我有一个实现异步模式的服务:

[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:....

构建代理

2 个答案:

答案 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