経緯
StartupのConfigureの処理中に、DBの内容を参照したい。
具体的には初回起動時にDBのシステム設定のテーブルが空なら、初期設定画面に強制遷移したい。その為にDBが見たかったのですが、ちょっと引っかかってしまったので、備忘録として書いときます。
まあ、引っかかってる人がいれば参考になるか、もっといい方法があるぞとか教えてください。
実装
Startup.csでDBが以下の様に登録されている場合。(Npgsqlになっているのはご愛嬌)
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(
Configuration.GetConnectionString("DefaultConnection")));
...
}
同じくStartup.csのConfigureメソッドでDIを利用して以下のように記述して使おうとすると
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ApplicationDbContext dbContext)
{
if(dbContext.Settings.Count() == 0)
{
// 初期設定できてないので初期設定画面を表示
context.Response.Redirect("/Initialize");
return;
}
...
}
実行時に以下のようなエラーメッセージが表示されてしまいます。
ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'ApplicationDbContext'.
オブジェクトはありそうですが、中のDB接続が破棄されてるみたいです。
引数「IApplicationBuilder app」から取得する必要がありそうですが、なかなかそういった記事が見当たらないので試してみたところ、
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var dbContext = app.ApplicationServices.CreateScope().ServiceProvider.GetRequiredService<ApplicationDbContext>();
if(dbContext.Settings.Count() == 0)
{
// 初期設定できてないので初期設定画面を表示
context.Response.Redirect("/Initialize");
return;
}
...
}
とするとうまくいきました。
分りにくかったのは、app.ApplicationServicesにも「GetRequiredService<>」メソッドがあるのですがこちらでは取得できません。上記の様にスコープを作ってそこのサービスから取得しないといけない様です。
とりあえずこれでできたのいいのですが、こうすべきというやり方があればコメントください。