我有一个 ASP.NET 网站,其中包含一些 WCF 服务。我已连接到 Application_Error 事件,因此可以记录任何未处理的异常。
我真正想做的是将执行传递回被调用的方法,这样我就可以向客户端返回一些有意义的内容,而不是抛出FaultException。
我知道我可以将每个单独的服务调用包装在 try/catch block 中,但这意味着每个方法中都有大量样板代码。我真正想做的是拥有一个中央包罗万象的方法,例如 Application_Error,但随后允许单个服务调用收回控制权并向客户端返回一些有意义的内容。
这可能吗?
附注如果有人认为我这样做的方式错误,其背景是我正在实现 Railway Oriented Programming在我的 C# WCF 代码中。这个想法是,如果出现异常,我会返回一个包含详细信息以及其他有用内容的适当对象。与让 WCF 服务抛出异常相比,这是一种更受控制的处理情况的方法。
最佳答案
如果你想做一些类似于 ROP 风格的事情,那么你可以执行以下操作(Jeff Bridgman 建议的 Failable 名称)。
首先创建抽象基类如下...
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 服务(或其他服务)的使用者有责任检查服务调用是否成功,并采取适当的行动。这是一种函数式风格,并且会导致更健壮的编码,因为您几乎被迫不忽略异常,这与非函数式编程不同,在非函数式编程中,您可能只是在假设没有出错的情况下获取服务的结果。一切都很好,直到出现问题为止!
希望有帮助。
关于c# - 在发生未处理的异常后,我可以将执行返回到失败的方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40474543/