在未处理的异常之后,我可以将执行返回到失败的方法吗?

时间:2016-11-07 21:02:04

标签: c# wcf exception-handling

我有一个ASP.NET网站,其中包含一些WCF服务。我已经连接到Application_Error事件,因此可以记录任何未处理的异常。

我真正想做的是将执行传递回被调用的方法,这样我就可以向客户端返回一些合理的东西,而不是抛出一个FaultException。

我知道我可以在try / catch块中包装每个单独的服务调用,但这意味着在每个方法中加载样板代码。我真正想做的是有一个集中的catch-all方法,比如Application_Error,但是然后允许单个服务调用取回控制并返回对客户端有意义的东西。

这可能吗?

P.S。如果有人认为我这样做的方式不对,那么我的背景是我在C#WCF代码中实现Railway Oriented Programming。我的想法是,如果有异常,我会返回一个包含细节的适当对象,以及其他有用的东西。与WCF服务抛出异常相比,这是一种更加可控的处理情况的方法。

1 个答案:

答案 0 :(得分:2)

如果您想做类似于ROP风格的事情,那么您可以执行以下操作(来自Jeff Bridgman建议的可用名称)。

首先创建抽象基类,如下所示......

public abstract class Failable<T> {
}
public abstract class Failable {
}

接下来,从这些类创建具体类来表示成功和失败。我已经添加了每个的通用和非通用版本,因此您可以处理返回值以及无效值的服务调用...

public class Success<T> : Failable<T> {
  public Success(T value) {
    Value = value;
  }

  public T Value { get; set; }
}

public class Success : Failable {
}

public class Failure<T> : Failable<T> {
  public Failure(Exception value) {
    Value = value;
  }

  public Exception Value { get; set; }
}

public class Failure : Failable {
  public Failure(Exception value) {
    Value = value;
  }

  public Exception Value { get; set; }
}

然后一些辅助方法会给你你想要的东西......

public Failable<T> DoFailableAction<T>(Func<T> f) {
  Failable<T> result;
  try {
    T fResult = f();
    result = new Success<T>(fResult);
  }
  catch (Exception ex) {
    result = new Failure<T>(ex);
    // Do logging, etc here...
  }
  return result;
}

public Failable DoFailableAction(Action f) {
  Failable result;
  try {
    f();
    result = new Success();
  }
  catch (Exception ex) {
    result = new Failure(ex);
    // Do logging, etc here...
  }
  return result;
}

要使用这些,请假设您拥有WCF服务。您在辅助方法中包装服务调用...

Failable<Person> p = failableHelpers.DoFailableAction(() => service.GetPerson(1));

...其中failableHelpers是包含上面显示的两个辅助方法的类的实例。

然后,您可以检查呼叫是成功还是失败,并采取适当的行动......

if (p is Success<Person>) {
  Person p = ((Success<Person>)p).Value;
  Debug.WriteLine("Value is Success, and the person is " + p.FirstName + " " + p.Surname);
} else {
  Exception ex = ((Failure<Person>)p).Value;
  Debug.WriteLine("Value is Failure, and the message is " + ex.Message);
}

如果您的服务方法无效,您只需使用非通用变体...

Person jim = new Person(1, "Jim", "Spriggs");
Failable saveResult = failableHelpers.DoFailableAction(() => service.Update(jim));

你还没有达到你想要的效果,因为你在每个服务方法中仍然有一些样板代码,但它很少。它不是方法的一个属性,但是这种方法实现起来要简单得多,适用于任何类型的级别,无论是存储库,业务逻辑,WCF服务,客户端等。这种方法仅适用于WCF。

这种方法的好处是它将责任放在WCF服务(或其他)的消费者身上,以检查服务调用是否成功,并采取适当的行动。这是一种功能样式,并且导致更强大的编码,因为您非常不得忽略异常,这与非函数式编程不同,在非假设没有出错的情况下,您可能只是抓住服务的结果。在出现问题之前,这很好!

希望有所帮助。