You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WebApi/WebApi2:如何用Autofac解析需路由参数的依赖及配置注入?

解决WebApi 2中Autofac注入带路由参数依赖的方案

1. 定义核心接口与实现

首先明确你的依赖链:控制器 → IRepository → IContext,其中IContext需通过工厂根据路由中的context id创建。

1.1 定义IContext与工厂接口

public interface IContext
{
    // 你的Context方法,比如数据库上下文操作等
    string ContextId { get; }
}

public class MyContext : IContext
{
    public string ContextId { get; }

    public MyContext(string contextId)
    {
        ContextId = contextId;
        // 初始化Context逻辑,比如连接对应数据库等
    }
}

public interface IContextFactory
{
    IContext CreateContext(string contextId);
}

public class ContextFactory : IContextFactory
{
    public IContext CreateContext(string contextId)
    {
        // 这里实现你的工厂逻辑,比如根据contextId返回不同的Context实例
        return new MyContext(contextId);
    }
}

1.2 定义IRepository与实现

public interface IRepository
{
    // 你的Repository方法
    object GetData();
    void SaveData(object model);
}

public class MyRepository : IRepository
{
    private readonly IContext _context;

    public MyRepository(IContext context)
    {
        _context = context;
    }

    public object GetData()
    {
        // 使用_context处理数据逻辑
        return $"Data from context {_context.ContextId}";
    }

    public void SaveData(object model)
    {
        // 使用_context保存数据逻辑
    }
}

2. Autofac容器配置

接下来配置Autofac,实现动态从路由获取context id并注入依赖。

2.1 基础注册

首先注册工厂和Repository,重点是Repository的依赖注入逻辑:

var builder = new ContainerBuilder();

// 注册Context工厂为单例(工厂一般不需要请求级实例)
builder.RegisterType<ContextFactory>().As<IContextFactory>().SingleInstance();

// 注册Repository,每个请求创建一个实例,并动态注入IContext
builder.RegisterType<MyRepository>().As<IRepository>()
       .InstancePerRequest()
       .WithParameter(
           new ResolvedParameter(
               // 匹配需要注入IContext的参数
               (parameterInfo, componentContext) => parameterInfo.ParameterType == typeof(IContext),
               // 动态解析IContext:从当前请求路由获取context id,通过工厂创建
               (parameterInfo, componentContext) =>
               {
                   // 获取当前请求的HttpRequestMessage
                   var request = componentContext.Resolve<HttpRequestMessage>();
                   // 从路由数据中提取context id
                   if (!request.GetRouteData().Values.TryGetValue("contextId", out var contextIdObj) ||
                       !(contextIdObj is string contextId))
                   {
                       throw new InvalidOperationException("路由中未找到有效的contextId参数");
                   }
                   // 通过工厂创建对应的IContext
                   var factory = componentContext.Resolve<IContextFactory>();
                   return factory.CreateContext(contextId);
               }));

// 注册所有WebApi控制器
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

// 构建容器并替换WebApi的依赖解析器
var container = builder.Build();
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

3. 控制器中使用依赖

现在控制器可以直接通过构造函数注入IRepository,这个实例已经绑定了当前请求路由中的context id对应的IContext:

public class DataController : ApiController
{
    private readonly IRepository _repository;

    // 构造函数注入IRepository
    public DataController(IRepository repository)
    {
        _repository = repository;
    }

    [HttpGet]
    [Route("api/data/{contextId}")]
    public IHttpActionResult Get(string contextId)
    {
        // 直接使用_repository,它已经关联了当前contextId的IContext
        var data = _repository.GetData();
        return Ok(data);
    }

    [HttpPost]
    [Route("api/data/{contextId}")]
    public IHttpActionResult Post(string contextId, [FromBody] MyModel model)
    {
        _repository.SaveData(model);
        return Ok("数据保存成功");
    }
}

4. 备选方案:使用Func工厂注入

如果需要更灵活地在动作中指定context id(比如同一个控制器的不同动作可能使用不同的id),可以注入Func<string, IRepository>:

4.1 注册Func工厂

builder.Register<Func<string, IRepository>>(componentContext =>
{
    // 保留组件上下文引用,用于后续解析依赖
    var ctx = componentContext.Resolve<IComponentContext>();
    return contextId =>
    {
        var factory = ctx.Resolve<IContextFactory>();
        var context = factory.CreateContext(contextId);
        return new MyRepository(context);
    };
});

4.2 控制器中使用Func

public class DataController : ApiController
{
    private readonly Func<string, IRepository> _repositoryFactory;

    public DataController(Func<string, IRepository> repositoryFactory)
    {
        _repositoryFactory = repositoryFactory;
    }

    [HttpGet]
    [Route("api/data/{contextId}")]
    public IHttpActionResult Get(string contextId)
    {
        // 手动传入contextId获取对应的Repository
        var repository = _repositoryFactory(contextId);
        var data = repository.GetData();
        return Ok(data);
    }
}

关键注意事项

  • 请求生命周期:使用InstancePerRequest确保每个请求的IRepository和IContext都是独立实例,避免并发问题。
  • 路由参数校验:在解析context id时要做好参数校验,防止空值或无效值导致异常。
  • WebApi依赖解析器替换:必须将Autofac的依赖解析器设置为WebApi的全局解析器,否则Autofac的注入逻辑不会生效。

内容的提问来源于stack exchange,提问作者Usman Khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:13:17