【问题标题】:Good practice for wcf service operation resultwcf 服务运行结果的良好实践
【发布时间】:2014-05-08 08:51:06
【问题描述】:

Wcf 服务的最佳实践是什么,以防我们需要发送失败/成功结果?

例如: 我们有 Wcf 服务,在服务后面我们有一些 BussinesLogic。 我们的服务有一份运营合同:

[OperationContract] /*SomeResult*/ SendImages(Bitmap[] images);

可能的场景:

  1. 操作完成,一切顺利。
  2. 位图参数不正确(位图大小或数量错误)。
  3. BussinesLogic 处于“坏”状态。逻辑处于错误状态,我们 不知道什么时候可以重新上班。

我应该自定义fault吗?在哪种情况下?我应该使用通用fault 吗?我应该制作enum OperationResult 吗?或者在成功的情况下,任何结果都像是矫枉过正? 可能的场景数量将保持不变。

【问题讨论】:

  • 任你选择 - 最重要的是保持一致。我看到很多次外部系统有时会返回错误代码,有时会出现故障。也许一开始他们甚至能够理解为什么他们会选择一种或另一种,一段时间后没有人能够证明这一决定的合理性,而我们作为客户总是必须双向服务。

标签: c# .net wcf


【解决方案1】:

我喜欢使用这种方法:

[DataContract]
public class OperationResult
{
  public OperationResult()
  {
    Errors = new List<OperationError>();
    Success = true;
  }

  [DataMember]
  public bool Success { get; set; }

  [DataMember]
  public IList<OperationError> Errors { get; set; }
}

[DataContract(Name = "OperationResultOf{0}")]
public class OperationResult<T> : OperationResult
{
  [DataMember]
  public T Result { get; set; }
}

[DataContract]
public class OperationError
{
  [DataMember]
  public string ErrorCode { get; set; }

  [DataMember]
  public string ErrorMessage { get; set; }
}

我还有一些扩展:

  public static OperationResult WithError(this OperationResult operationResult, string errorCode,
                                          string error = null)
  {
    return operationResult.AddErrorImpl(errorCode, error);
  }

  public static OperationResult<T> WithError<T>(this OperationResult<T> operationResult, string errorCode,
                                                string error = null)
  {
    return (OperationResult<T>) operationResult.AddErrorImpl(errorCode, error);
  }

  private static OperationResult AddErrorImpl(this OperationResult operationResult, string errorCode,
                                              string error = null)
  {
    var operationError = new OperationError {Error = error ?? string.Empty, ErrorCode = errorCode};

    operationResult.Errors.Add(operationError);
    operationResult.Success = false;

    return operationResult;
  }

  public static OperationResult<T> WithResult<T>(this OperationResult<T> operationResult, T result)
  {
    operationResult.Result = result;
    return operationResult;
  }

这些扩展可以通过一行代码返回错误:

return retValue.WithError(ErrorCodes.RequestError);

在我的 wcf 服务中,我从不抛出异常。

对不起,代码墙


调用者的代码是这样的。但这一切都取决于您的要求

OperationResult res = _service.Register(username, password);

if(!res.Success)
{
    if(res.Errors.Any(x => ErrorCodes.UsernameTaken)
    {
       // show error for taken username
    }
    ...
}

【讨论】:

  • 您的服务的调用者是否真的处理错误列表?他们如何处理列表?
  • 我想你的意思是res.Errors.Any(x=&gt;x.ErrorCode == "UsernameTaken") 什么的。这看起来像一团糟。
  • 我会赞成这样一个全面的答案,但我认为这是错误的答案。 “回到过去”,我们过去必须检查方法和服务调用的返回值。忘记检查错误,以及大量专门用于检查错误的代码是创建异常(和故障)的原因。
  • @JohnSaunders,wcf 中的异常很昂贵。此外,我认为没有理由抛出异常,例如当用户名被使用时。此外,我如何让用户知道请求包含多个错误?例如,用户名被占用,密码太短
  • 不要将其视为异常。如果您抛出 FaultException&lt;T&gt;,那么您将向客户端返回一个 SOAP 错误。 T 可以是任何数据合约类型,允许您将详细信息返回给客户端。不同之处在于客户端不需要在每次调用后检查错误状态,实际上也不需要逐个调用处理错误。
猜你喜欢
  • 2012-09-20
  • 2012-01-10
  • 2020-08-17
  • 1970-01-01
  • 2016-06-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-20
相关资源
最近更新 更多