我有一个ASP.NET网站,其中包含一些WCF服务。我已经连接到Application_Error事件,因此可以记录任何未处理的异常。
我真正想做的是将执行传递回被调用的方法,这样我就可以向客户端返回一些合理的东西,而不是抛出一个FaultException。
我知道我可以在try / catch块中包装每个单独的服务调用,但这意味着在每个方法中加载样板代码。我真正想做的是有一个集中的catch-all方法,比如Application_Error,但是然后允许单个服务调用取回控制并返回对客户端有意义的东西。
这可能吗?
P.S。如果有人认为我这样做的方式不对,那么我的背景是我在C#WCF代码中实现Railway Oriented Programming。我的想法是,如果有异常,我会返回一个包含细节的适当对象,以及其他有用的东西。与WCF服务抛出异常相比,这是一种更加可控的处理情况的方法。
答案 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服务(或其他)的消费者身上,以检查服务调用是否成功,并采取适当的行动。这是一种功能样式,并且导致更强大的编码,因为您非常不得忽略异常,这与非函数式编程不同,在非假设没有出错的情况下,您可能只是抓住服务的结果。在出现问题之前,这很好!
希望有所帮助。