あなたが指定する質問で:
いくつかの FaultContract を追加し、それらをビジネス ロジックで使用して適切な例外をスローしたいと考えています。
ご指摘のとおり、これにより、サービスのパブリック API (サービス、データ、およびフォールト コントラクト) とビジネス ロジックが結合されます。理想的には、ビジネス ロジックは、サービスによって呼び出されているという事実にとらわれないようにする必要があります。そのため、コントラクト アセンブリへの参照は厄介です。
コントラクト アセンブリは、クライアントがサービスに関して公開している情報をレイアウトする必要があります。
namespace Contracts
{
[ServiceContract]
interface IMyService
{
[OperationContract]
[FaultContract(typeof(MyFaultContract))]
[FaultContract(typeof(AnotherFaultContract))]
void MyOperation();
}
[DataContract]
public class MyFaultContract
{
[DataMember]
public string Problem { get; set; }
}
[DataContract]
public class AnotherFaultContract
{
[DataMember]
public string Description { get; set; }
}
}
ソフトウェア開発における多くの問題と同様に、問題は間接的なレイヤーで対処できます。質問で指定したことにもかかわらず、ビジネスロジックをコントラクトアセンブリに結合したくありません。そうしないことの利点は明らかです。これにより、パブリック コントラクトと「内部」ビジネス ロジックが独立して進化できるようになります。
以下は、サービス実装を使用してコントラクトをビジネス ロジックに結合する例を示しています。ビジネス レイヤーの例外は、クライアントに返される障害コントラクトにマップされます。
namespace Service
{
class MyService: IMyService
{
public void MyOperation()
{
try
{
var businessLogic = new BusinessLogic();
businessLogic.DoOperation();
}
catch (KeyNotFoundException)
{
throw new FaultException<MyFaultContract>(new MyFaultContract
{
Problem = "A key issue occurred in the service"
});
}
catch (Exception)
{
throw new FaultException<AnotherFaultContract>(new AnotherFaultContract
{
Description = "Something BAD happened in the service"
});
}
}
}
}
余談ですが、クライアントで公開する障害コントラクトと、サーバー側で問題が発生した場合にクライアントが必要とする情報について慎重に検討する価値があります。サービスの例外に関する情報を公開しすぎると、セキュリティ リスクになる可能性があります。