WCF: предоставить универсальное исключение FaultException в IErrorHandler

Немного контекста: у нас есть собственный XSD и мы генерируем код WSDL и C # с помощью WSCF.blue. Клиентская сторона используетChannelFactory<T> и разделяет интерфейс, который включает все атрибуты, добавленные WSCF.blue, чтобы соответствовать тому, что находится в XSD.

Я пытаюсь реализоватьIErrorHandler.ProvideFault где он предоставляет общийFaultException<T>, но на стороне клиента я получаю не универсальныйFaultContract, Это то, что мойProvideFault Метод выглядит так:

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
    if (!(error is FaultException))
    {
        FaultException faultException = FaultExceptionFactory.CreateFaultException(error);
        MessageFault messageFault = faultException.CreateMessageFault();
        fault = Message.CreateMessage(version, messageFault, faultException.Action);
    }
}

В каждом методе обслуживания, если я делаю попытку / поймать сthrow FaultExceptionFactory.CreateFaultException(ex) это работает, как и ожидалось, поэтому я думаю,[FaultContract], фабрика, крепления и т. д. все правильно. На всякий случай вот так работает фабрика:

BusinessRuleFaultExceptionType businessRuleFaultException = new BusinessRuleFaultExceptionType();
BusinessRuleFaultException.Code = exception.Code.ToString();
BusinessRuleFaultException.Reason = exception.Message;
return new FaultException<BusinessRuleFaultExceptionType>(
    businessRuleFaultException,
    exception.Message,
    new FaultCode(exception.Code.ToString())
);

Я думаю, что проблема в том, как сообщение создается вIErrorHandlerвозможно вCreateMessageFault(), Я прочитал, что действие должно бытьfaultException.Action вместоnull, но по фактуfaultException.Action являетсяnull, Может быть, это вызывает проблему. Я могу установить действие на заводе, но каким должно быть это действие, и почему оно не появится при ручном броске?

Любые другие идеи, которые я мог бы упустить?

Редактировать: Я проверил WSDL и нашел конкретную операцию, которую я вызывал, и ее действие:

<wsdl:operation name="MyMethod">
<wsdl:fault wsaw:Action="http://myNamespace/MyMethodBusinessRuleFaultExceptionTypeFault" name="BusinessRuleFaultExceptionTypeFault" message="tns:..."/>

Я старался кодировать действие:Message.CreateMessage(..., "http://myNamespace/MyMethodBusinessRuleFaultExceptionTypeFault") и установив его на.Action на фабрике, но это все еще не сработало.

Изменить 2: Метод throw / catch генерирует следующий XML, который позволяет перехватить общее исключение на клиенте:

<s:Fault>
    <faultcode xmlns="">s:-100</faultcode>
    <faultstring xml:lang="en-US" xmlns="">xxx</faultstring>
    <detail xmlns="">
        <BusinessRuleFaultExceptionType xmlns="http://myNamespace/Services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <Code xmlns="http://myNamespace/Entitites">-100</Code>
            <Reason xmlns="http://myNamespace/Entitites">xxx</Reason>
        </BusinessRuleFaultExceptionType>
    </detail>
</s:Fault>

IHttpErrorHandler генерирует следующее, что идет к неуниверсальномуFaultException:

<s:Fault>
    <faultcode xmlns="">s:-100</faultcode>
    <faultstring xml:lang="en-US" xmlns="">xxx</faultstring>
    <detail xmlns="">
        <BusinessRuleFaultExceptionType xmlns="http://schemas.datacontract.org/2004/07/My.Dot.Net.Namespace" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <codeField>-100</codeField>
            <reasonField>xxx</reasonField>
        </BusinessRuleFaultExceptionType>
    </detail>
</s:Fault>

Изменить 3: Если я добавлю[DataContract] а также[DataMember] кBusinessRuleFaultExceptionTypeтогда я получаю почти правильный XML:

<s:Fault>
    <faultcode xmlns="">s:-100</faultcode>
    <faultstring xml:lang="en-US" xmlns="">xxx</faultstring>
    <detail xmlns="">
        <BusinessRuleFaultExceptionType xmlns="http://myNamespace/Services" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <Code>-100</Code>
            <Reason>xxx</Reason>
        </BusinessRuleFaultExceptionType>
    </detail>
</s:Fault>

В нем отсутствует пространство имен для кода и причины. По крайней мере, я думаю, что это сужает это. Регулярная сериализация использует[XmlType] а также[XmlElement] в то время какIErrorHandler использует[DataContract] а также[DataMember], к несчастью[DataMember] не позволяет вам установить пространство имен, поэтому я думаю, что теперь вопрос заключается в том, как использовать XMLSerializer вIErrorHandler, Это описывает мою проблему, но исправление не будет работать по причине, указанной выше:http://twenty6-jc.blogspot.com/2011/05/ierrorhandlerprovidefault-serialization.html

Изменить 4: Я частично нашел проблему. Мы используемXmlSerializer, но с тех порIErrorHandler находится за пределами действия операции, возвращается к значению по умолчаниюDataContractSerializer, Решение состоит в том, чтобы либо изменить свой сервис для использованияDataContractSerializer везде или вручную выбратьXmlSerializer при создании неисправностей. Эти две статьи предоставили то, что мне было нужно:

http://twenty6-jc.blogspot.com/2011/05/ierrorhandlerprovidefault-serialization.html http://zamd.net/2008/08/15/serializing-faults-using-xmlserializer/

Это получает меняочень близко. Он такой же, как и рабочий XML, за исключением того, что отсутствует пространство имен типа исключения:

<s:Fault>
    <faultcode xmlns="">s:-100</faultcode>
    <faultstring xml:lang="en-US" xmlns="">xxx</faultstring>
    <detail xmlns="">
        <BusinessRuleFaultExceptionType xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
            <Code xmlns="http://myNamespace/Entitites">-100</Code>
            <Reason xmlns="http://myNamespace/Entitites">xxx</Reason>
        </BusinessRuleFaultExceptionType>
    </detail>
</s:Fault>

Я предполагаю, что это не добавляетxmlns="http://myNamespace/Services" потому что у него нет контекста запроса. Это пространство имен определено в интерфейсе, но не в контракте данных. Я действительно буду вынужден оставаться в контексте запроса (надеюсь,IOperationInvoker работает) вместо использованияIHttpHandler?

Ответы на вопрос(2)

Ваш ответ на вопрос