在您指定的问题中:
我想添加一些 FaultContracts,然后在我的业务逻辑中使用它们来抛出正确的异常。
正如您正确识别的那样 - 这引入了服务的公共 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"
});
}
}
}
}
顺便说一句,值得仔细考虑您在客户端中公开的故障合约以及当服务器端出现问题时客户端需要哪些信息。在您的服务上公开过多有关异常的信息可能会带来安全风险。