DI 1.0 —— 通過 RegisterInstance
注入
一開始,並不是很懂 AutoFac 的用法,又因為要使用特定的構造器和參數來初始化 DbContext
,所以我想到的辦法就是使用 RegisterInstance
,代碼如下:
var optionsBuilder = new DbContextOptionsBuilder<BookListDbContext>();
optionsBuilder.UseMySql(connectionString, b => b.MigrationsAssembly("BookList.Domain"));
// SingleInstance 就是單例模式,現在想起來當時寫的好智障
containerBuilder.RegisterInstance(new BookListDbContext(optionsBuilder.Options)).SingleInstance();
一開始在本地用 Swagger 一個一個的調試 api 的感覺還很好,沒啥問題,后來前端同學把 js 加上,就會經常的出現 404。經過 debug 發現,是 DbContext
出現了沖突,多個請求同時訪問同一個 DbContext
對象,造成異常,雖然不清楚為啥沒有出現500而是404。
DI 2.0 —— 添加 IDbContext
接口,通過 RegisterType
注入
知道了問題所在,就想到了更換服務的生命周期設置,於是我在上面的代碼的基礎上直接把 SingleInstance
改成了 InstancePerLifetimeScope
,但在運行時遇到了異常,原來 RegisterInstance
僅支持 SingleInstance
。既然這樣,那就接着換,於是我在網上發現了別人通過讓自定義的 DbContext
實現一個 IDbContext
接口,進行依賴注入,代碼如下:
// ··········· 省略 IDbContext 的定義
var optionsBuilder = new DbContextOptionsBuilder<BookListDbContext>();
optionsBuilder.UseMySql(connectionString, b => b.MigrationsAssembly("BookList.Domain"));
containerBuilder.RegisterType<MyDbContext>()
.As<IDbContext>()
.WithParam("options",optionsBuilder.Options)
.InstancePerLifetimeScope();
這樣一來,我們就需要提取一個 IDbContext
,這個工作有些麻煩,但是在 ReSharper 的幫助下,簡化了不少。然而,這個方法並沒有生效,現在消費者類依賴 IDbContext
接口的一個實例,但是在實例化服務的時候卻拋出了異常。。。
很蛋疼,剛剛提取出來的接口白費了。
DI 3.0 —— 使用 Register
方法
其實這個是我根據 Intellisence 試出來的,代碼如下:
// 首先注冊 options,供 DbContext 服務初始化使用
containerBuilder.Register(c =>
{
var optionsBuilder = new DbContextOptionsBuilder<BookListDbContext>();
optionsBuilder.UseMySql(connectionString, b => b
.MigrationsAssembly("BookList.Domain"));
return optionsBuilder.Options;
}).InstancePerLifetimeScope();
// 注冊 DbContext
containerBuilder.RegisterType<BookListDbContext>()
.AsSelf()
.InstancePerLifetimeScope();
實驗證明,這樣注入 DbContext
是沒有問題的