我如何决定使用 Autofac 根据每个请求注入哪个服务实现?

How can I decide which service implementation to inject on a per request basis with Autofac?

我正在使用 ASP.NET 网络 API/Autofac。有没有一种方法可以根据路由或查询字符串参数来决定在每个请求的基础上注入两种可能的命名服务中的哪一种?

我的注册是这样的:

var configuration = GlobalConfiguration.Configuration;
var builder = new ContainerBuilder();

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

builder.RegisterType<Provider1>().Named<IProvider>("one").InstancePerRequest();
builder.RegisterType<Provider2>().Named<IProvider>("two").InstancePerRequest();

var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
configuration.DependencyResolver = resolver;

还有我的控制器:

public class SomeController : ApiController
{
    private readonly IProvider _provider;

    public SomeController(IProvider provider)
    {
        _provider = provider;
    }

    // GET /api/some?provider=x
    public IHttpActionResult Get(string provider)
    {
        //...
    }
}

您可以通过注册 lambda 表达式来实现。

builder.Register(c => 
{
    if(true) 
    {
        return c.ResolveNamed<IProvider>("one");
    }
    else 
    {
        return c.ResolveNamed<IProvider>("two");
    }
})
.As<IProvider>()
.InstancePerRequest();

您可以通过创建自定义界面来更进一步。例如,如果你想根据站点名称注入不同的实现,你可以创建一个 ISiteNameProvider 接口。例如:

public interface ISiteNameProvider
{
    String SiteName { get; }
}

public class HttpContextSiteNameProvider : ISiteNameProvider
{
    public HttpContextSiteNameProvider(HttpContextBase context)
    {
        this._context = context;
    }

    private readonly HttpContextBase _context; 

    public String SiteName 
    {
        get 
        {
            return this._context.Request.Url.Host;
        }
    }
}

然后

builder.RegisterType<HttpContextSiteNameProvider>()
       .As<ISiteNameProvider>()
       .InstancePerRequest();

builder.Register(c => 
{
    String siteName = c.Resolve<ISiteNameProvider>().SiteName;
    if(siteName == "www.domain.com") 
    {
        return c.ResolveNamed<IProvider>("one");
    }
    else 
    {
        return c.ResolveNamed<IProvider>("two");
    }
})
.As<IProvider>()
.InstancePerRequest();