有没有一种方法来处理由WCF服务的构造函数抛出的异常,当构造函数接受的依赖, 这是依赖关系的实例由IoC容器(AutoFac在这种情况下)引起的异常 ?
考虑采用以下构造一个WCF服务:
public InformationService(IInformationRetriever informationRetriever)
{
_informationRetriever = informationRetriever;
}
//... the service later makes use of the injected InformationRetriever
该服务使用AutoFac WcfIntegration和AutofacWebServiceHostFactory
(这恰好是一个RESTful服务)。
依赖已在服务,即在的global.asax.cs:
builder.RegisterType<InformationRetriever>()
.As<IInformationRetriever>()
现在InformationRetriever
实现执行在其构造一些检查,以确保一切都在地方,它能够完成其工作。 若在该阶段发现问题,它抛出一个异常。
不过,我不希望服务接受AutoFac异常的调用者:
An exception was thrown while invoking the constructor ... on type InformationRetriever
有效地我想测试:
鉴于 InformationService运行
当我打电话GetSomeInformation()方法
而 InformationRetriever不能被实例化
然后我想返回一个友好的错误消息
并记录实际的异常
这是我的设计有问题,或者是有一个已知的模式,以克服或避免这个问题?
我猎杀四周,找不到这种类型的问题的任何信息。
我不是构造函数抛出异常比坏的争论等原因的忠实粉丝。 我想大概我的模型类型以不同的方式。 但这里的一些想法。 起初,我想过做这样的事情:
builder
.Register(c => {
try
{
return new InformationRetriever();
}
catch (Exception)
{
return new FailoverInformationRetreiver();
}})
.As<IInformationRetriever>();
...其中FailoverInformationRetreiver
抛出的成员访问异常。 另一个想法可能是要做到:
public InformationService(Lazy<IInformationRetriever> informationRetriever)
{
_informationRetriever = informationRetriever;
}
和try/catch
围绕用法内InformationService
。 另一种选择,你可以与如果可用性去InformationRetriever
在应用程序启动被称为:
// inside your container builder:
if (InformationRetreiver.IsAvailable())
builder.RegisterType<InformationRetriever>()
.As<IInformationRetriever>()
// inside InformationService, make the dependency optional
public InformationService(IInformationRetriever informationRetriever = null)
{
_informationRetriever = informationRetriever;
}
做任何的这些想法帮助吗?
写在DI风格对象通常通过两个分离相:组合物和执行。 合成阶段是你线了依赖和不喜欢的东西扔参数异常。 通常你想保持这个阶段免费的有意义的行为,因为这可以让你在你的系统的配置表面误差。 第二阶段的执行,是您使用的第一阶段(依赖)做你的工作的输出。
分离这两个阶段去掉了很多不确定性和复杂性。 举个例子,你不要试图修剪草坪,而毒气你剪草机; 这导致两个活动变得更加复杂(和危险!)
在这种情况下, InformationRetriever
通过在它的构造进行有意义的工作混为一谈组合物和执行阶段。 这种混合导致正是你要设法避免的问题:被包裹在一个组成异常的有意义的业务异常。 目前还不清楚如何处理异常,因为顶层调用是Autofac,而不是这实际上是要求组件InformationRetriever
做的工作。
我建议努力做时调用验证InformationRetriever
; 这消除了Autofac异常,并允许InformationService
处理的特殊情况没有任何弄虚作假。
这种方法的一个潜在缺点是,验证会发生在每次调用InformationRetriever
在构造函数,而不是一次。 你有两个选择:1)让它发生每一次,绝对确保工作有效执行,或2)跟踪的你是否已经做了检查,只有做到这一点,如果你之前还没有。
如果您选择#2,你可以保持InformationRetriever
清洁用装饰来包装它在同一界面的验证版本:
public class ValidatingInformationRetriever : IInformationRetriever
{
private readonly IInformationRetriever _baseRetriever;
private bool _validated;
public ValidatingInformationRetriever(IInformationRetriever baseRetriever)
{
_baseRetriever = baseRetriever;
}
public void Foo()
{
if(!_validated)
{
Validate();
_validated = true;
}
_baseRetriever.Foo();
}
private void Validate()
{
// ...
}
}
您可以使用它注册Autofac的装饰支持 ,如下所示:
builder
.RegisterType<InformationRetriever>()
.Named<IInformationRetriever>("base");
builder.RegisterDecorator<IInformationRetriever>(
(c, inner) => new ValidatingInformationRetriever(inner),
fromKey: "base");