Бросать универсальный FaultException

У меня есть служба WCF, которая, если что-то идет не так, генерирует общее исключение FaultException. Я не знаю почему, иногда клиенты будут ловить не универсальное исключение FaultException вместо универсального исключения.

Кто-нибудь знает, в чем проблема?

7 ответов

Ваша служба должна обрабатывать все исключения и заключать их в FaultException, где T - это контракт данных, который вы написали. Поэтому первым шагом является определение пользовательского контракта на данные, который будет содержать информацию об исключении:

[DataContract]
public class CustomFault
{
    public string Message { get; set; }
}

Затем вы указываете своему сервисному контракту, что его методы потенциально могут вызвать FaultException. Это позволяет службе предоставлять класс CustomFault в wsdl, чтобы клиенты могли генерировать прокси-класс:

[ServiceContract]
public interface IMyServiceContract
{
    [FaultContract(typeof(CustomFault))]
    void MyMethod(string someArgument);
}

Следующим шагом является реализация этого интерфейса:

public class MyService : IMyServiceContract
{
    public void MyMethod(string someArgument)
    {
        // Do something here that could throw exceptions but don't catch yet
    }
}

Для обработки исключений вы можете реализовать IErrorHandler, который будет использоваться всякий раз, когда один из ваших методов обслуживания генерирует исключение. Назначение этого обработчика ошибок - заключить исключение в FaultException:

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

    public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
    {
        var customFault = new CustomFault()
        {
            Message = error.Message,
        };
        var fe = new FaultException<CustomFault>(customFault);
        MessageFault fault = fe.CreateMessageFault();
        string ns = "http://somenamespace/whatever";
        msg = Message.CreateMessage(version, fault, ns);
    }
}

Как только вы зарегистрируете свой обработчик ошибок, на стороне клиента вы всегда получите FaultException.

Если ваш клиент не имеет доступа к самому типу исключения ( на FaultException), то генерируется неуниверсальная версия FaultException. Я потратил часы, пытаясь понять это, и в конце концов понял это, когда обнаружил это на форумах msdn. Было бы замечательно, если бы было какое-то указание на то, что исключение было изменено до его выброса из службы, но это не так.

Неуниверсальный FaultException генерируется, когда служба генерирует другое исключение, которое не было перехвачено. Вам нужно будет выяснить, что является исключением, и исправить его, если это ошибка, или решить, что это то, что вы хотите показать своим клиентам, а затем обернуть его в общий FaultException и добавить FaultContract соответственно.

Другая возможность состоит в том, что ваш TDetail не сериализуется должным образом. Это может быть в том случае, если, например, TDetail происходит от Exception, и у вас есть внутреннее исключение, которое не сериализуемо.

Я видел ту же проблему, и ссылка, которую разместил Дрю, дала мне ответ.

Для меня было решено, что мой Сервисный интерфейс имел другое пространство имен, чем моя ошибка сервиса.

т. е. договор на обслуживание имел:

[ServiceContract(Namespace = "http://dummydomain.com/service/searchservice")]
    public interface ISearchService
    ....

и сервисная неисправность имела:

[DataContract(Namespace = "http://dummydomain.com/service/searchservicefault")]
public class MySearchServiceFault
...

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

Но когда я изменил пространство имен на одно и то же, это, кажется, заставило код работать все время в моем тестировании.

Это произойдет, если вы не объявили свой тип детализации ошибки с помощью FaultContractAttribute.

Вот как должен выглядеть ваш контракт на обслуживание:

[ServiceContract]
public interface IMyServiceContract
{
    //...
    [OperationContract]
    [FaultContract(typeof(MyFaultDetail))]
    [FaultContract(typeof(OtherFaultDetail))] 
    GetDetailsResp GetDetails(GetDetailsReq req);
    //...
}

У меня была похожая проблема, и это произошло, когда я обновил некоторые пакеты NuGet, использовал общий стандартный класс.NET и т. Д. (Я не знаю точно, что вызвало это, много изменений произошло за два месяца, но они были среди изменения). Это оказалось проблемой, когда Action было установлено в строку "FAULT" ранее, и она работала нормально на стороне клиента с атрибутами FaultContract по умолчанию. Но после этих изменений (конец 2018 года) строка "НЕИСПРАВНОСТЬ" как действие означала, что она больше не соответствует классам неисправностей, и вместо этого я получил общее исключение FaultException. Изменения, которые исправили все это (без изменений на стороне клиента), заключались в том, чтобы установить для действия значение "null" при возникновении FaultException вместо "FAULT". Я решил опубликовать это исправление здесь как ответ, если кто-то еще столкнется с этим.

Другие вопросы по тегам