الگوی Service locator را در قسمت دوم بررسی کردیم. همانطور که عنوان شد، بهتر است تا جائیکه امکان دارد از بکارگیری آن به علت ضدالگو بودن پرهیز کرد. در ادامه قسمتهای مختلف یک برنامهی ASP.NET Core را که میتوان بدون نیاز به استفادهی الگوی Service locator، تزریق وابستگیها را در آنها انجام داد، مرور میکنیم.
در کلاس آغازین برنامه
در اینجا در متد Configure آن تنها کافی است اینترفیس سرویس مدنظر خود را مانند IAmACustomService، به صورت یک پارامتر جدید اضافه کنید. کار وهله سازی آن توسط Service Provider برنامه به صورت خودکار صورت میگیرد:
یک نکتهی مهم: اگر طول عمر IAmACustomService را Scoped تعریف کردهاید و این سرویس از نوع IDisposable نیز میباشد، این روش کارآیی نداشته و باید از نکتهی «روش صحیح Dispose اشیایی با طول عمر Scoped، در خارج از طول عمر یک درخواست ASP.NET Core» که در قسمت قبل معرفی شد استفاده کنید.
در میان افزارها
هم سازندهی یک میان افزار و هم متد Invoke آن قابلیت تزریق وابستگیها را دارند:
از سازندهی آن برای تزریق وابستگی سرویسهایی با طول عمر Singleton استفاده کنید. ServiceProvider به همراه ویژگی است به نام Scope Validation. در این حالت اگر طول عمر سرویسی Singleton باشد (مانند طول عمر یک میانافزار) و در سازندهی آن یک سرویس با طول عمر Scoped تزریق شود، در زمان اجرا یک استثناء را صادر میکند؛ چون در این حالت رفتار این سرویس Scoped نیز Singleton میشود که احتمالا مدنظر شما نیست. در این حالت از پارامترهای اضافی متد Invoke میتوان برای تزریق وابستگیهایی با طول عمر Transient و یا Scoped استفاده کرد.
البته میتوان این Scope Validation را در فایل program.cs به نحو زیر غیرفعال کرد، ولی بهتر است اینکار را انجام ندهید و همان مقدار پیشفرض آن بسیار مناسب است:
در کنترلرها
سازندههای کنترلرهای برنامههای ASP.NET Core قابلیت تزریق وابستگیها را دارند:
در اینجا حتی میتوان با استفاده از ویژگی FromServices، یک سرویس را توسط پارامترهای یک اکشن متد نیز درخواست کرد:
در این حالت بجای model binding، کار دریافت این سرویس درخواستی صورت میگیرد.
در مدلها
ویژگی FromServices بر روی مدلها نیز کار میکند.
در اینجا نحوهی تعریف TestModel را به همراه ویژگی FromServices مشاهده میکنید:
این حالت که property injection نیز نام دارد، نیاز به خاصیتی با یک public setter را دارد.
در Viewها
در Razor Views نیز میتوان توسط inject directive@ کار تزریق وابستگیها را انجام داد:
در ویژگیها و فیلترها
در ASP.NET Core تزریق وابستگیهای در سازندههای فیلترها نیز کار میکند:
در این حالت چون سازندهی این ویژگی، پارامتر دار شدهاست و این پارامترها نیز یک مقدار ثابت قابل کامپایل نیستند، برای معرفی یک چنین فیلتری باید از ServiceFilterها به صورت زیر استفاده کرد:
در کلاس آغازین برنامه
در اینجا در متد Configure آن تنها کافی است اینترفیس سرویس مدنظر خود را مانند IAmACustomService، به صورت یک پارامتر جدید اضافه کنید. کار وهله سازی آن توسط Service Provider برنامه به صورت خودکار صورت میگیرد:
public class Startup { public void ConfigureServices(IServiceCollection services) { } public void Configure(IApplicationBuilder app, IAmACustomService customService) { // .... } }
یک نکتهی مهم: اگر طول عمر IAmACustomService را Scoped تعریف کردهاید و این سرویس از نوع IDisposable نیز میباشد، این روش کارآیی نداشته و باید از نکتهی «روش صحیح Dispose اشیایی با طول عمر Scoped، در خارج از طول عمر یک درخواست ASP.NET Core» که در قسمت قبل معرفی شد استفاده کنید.
در میان افزارها
هم سازندهی یک میان افزار و هم متد Invoke آن قابلیت تزریق وابستگیها را دارند:
public class TestMiddleware { public TestMiddleware(RequestDelegate next, IAmACustomService service) { // ... } public async Task Invoke(HttpContext context, IAmACustomService service) { // ... } }
البته میتوان این Scope Validation را در فایل program.cs به نحو زیر غیرفعال کرد، ولی بهتر است اینکار را انجام ندهید و همان مقدار پیشفرض آن بسیار مناسب است:
public static IWebHostBuilder CreateDefaultBuilder(string[] args) { var builder = new WebHostBuilder() //... .UseDefaultServiceProvider((context, options) => { options.ValidateScopes = context.HostingEnvironment.IsDevelopment(); }) //...
در کنترلرها
سازندههای کنترلرهای برنامههای ASP.NET Core قابلیت تزریق وابستگیها را دارند:
public class HelloController : Controller { private readonly IAmACustomService _customService; public HelloController(IAmACustomService customService) { _customService = customService; } public IActionResult Get() { // ... } }
[HttpGet("[action]")] public IActionResult Index([FromServices] IAmACustomService service) { // ... }
در مدلها
ویژگی FromServices بر روی مدلها نیز کار میکند.
public IActionResult Index(TestModel model) { // ... }
public class TestModel { public string Name { get; set; } [FromServices] public IAmACustomService CustomService { get; set; } }
در Viewها
در Razor Views نیز میتوان توسط inject directive@ کار تزریق وابستگیها را انجام داد:
@inject IAmACustomService CustomService
در ویژگیها و فیلترها
در ASP.NET Core تزریق وابستگیهای در سازندههای فیلترها نیز کار میکند:
public class ApiExceptionFilter : ExceptionFilterAttribute { private ILogger<ApiExceptionFilter> _logger; private IHostingEnvironment _environment; private IConfiguration _configuration; public ApiExceptionFilter(IHostingEnvironment environment, IConfiguration configuration, ILogger<ApiExceptionFilter> logger) { _environment = environment; _configuration = configuration; _logger = logger; }
[Route("api/[controller]")] [ApiController] [ServiceFilter(typeof(ApiExceptionFilter))] public class ValuesController : ControllerBase {