Использование пользовательского объекта FaultContract, содержащего System.Exception, приводит к сбою добавления ссылки на службу - PullRequest
3 голосов
/ 11 января 2011

Я только что заметил что-то особенное. У меня есть внутренний сервис, который публикуется через basicHttpBinding, и customBinding (http + binary), для которого включены метаданные. Я также включил конечную точку mex для http. Мы используем Visual Studio 2008 & VB.NET

Совсем недавно мы заметили, что нам не удалось успешно добавить ссылку на эту услугу в другие наши проекты. Все, что он генерировал, было первым пользовательским исключением, которое мы включили через FaultContract (на самом деле, был только 1 тип). если бы я добавил простую веб-ссылку, она бы тоже работала правильно. Кроме того, у WcfClient.exe не было проблем с загрузкой сервисов. Просто VS.NET добавить ссылку на службу не будет работать.

В службе это исключение наследуется от Exception и помечается как сериализуемое. Это все, что ты должен делать, нет?

Во всяком случае, это сбило меня с толку. Если я удаляю FaultContract для этого пользовательского исключения, все работает нормально. Я могу добавить ссылку на сервис, нет проблем. Но есть ли способ, которым я все еще могу иметь свои собственные исключения? Это известная проблема?

Ответы [ 4 ]

8 голосов
/ 08 февраля 2011

Я столкнулся с этим сам сегодня. Решением было использование объекта, не наследующего от Exception в FaultContract. Если вы посмотрите документы MSDN для FaultException и FaultContract , вы увидите, что в официальных примерах используются простые классы (с атрибутами DataContact), а не классы, расширяющие Exception для FaultException.Detail. Я не уверен, почему Exception приводит к сбою Add Service Reference, но я подозреваю, что это связано с сериализацией или получением информации о типе для пользовательских исключений. Я включил примеры до и после реализации, чтобы продемонстрировать рабочий подход.

До (не работал):

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    [FaultContract(typeof(MyException))]
    MyResults MyServiceOperation(string myParameter);
}

[Serializable]
public class MyException : Exception
{
    public string CustomData { get; set; }
}

[ErrorHandlerBehavior(typeof(MyErrorHandler))]
public class MyService : IMyService
{
    public MyResults MyServiceOperation(string myParameter)
    {
        ...
        throw new MyModelException { CustomData = "42" };
        ...
    }
}

public class MyErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error) { return false; }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        try { throw error; }
        catch (MyModelException ex)
        {
            var faultEx = new FaultException<MyException>(new MyException { CustomData = ex.CustomData });
            fault = Message.CreateMessage(version, faultEx.CreateMessageFault(), faultEx.Action);
        }
        catch { /* Supress all others */ }
    }
}

После (работал):

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    [FaultContract(typeof(MyFault))]
    MyResults MyServiceOperation(string myParameter);
}

[DataContract]
public class MyFault
{
    [DataMember]
    public string CustomData { get; set; }
}

[ErrorHandlerBehavior(typeof(MyErrorHandler))]
public class MyService : IMyService
{
    public MyResults MyServiceOperation(string myParameter)
    {
        ...
        throw new MyModelException { CustomData = "42" };
        ...
    }
}

public class MyErrorHandler : IErrorHandler
{
    public bool HandleError(Exception error) { return false; }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        try { throw error; }
        catch (MyModelException ex)
        {
            var faultEx = new FaultException<MyFault>(new MyFault { CustomData = ex.CustomData });
            fault = Message.CreateMessage(version, faultEx.CreateMessageFault(), faultEx.Action);
        }
        catch { /* Supress all others */ }
    }
}

Источник: Макс Стрини за использование своего кода и помощь в поиске решения этой проблемы.

1 голос
/ 01 августа 2012

Я нашел следующую статью о том, как создать контракт отказа, используя возраженные, унаследованные от System.Exception: http://blog.clauskonrad.net/2008/06/wcf-and-custom-exceptions.html

Однако, это не сработало для меня. Я подозреваю, что причина, по которой это не сработало, заключается в том, что я использую привязку BasicHttp, а не привязку .NET-.NET.

0 голосов
/ 25 ноября 2011

У меня возникла та же проблема, и я решил ее, сгенерировав прокси с помощью SVCUTIL.exe.У меня была настраиваемая настройка сбоя в точности так, как рекомендует MSDN, но «добавить ссылку на сервис» не включало контракт на сбой в прокси.Затем я использовал SVCUTIL, и он работал как по волшебству:)

0 голосов
/ 02 сентября 2011

Я тоже затронул эту проблему. В итоге я использовал svcutil.exe для генерации прокси-сервера, который, похоже, не сталкивается с той же проблемой.

...