c# - 如何使 autofac KeyFilter 在 asp.net-core web api 中工作?

标签 c# asp.net-core autofac

无法使用 KeyFilter 属性解析 asp.net core web api 2.2 中的注册类型

我想使用 Autofac 来解析类型的不同实例。我使用 RegisterType().Keyed 和 RegisterType().Named 在 Startup.ConfigureServices 中注册了类型。

我可以使用 IContainer.ResolveKeyed 解析实例,但无法使用 KeyFilter 解析构造函数中的实例

启动

   public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public static IContainer Container { get; private set; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).AddControllersAsServices();

            var builder = new ContainerBuilder();
            builder.Populate(services);

            builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Eric").Named<Foobar>("Eric").SingleInstance();
            builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Fred").Keyed<Foobar>("Fred").SingleInstance();

            Container = builder.Build();

            var serviceProvider = new AutofacServiceProvider(Container);
            return serviceProvider;
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();
            app.UseMvc();
        }
    }

值 Controller

    [Route("api/[controller]")]
    [ApiController]
    public class ValuesController : ControllerBase
    {
        private readonly Foobar fb1;
        private readonly Foobar fb2;

        public ValuesController([KeyFilter("Eric")]Foobar fbEric, [KeyFilter("Fred")]Foobar fbFred)
        {
            // KeyFilter not work
            fb1 = fbEric;
            fb2 = fbFred;
            
            // Container.ResolvedKeyed work
            fb1 = Startup.Container.ResolveKeyed<Foobar>("Eric");
            fb2 = Startup.Container.ResolveNamed<Foobar>("Fred");
        }
        
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return new string[] { fb1.Say(), fb2.Say() };
        }
    }

使用KeyFilter会抛出以下异常:

An unhandled exception has occurred while executing the request.
Autofac.Core.DependencyResolutionException: An exception was thrown while activating Autofac.MI.WebApi.Controllers.ValuesController. ---> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'Autofac.MI.WebApi.Controllers.ValuesController' can be invoked with the available services and parameters:
Cannot resolve parameter 'Autofac.MI.ClassLib.Foobar fbEric' of constructor 'Void .ctor(Autofac.MI.ClassLib.Foobar, Autofac.MI.ClassLib.Foobar)'.
   at Autofac.Core.Activators.Reflection.ReflectionActivator.GetValidConstructorBindings(IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 160
   at Autofac.Core.Activators.Reflection.ReflectionActivator.ActivateInstance(IComponentContext context, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Activators\Reflection\ReflectionActivator.cs:line 120
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 117
   --- End of inner exception stack trace ---
   at Autofac.Core.Resolving.InstanceLookup.Activate(IEnumerable`1 parameters, Object& decoratorTarget) in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 135
   at Autofac.Core.Resolving.InstanceLookup.Execute() in C:\projects\autofac\src\Autofac\Core\Resolving\InstanceLookup.cs:line 83
   at Autofac.Core.Resolving.ResolveOperation.GetOrCreateInstance(ISharingLifetimeScope currentOperationScope, IComponentRegistration registration, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 131
   at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\Core\Resolving\ResolveOperation.cs:line 84
   at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 1041
   at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters) in C:\projects\autofac\src\Autofac\ResolutionExtensions.cs:line 871
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.AspNetCore.Mvc.Controllers.ServiceBasedControllerActivator.Create(ControllerContext actionContext)
   at Microsoft.AspNetCore.Mvc.Controllers.ControllerFactoryProvider.<>c__DisplayClass5_0.<CreateControllerFactory>g__CreateController|0(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

最佳答案

对于KeyFilter,您需要使用WithAttributeFiltering注册服务。

对于AddControllersAsServices,它只将服务注册到服务集合,但没有向WithAttributeFiltering注册。

尝试下面的代码:

services.AddMvc().AddControllersAsServices().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

var builder = new ContainerBuilder();
builder.Populate(services);
builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Eric").Named<Foobar>("Eric").SingleInstance();
builder.RegisterType<Foobar>().UsingConstructor(typeof(string)).WithParameter("name", "Fred").Keyed<Foobar>("Fred").SingleInstance();
var controllers = typeof(Startup).Assembly.GetTypes().Where(t => t.BaseType == typeof(ControllerBase)).ToArray(); // for api controller
//var controllers = typeof(Startup).Assembly.GetTypes().Where(t => t.BaseType == typeof(Controller)).ToArray(); // for mvc controller
builder.RegisterTypes(controllers).WithAttributeFiltering();

Container = builder.Build();

关于c# - 如何使 autofac KeyFilter 在 asp.net-core web api 中工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57522349/

相关文章:

c# - 每次关闭表单应用程序时注销 C# WCF

c# - 如果 X 分钟内没有新项目进入 channel ,如何读取 Channel<T> 中小于批量大小的剩余项目?

autofac - 理解 Autofac 中 Lifetime 范围的概念

c# - 如何将依赖项注入(inject) MVVM View Model 类?

c# - Autofac 通用接口(interface)工厂

c# - 使用 nunit 测试事件

c# - WCF。服务泛型方法

c# - 无法访问 VB 类文件...... friend 的事

c# - ASP.NET Core 2 本地化(ViewLocalizer 不工作)

jquery - 如何单独影响每个元素的样式(悬停)