如何在Autofac中通过构造函数注入带NamedParameter的Keyed服务?
Yes, you absolutely can achieve constructor injection for your keyed service with named parameters in Autofac—you just need to extend Autofac's filtering mechanism since the built-in KeyFilterAttribute doesn't support passing additional parameters out of the box. Here's a step-by-step solution tailored to your scenario:
1. Create a Custom Attribute to Carry Key + Parameter Metadata
First, define an attribute that marks the constructor parameter, including both the service key and the named parameter details you need to pass to the keyed service's registration:
[AttributeUsage(AttributeTargets.Parameter)] public class KeyedWithNamedParamAttribute : Attribute { public object ServiceKey { get; } public string ParamName { get; } public object ParamValue { get; } public KeyedWithNamedParamAttribute(object serviceKey, string paramName, object paramValue) { ServiceKey = serviceKey; ParamName = paramName; ParamValue = paramValue; } }
2. Register Your Consumer with a Custom Parameter Resolver
When registering MyConsumer with Autofac, use a ResolvedParameter to detect the custom attribute and resolve the keyed service with the required named parameter. This tells Autofac exactly how to resolve that specific constructor parameter:
builder.RegisterType<MyConsumer>() .WithParameter(new ResolvedParameter( // Match any constructor parameter decorated with our custom attribute (parameterInfo, context) => parameterInfo.GetCustomAttribute<KeyedWithNamedParamAttribute>() != null, // Resolve the keyed service using the metadata from the attribute (parameterInfo, context) => { var attr = parameterInfo.GetCustomAttribute<KeyedWithNamedParamAttribute>(); return context.ResolveKeyed( attr.ServiceKey, parameterInfo.ParameterType, new NamedParameter(attr.ParamName, attr.ParamValue)); }));
3. Update Your Consumer's Constructor for Automatic Injection
Now you can inject IMyService directly in the constructor, using your custom attribute to specify the key and named parameter values. No more manual ResolveKeyed calls in the constructor:
public class MyConsumer { private readonly IMyService _myService; public MyConsumer( [KeyedWithNamedParam("myKey", "myNamedParameter", "parameterValue")] IMyService myService) { _myService = myService; } }
Bonus: Handling Dynamic Parameter Values
If your named parameter value isn't static (e.g., it needs to be fetched from another registered service), you can adjust the resolver to pull it from the Autofac container instead of using a hardcoded value:
// Inside the ResolvedParameter logic var dynamicParamValue = context.Resolve<IMyParameterProvider>().GetValue(); // Example service to fetch dynamic values return context.ResolveKeyed( attr.ServiceKey, parameterInfo.ParameterType, new NamedParameter(attr.ParamName, dynamicParamValue));
How This Works
The built-in KeyFilterAttribute only handles matching the service key, but Autofac's ResolvedParameter gives you full control over parameter resolution. By combining a custom attribute to carry metadata with a resolver that uses that metadata, you can inject keyed services with any required parameters automatically—exactly what you were looking for.
内容的提问来源于stack exchange,提问作者Travieso

