在Autofac中为同一类型选择多个注册

本文关键字:选择 注册 类型 Autofac | 更新日期: 2023-09-27 18:20:39

我正在使用带有Autofac的MVC4开发一个web应用程序。我有一个全局异常过滤器,我在其中注入了一个记录器服务,所以我在App_Start中初始化它,如下所示:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(DependencyResolver.Current.GetService<IExceptionFilter>());
    }

这是过滤器的总体布局:公共类ErrorHandlerAttribute:HandleErrorAttribute{专用只读ILoggerService记录器;

    public ErrorHandlerAttribute(ILoggerService logger)
    {
        this.logger = logger;
    }
    public override void OnException(ExceptionContext filterContext)
    {
        //dostuff
    }
    public void LogError(ExceptionContext context)
    {
        try
        {
            logger.Error(context.Exception.Message, context.Exception);
        }
        catch (Exception) { }
    }
}

如果我没有使用Autofac,我会有这样的东西:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ErrorHandlerAttribute());
        filters.Add(new ErrorHandlerAttribute
        {
            View = "UnauthorizedException",
            ExceptionType = typeof(UnauthorizedAccessException)
        });
        filters.Add(new ErrorHandlerAttribute
        {
            View = "PageNotFound",
            ExceptionType = typeof(NotImplementedException)
        });
    }

ErrorHandlerAttribute是我的自定义异常过滤器,源自MVC的HandleErrorAttribute。

我希望能够保持重定向到自定义错误页面的能力,同时使用Autofac的注入和单个过滤器(因为我构建了它,所以它可以处理任何异常)。不幸的是,尽管我在网络和其他论坛上搜索可能的解决方案,但我似乎找不到任何方法来做到这一点。我尝试了很多配置更改、不同的注册、集合解析等。

我希望它的工作方式与此类似:

    builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>().InstancePerHttpRequest();
    builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
        .WithProperties(new List<NamedParameter>() { new NamedParameter("ExceptionType", typeof(UnauthorizedAccessException)), new NamedParameter("View", "UnauthorizedAccess") })
        .InstancePerHttpRequest();
    builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
        .WithProperties(new List<NamedParameter>() { new NamedParameter("ExceptionType", typeof(NotImplementedException)), new NamedParameter("View", "UnderConstruction") })
        .InstancePerHttpRequest();
    builder.RegisterFilterProvider();
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        DependencyResolver.Current.GetServices<IExceptionFilter>().ForEach(f => filters.Add(f));
    }

令人惊讶的是,它编译并运行,但所有3个IExceptionFilter实例都是正常的、默认的ErrorHandlerAttribute(View="Error",ExceptionType=typeof(object))。

我知道Autofac将服务的最后一次注册作为默认值,我已经尝试对三次注册中的两次进行注释,并使用PreserveExistingDefaults,但我所有的异常过滤器都带有默认值。

我是否误解了WithProperties扩展方法,或者是否有其他类似的方法来实现我想要的?

编辑1:

感谢Alex的建议,我使用NamedPropertyParameter并切换语句的顺序来解决这个问题:

builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
    .WithProperties(new List<NamedPropertyParameter> { new NamedPropertyParameter("ExceptionType", typeof(UnauthorizedAccessException)), new NamedPropertyParameter("View", "UnauthorizedAccess") })
    .InstancePerHttpRequest();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
    .WithProperties(new List<NamedPropertyParameter> { new NamedPropertyParameter("ExceptionType", typeof(NotImplementedException)), new NamedPropertyParameter("View", "UnderConstruction") })
    .InstancePerHttpRequest();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>().InstancePerHttpRequest();

在Autofac中为同一类型选择多个注册

您需要使用NamedPropertyParameter而不是NamedParameter

builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
    .SingleInstance();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
    .WithProperties(new List<NamedPropertyParameter> { new NamedPropertyParameter("ExceptionType", typeof(UnauthorizedAccessException)), new NamedPropertyParameter("View", "UnauthorizedAccess") })
    .SingleInstance();
builder.RegisterType<ErrorHandlerAttribute>().As<IExceptionFilter>()
    .WithProperties(new List<NamedPropertyParameter> { new NamedPropertyParameter("ExceptionType", typeof(NotImplementedException)), new NamedPropertyParameter("View", "UnderConstruction") })
    .SingleInstance();

您还可以将全局筛选器注册为SingleInstance,因为它们已解析,然后直接添加到筛选器集合中。MVC不会在每个HTTP请求中请求这些筛选器的实例。它将只使用您添加到集合中的实例。