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
相关产品推荐
相关产品推荐

