Wcf асинхронный шаблон не генерирует Fault Exception - PullRequest
2 голосов
/ 24 августа 2010

У меня есть служба, которая реализует шаблон Async:

[OperationContract(AsyncPattern = true)]
IAsyncResult BeginLoadDocument(Byte[] value, AsyncCallback callback, object state);

Boolean EndLoadDocument(IAsyncResult asyncResult);

«BeginLoadDocument» запускает закрытый метод «CallBack» на стороне службы, используя ThreadPool:

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;
    }

метод обратного вызова загружает документ и устанавливает результат для «EndLoadDocument».

Пока все хорошо, но как я могу обработать исключения?

Если я выбрасываю исключение на стороне сервера, я получаю FaultedException'1, который не обрабатывается.Я пытался использовать атрибут [FaultContract(typeof(InforError))], где «InfoError» - это мой custum DataMember, но он не работает.

Я создаю прокси-сервер с помощью svcutil / a http: ....

Ответы [ 2 ]

1 голос
/ 21 января 2011

Похоже, вы используете Silverlight.Проблема заключается в том, что служба WCF возвращает статус HTTP, отличный от 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)
    {
    }
}

Для получения более подробной информации смотрите Понимание ошибок WCF в Silverlight .

1 голос
/ 24 августа 2010

Вы можете перехватить исключительную ситуацию на стороне клиента следующим образом:

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" - это моеcustum 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 s при вызове EndLoadDocument (при условиибыло сгенерировано исключение InfoErrorException).

На стороне сервера необходимо перехватывать исключения, а затем заключать их в FaultException, например:

catch (IOException exp) {
    InfoErrorException myException = new InfoErrorException();
    myException.Reason = "I failed:  " + exp.Message;
    throw new FaultException<InfoErrorException>(myException);
}

Я считаю (но должен был бы перепроверить), что вы также можете поймать FaultException на стороне клиента без указания типа ... похоже на перехват универсального System.Exception.

Ваш try...catch для FaultException должен быть в вашем обратном вызове вокруг оператора для вызова EndLoadDocument().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...