Бросать универсальный FaultException
У меня есть служба WCF, которая, если что-то идет не так, генерирует общее исключение FaultException. Я не знаю почему, иногда клиенты будут ловить не универсальное исключение FaultException вместо универсального исключения.
Кто-нибудь знает, в чем проблема?
7 ответов
Ваша служба должна обрабатывать все исключения и заключать их в FaultException
[DataContract]
public class CustomFault
{
public string Message { get; set; }
}
Затем вы указываете своему сервисному контракту, что его методы потенциально могут вызвать FaultException
[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
и добавить 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". Я решил опубликовать это исправление здесь как ответ, если кто-то еще столкнется с этим.