.net – 现实世界中的WCF故障契约

假设我们有一个服务方法执行一些安全检查,从数据库和第三方Web服务检索数据,构造MyDataDTO,将审核条目写回数据库.
而且我们想要结构良好,精细的错误代码,不是吗?我们是好男孩,遵循标准的WCF错误处理指南:

[FaultContract(typeof(AccessDenied))]
[FaultContract(typeof(KeyNotFound))]
[FaultContract(typeof(WsFault))]
[FaultContract(typeof(DbFault))]
MyDataDTO GetData(string key);

现在我们添加一种更新数据的新方法.该方法在内部(或其主要部分)调用GetData(),执行验证添加更新数据.所以它必须有GetData()重复的所有错误加上自己的错误:

[FaultContract(typeof(InvalidState))]
[FaultContract(typeof(DataNotValid))]
[FaultContract(typeof(AccessDenied))]
[FaultContract(typeof(KeyNotFound))]
[FaultContract(typeof(WsFault))]
[FaultContract(typeof(DbFault))]
void UpdateData(MyDataDTO data);

到现在为止还挺好.这使我们甚至可以生成我们可以为我们服务的消费者提供的文档,以便他们知道他们期望的错误代码.

现在想象我们有10个服务,有10个方法,如上所述(甚至更复杂).并且定义所有这些故障契约变得噩梦,因为这是非常容易出错的过程:

>无法为整个服务定义一般错误(如DbFault)
>您不能保证真正返回操作合同中定义的故障(复制粘贴问题)
>您不能保证您没有错过任何错误来增加操作合同

让我们不要在这里考虑界面版本控制:)

所以,如果您在生产中支持WCF服务,则可以获得图片.我们应该放弃故障合同,并使用好的旧C风格(像使用带有ErrorCode属性的DTBase类)?减少错误粒度?如何确保文档正确/最新?我对一些最佳做法感兴趣

您原始方法的一个问题是您正在尝试复制可能发生的大量系统错误/异常.由于系统的复杂性随着每个新功能的增加而增加,所以您必须考虑的可能问题的数量呈指数级增长(或更大)

我会建议以下方法:由于您正在创建一个“系统”的服务和访问调用,只能定义与该系统相关的FaultContracts.客户只对以下问题感兴趣:

这是我想要的数据还是我问的方式的问题?
>如果不是,这是我的问题,还是与IT相关的问题(系统崩溃,网络错误,数据库问题,无论如何)?

通过一点返工,您可以减少您提供的故障合同数量.例如(这是我头顶的):

//Base class to define general problems
[DataContract]
public class SysFault
{
  //MyDataDTO-specific general error.
  [DataMember]
  public string SysMsg {get;set;}

  //boolean for "this is a problem with me or the hosting system?"
  [DataMember]
  public bool IsSystemic {get;set;}
}

//Subclass to expose synchronization issues--if that's one you want to define
[DataContract]
public class SyncFault : SysFault
{
  [DataMember]
  public string SyncMsg { get;set; }
}

//Subclass to expose validation issues
[DataContract]
public class ValFault : SysFault
{
  [DataMember]
  public string ValMsg { get;set; }
}

现在,您可以使用故障类型分离出您的服务正在发生的情况.
例如:

[ServiceContract]
public interface IRecordSys
{
    [OperationContract]
    [FaultContract(typeof(SysFault))]  //Raised for underlying problem
    [FaultContract(typeof(ValFault))]  //Raised if there is an issue with the key value
    MyDataDTO getData(string key);

    [OperationContract]
    [FaultContract(typeof(SysFault))]  //Raised for underlying problem elsewhere
    //Raised for some issue, such as unable to get two subsystems to update properly
    //with the given data
    [FaultContract(typeof(SyncFault))]
    void update(MyDataDTO data); 
}

您的具体实施方式将有所不同,但其想法是传递关于您的系统的消息,而不是每一个可能出现的系统性问题.

翻译自:https://stackoverflow.com/questions/8758773/wcf-fault-contracts-in-real-world

转载注明原文:.net – 现实世界中的WCF故障契约