2

私のWCFサービスには、いくつかのカスタム障害タイプがあります。BaseFaultと呼ばれる抽象型と、TypeOneFaultおよびTypeTwoFaultと呼ばれるその2つの実装

私はこのようにサービス側で例外をスローしています

public string ThisMethodHasFault(string eType)
{
    if (eType.Contains("One"))
    {
        TypeOneFault one = new TypeOneFault("TypeOneFault thrown");
        throw new FaultException<TypeOneFault>(one, new FaultReason(new FaultReasonText("Fault reason here")));
    }
    else
    {
        TypeTwoFault two = new TypeTwoFault("TypeTwoFault thrown");
        throw new FaultException<TypeTwoFault>(two, new FaultReason(new FaultReasonText("Fault reason here")));
    }

    return "";
}

私のサービスインターフェースはこんな感じです

[OperationContract]
[FaultContract(typeof(TypeOneFault ))]
[FaultContract(typeof(TypeTwoFault ))]
string ThisMethodHasFault(string eType);

クライアント側では、このようにキャッチするテストWinFormアプリケーションがあります

   MyServiceClient client = new MyServiceClient();

   try
    {
        client.ThisMethodHasFault(""); //get value from user

    }
    catch (FaultException<TypeOneFault>  ox)
    {
         TypeOneFault oneEx = ox.Detail;
         oneEx.{property} ...

    }   
    catch (FaultException<TypeTwoFault>  tx)
    {
         TypeTwoFault twoEx = tx.Detail;
         twoEx.{property} ...
    }    

質問:

代わりにこれを行うことでキャッチブロックの数を減らすことができないようです

    catch (FaultException<BaseFault> fex)
    {
         BaseFault Ex = fex.Detail;
         twoEx.{property} ...
    }    

サーバーにスローする例外をキャプチャできるブロックが1つあれば、抽象化によって適切なクラスの詳細を取得できればよかったと思います。上記を実行すると、エラーが発生します。An unhandled exception of type 'System.ServiceModel.FaultExceptionmscorlib.dll`で1'が発生しました

これを機能させるために変更する必要があるものはありますか、それとも複数のキャッチブロックのみに満足する必要がありますか?

4

2 に答える 2

4

FaultException<T>から継承するFaultExceptionため、代わりに基本タイプをキャッチできます。

catch(FaultException ex) {
    if(ex is FaultException<TypeOneFault>) {
        var detail = ((FaultException<TypeOneFault>) ex).Detail;
        // process it
    } else if(ex is FaultException<TypeTwoFault>) {
        var detail = ((FaultException<TypeTwoFault>) ex).Detail;
        // process it
    } else {
        // unexpected error
        throw;
    }
}

2つの別々のcatchブロックとは異なり、これはリファクタリングできます。

    catch(FaultException ex) {
        if(!ProcessFault(ex)) {
            throw;
        }

bool ProcessFault(FaultException ex) {
    if(ex is FaultException<TypeOneFault>) {
        var detail = ((FaultException<TypeOneFault>) ex).Detail;
        // process it
        return true;
    } else if(ex is FaultException<TypeTwoFault>) {
        var detail = ((FaultException<TypeTwoFault>) ex).Detail;
        // process it
        return true;
    } else {
        // unexpected error
        return false;
    }
}

2つの障害クラスが関連していない場合、それは可能な限りです。ただし、それらが共通ベースから継承している場合は、さらにリファクタリングできます。

bool ProcessFault(FaultException ex) {
    if(ex is FaultException<TypeOneFault>) {
        ProcessFault(((FaultException<TypeOneFault>) ex).Detail);
        return true;
    } else if(ex is FaultException<TypeTwoFault>) {
        ProcessFault(((FaultException<TypeTwoFault>) ex).Detail);
        return true;
    } else {
        // unexpected error
        return false;
    }
}

void ProcessFault(BaseFault detail) {
    // process it
}
于 2012-10-16T12:35:49.987 に答える
2

便宜上FastMemberを使用して、このようなものはどうですか。ただし、動的ブロックといくつかのtry/catchブロックを使用して同じ効果を得ることができます。

try
{
    client.ThisMethodHasFault("");
}
catch (FaultException e)
{
    var accessor = TypeAccessor.Create(e.GetType());
    var detail = accessor.GetMembers().Any(x => x.Name == "Detail")
                     ? accessor[e, "Detail"] as BaseFault
                     : null;

    if (detail != null)
    {
        // Do processing here
    }
    else
    {
        throw;
    }
}
于 2014-02-24T02:20:04.073 に答える