Autofac RegisterInstance未按预期工作:注入的IMemoryCache实例不一致
IMemoryCache实例注入不一致问题
在我的ASP.NET Core应用中,我在Startup里以实例形式注册了IMemoryCache,但注入控制器时,收到的却是和注册时不同的实例,明明注册的是单例实例,这是怎么回事?
Program.cs代码
public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args) .Build() .Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureServices(s => s.AddAutofac()) .UseStartup<Startup>(); }
Startup.cs代码
public class Startup { public static IMemoryCache MemoryCacheInstance; public Startup() { } public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); MemoryCacheInstance = new MemoryCache(new MemoryCacheOptions()); var builder = new ContainerBuilder(); builder.RegisterInstance<IMemoryCache>(MemoryCacheInstance); builder.Populate(services); return new AutofacServiceProvider(builder.Build()); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } }
Controller代码
public class UtilsController : Controller { public UtilsController(IMemoryCache memoryCache) { if (Startup.MemoryCacheInstance == memoryCache) { // 调试器永远不会走到这里 } } [HttpGet("api/utils/test-method")] public string TestMethod() { return null; } }
问题原因
核心问题是**services.AddMvc()会自动注册IMemoryCache的默认实现**,而你调用builder.Populate(services)时,把这个默认注册也同步到了Autofac容器中。Autofac解析服务时,默认注册的优先级高于你手动调用的RegisterInstance,最终导致控制器注入的是框架自动创建的实例,而非你手动初始化的那个。
解决方法
有三种可行的修复方式:
调整注册顺序,先加自定义实例再调用AddMvc
框架的AddMvc()会检测服务集合中是否已存在IMemoryCache注册,若存在则不会重复添加。所以先注册你的实例,再添加Mvc服务即可:public IServiceProvider ConfigureServices(IServiceCollection services) { // 先注册自定义IMemoryCache实例 MemoryCacheInstance = new MemoryCache(new MemoryCacheOptions()); services.AddSingleton<IMemoryCache>(MemoryCacheInstance); // 再添加Mvc服务 services.AddMvc(); var builder = new ContainerBuilder(); builder.Populate(services); return new AutofacServiceProvider(builder.Build()); }移除默认注册后再添加自定义实例
如果不想调整顺序,可以先移除服务集合中已有的IMemoryCache注册,再添加自己的实例:public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); MemoryCacheInstance = new MemoryCache(new MemoryCacheOptions()); // 移除框架自动注册的IMemoryCache var cacheDescriptor = services.FirstOrDefault(d => d.ServiceType == typeof(IMemoryCache)); if (cacheDescriptor != null) { services.Remove(cacheDescriptor); } // 添加自定义实例 services.AddSingleton<IMemoryCache>(MemoryCacheInstance); var builder = new ContainerBuilder(); builder.Populate(services); return new AutofacServiceProvider(builder.Build()); }在Autofac Populate后覆盖注册
若坚持使用Autofac的RegisterInstance,可以在builder.Populate(services)之后再注册实例,这样会覆盖之前从服务集合同步过来的默认注册:public IServiceProvider ConfigureServices(IServiceCollection services) { services.AddMvc(); MemoryCacheInstance = new MemoryCache(new MemoryCacheOptions()); var builder = new ContainerBuilder(); builder.Populate(services); // 覆盖默认注册 builder.RegisterInstance<IMemoryCache>(MemoryCacheInstance).SingleInstance(); return new AutofacServiceProvider(builder.Build()); }
以上任意一种方式,都能确保控制器注入的是你手动创建的IMemoryCache实例。
内容的提问来源于stack exchange,提问作者Martin Staufcik
相关产品推荐
相关产品推荐

