.NET Core 3中使用Autofac如何为不同调用者传递运行时变量?
You can absolutely have Root's constructor behave differently when resolved for A vs B in .NET Core 3 with Autofac. The key is letting Root know which class is depending on it during construction. Below are two reliable approaches:
Approach 1: Track Dependency Context (No Changes to A/B)
Autofac lets you access the resolution context to trace which class is requesting Root. Here's how to set this up:
- Update the
Rootconstructor to accept Autofac'sIComponentContextand use it to find the parent dependency:
public class Root { public Root(IComponentContext context) { // Grab the active resolution request context var requestContext = context.Resolve<IResolveRequestContext>().ActiveRequest; // Trace back to the class directly requesting Root var requestingType = requestContext.Parent?.Registration.Activator.LimitType; if (requestingType == typeof(A)) { DoSomethingForClassA(); } else if (requestingType == typeof(B)) { DoSomethingForClassB(); } } private void DoSomethingForClassA() => Console.WriteLine("Running logic for Class A"); private void DoSomethingForClassB() => Console.WriteLine("Running logic for Class B"); }
- Enable resolution context tracking when building your Autofac container:
var builder = new ContainerBuilder(); // Add support for resolving the request context builder.RegisterSource(new ResolveRequestContextRegistrationSource()); // Register your classes as usual builder.RegisterType<Root>(); builder.RegisterType<A>(); builder.RegisterType<B>(); var container = builder.Build();
This method is great if you don't want to modify A or B at all—Autofac handles the context tracking behind the scenes. Just note that ResolveRequestContext requires Autofac 4.8 or newer.
Approach 2: Explicitly Pass a Marker Parameter (More Controllable)
If you prefer a more explicit, readable approach (and don't want to rely on Autofac's internal context), you can pass a marker parameter to Root when registering A and B:
- Modify
Rootto accept a marker string in its constructor:
public class Root { public Root(string resolvedFor) { if (resolvedFor == nameof(A)) { DoSomethingForClassA(); } else if (resolvedFor == nameof(B)) { DoSomethingForClassB(); } } private void DoSomethingForClassA() => Console.WriteLine("Running logic for Class A"); private void DoSomethingForClassB() => Console.WriteLine("Running logic for Class B"); }
- Configure Autofac to pass the right parameter for each class:
var builder = new ContainerBuilder(); // Register Class A, and pass "A" as the marker for its Root dependency builder.RegisterType<A>() .WithParameter(new ResolvedParameter( (param, ctx) => param.ParameterType == typeof(Root), (param, ctx) => ctx.Resolve<Root>(new TypedParameter(typeof(string), nameof(A))) )); // Register Class B, passing "B" instead builder.RegisterType<B>() .WithParameter(new ResolvedParameter( (param, ctx) => param.ParameterType == typeof(Root), (param, ctx) => ctx.Resolve<Root>(new TypedParameter(typeof(string), nameof(B))) )); builder.RegisterType<Root>(); var container = builder.Build();
This approach is more transparent—anyone reading the code can immediately see that A and B get different Root configurations. It also doesn't rely on Autofac's internal APIs, making it more future-proof.
Important Notes
- If
Rootneeds to be a singleton, neither of these approaches will work (since singletons are only constructed once). In that case, you'd need to either:- Move the conditional logic to an instance method instead of the constructor, or
- Register two named instances of
Root(one forA, one forB) and haveA/Bdepend on the named version.
- For Approach 1, double-check your Autofac version to ensure
ResolveRequestContextis available.
内容的提问来源于stack exchange,提问作者Qtybek

