نکتهای مهم در مورد تزریق وابستگیها در کلاس ویژهی آغازین برنامه
عموما کلاسهای کار با بانک اطلاعاتی، با طول عمر Scoped مشخص میشوند (جهت پیاده سازی الگوی واحد کار):
services.AddScoped<IOperationScoped, Operation>();
به این معنا که یک وهله از کلاس Operation در طول درخواست جاری در بین تمامی درخواست کنندههای آن به اشتراک گذاشته خواهد شد. این به اشتراک گذاری فقط زمانی معنا خواهد داشت که طول عمر درخواست جاری را مدنظر داشته باشیم و همچنین تزریق وابستگی IOperationScoped به صورت متداولی در کنترلرها، View Components، فیلترها و غیره انجام شود.
اما اگر از سرویس فرضی IOperationScoped در متدهای مختلف کلاس آغازین برنامه استفاده کنیم، طول عمری را که دریافت خواهیم کرد singleton خواهد بود و نه Scoped. علت اینجا است که در پشت صحنه، در ابتدای هر درخواست توسط سرویسی به نام IServiceScopeFactory کار وهله سازی scope صورت گرفته و در پایان درخواست این scope رهاسازی میشود:
using (var scope = scopeFactory.CreateScope())
{
// ...
}
اما در کلاس آغازین برنامه، ما هنوز داخل scope قرار نگرفتهایم. بنابراین هر درخواست وهلهای از سرویس IOperationScoped با طول عمر Scoped، تنها همان وهلهی ابتدایی آنرا باز میگرداند و singleton رفتار میکند؛ چون scope ایی ایجاد و تخریب نشدهاست.
در یک چنین مواردی، برای اطمینان حاصل کردن از dispose شدن سرویس در پایان کار، نیاز است مراحل ایجاد scope و dispose آنرا به صورت دستی به نحو ذیل مدیریت کنیم:
public void Configure(IApplicationBuilder app,
ILoggerFactory loggerFactory,
IServiceScopeFactory scopeFactory)
{
using (var scope = scopeFactory.CreateScope())
{
var initializer = scope.ServiceProvider.GetService<IOperationScoped>();
initializer.SeedAsync().Wait();
}
}
بنابراین به صورت خلاصه
اگر سرویسی با طول عمر Scoped تعریف شد (و نه سایر حالتها)، درخواست وهلهای از آن در کلاس آغازین برنامه، طول عمر singleton را خواهد داشت؛ مگر اینکه صراحتا scope را به نحو فوق ایجاد و تخریب کنید.
این نکته در متدهای الحاقی که قرار است در کلاس آغازین برنامه اجرا شوند، مفید خواهد بود.