如何使用Autofac WcfIntegration时处理构造异常(How to handle co

2019-09-19 11:30发布

有没有一种方法来处理由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不能被实例化

然后我想返回一个友好的错误消息

记录实际的异常

这是我的设计有问题,或者是有一个已知的模式,以克服或避免这个问题?

我猎杀四周,找不到这种类型的问题的任何信息。

Answer 1:

我不是构造函数抛出异常比坏的争论等原因的忠实粉丝。 我想大概我的模型类型以不同的方式。 但这里的一些想法。 起初,我想过做这样的事情:

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;
}

做任何的这些想法帮助吗?



Answer 2:

写在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");


文章来源: How to handle constructor exception when using Autofac WcfIntegration