简体   繁体   中英

Select multiple registrations for the same type in Autofac

I am developing a web app using MVC4 with Autofac. I have a global exception filter in which I'm injecting a logger service, so I'm initializing it in App_Start like this:

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

This is the general layout of the filter: public class ErrorHandlerAttribute : HandleErrorAttribute { private readonly ILoggerService logger;

    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) { }
    }
}

If I weren't using Autofac, I would've had something like this:

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 is my custom exception filter, derived from MVC's HandleErrorAttribute.

(since I built it so it can handle any exception). (因为我已经构建了它,因此它可以处理任何异常)。 Unfortunately, I can't seem to find any way to do this, despite scouring the web and other forums for possible solutions. I've tried a lot of configuration changes, different registrations, collection resolving etc.

The way I would like it to work would be similar to this:

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

Surprisingly, this compiles and runs, but all 3 IExceptionFilter instances are normal, defaulted ErrorHandlerAttribute (with View="Error" and ExceptionType=typeof(object)).

I am aware of the fact that Autofac takes the last registration of a service as default, and I have tried commenting two out of three registrations, as well as using PreserveExistingDefaults, still all my exception filters come with default values.

Have I misunderstood the WithProperties extension method or is there another similar way to implement what I want?

:

Thanks for Alex's suggestion, I solved it by using NamedPropertyParameter and switching the order of the statements:

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();

You need to use NamedPropertyParameter instead of 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();

You also may as well register the global filters as SingleInstance because they are resolved and then added directly to the filter collection. MVC will not request an instance of these filters per HTTP request. It will just use the instances you added to the collection.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM