7

いくつかのコンテキスト: カスタム XSD があり、WSCF.blue を使用して WSDL および C# コードを生成します。クライアント側はChannelFactory<T>、XSD の内容と一致するように WSCF.blue によって追加されたすべての属性を含むインターフェースを使用および共有します。

IErrorHandler.ProvideFaultgeneric を提供する場所を実装しようとしています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);
    }
}

各サービスメソッドで、try/catch を実行すると期待どおりに動作するので、 、ファクトリ、バインディングなどはすべて正しい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:..."/>

action: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]と、ほぼ正しい XML が得られます。[DataMember]BusinessRuleFaultExceptionType

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

Code と Reason の名前空間がありません。少なくともこれで絞れると思います。通常のシリアル化では and を使用し、 では[XmlType]and[XmlElement]IErrorHandler使用[DataContract]してい[DataMember]ます。残念ながら[DataMember]、名前空間を設定することはできません。そのため、問題は .xml で XMLSerializer を使用する方法だと思いますIErrorHandler。これは私の問題を説明していますが、上記の理由で修正は機能しません: http://twenty6-jc.blogspot.com/2011/05/ierrorhandlerprovidefault-serialization.html

編集 4: 問題を部分的に見つけました。を使用してXmlSerializerIErrorHandlerますが、運用範囲外のため、デフォルトの に戻しますDataContractSerializer。解決策は、サービスをどこでも使用するように変更するか、障害を作成するときにDataContractSerializer手動で選択することです。XmlSerializerこれらの 2 つの記事は、私が必要としていたものを提供してくれました。

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でしょうか(うまくいけばうまくいきます)。

4

2 に答える 2

2

IErrorHandlerの代わりに IOperationInvokerを使用することをお勧めします。IOperationInvoker を使用:

  • 単一の try/catch ステートメントを使用できます。すべての操作が try/catch でラップされているかのように機能します。
  • 結果の Message を手動で作成する必要はありません。

あなたの場合の実装は次のようになります。

public object Invoke(object instance, object[] inputs, out object[] outputs)
{
    try
    {
        return _childInvoker.Invoke(instance, inputs, out outputs);
    }
    catch (Exception error)
    {
        throw FaultExceptionFactory.CreateFaultException(error);
    }
}
于 2014-04-18T20:17:30.297 に答える