

Injecting Services to ASP.NET Core Controller Actions
source link: https://www.tuicool.com/articles/hit/B3iQR3r
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

ASP.NET Core comes with a thin but rich and powerful built-in dependency injection mechanism we can use to inject instances to controllers and some other parts of web applications. Although constructor injection is the most famous dependency injection method for controllers, there is also dependency injection to controller actions available. This post introduces controller action injection and shows how to benefit from it.
Constructor Injection With Controllers
Controller action injection is a great feature to use with controllers where most of the actions need some specific service that others don't need. In ASP.NET Core, it's traditional to use constructor injection. Let's take a look at the following controller.
public class HomeController : Controller { private readonly ICustomerDAO _customerDao; private readonly ISmsService _smsService; private readonly IVehicleTelemetryService _telemetryService; private readonly IMailService _mailService; public HomeController(ICustomerDAO customerDao, ISmsService smsService, IMailService mailService, IVehicleTelemetryService telemetryService) { _customerDao = customerDao; _smsService = smsService; _mailService = mailService; _telemetryService = telemetryService; } public IActionResult Index(int page = 1) { var customers = _customerDao.ListCustomers(page: 1, pageSize: 25); return View(customers); } public IActionResult SendSms(int id, string text) { var customer = _customerDao.GetById(id); _smsService.Send(customer.Phone, text); } public IActionResult SendMail(int id, string subject, string body) { var customer = _customerDao.GetById(id); _mailService.Send(customer.Email, subject, body); } public IActionResult GetCoordinates(int id) { var coordinates = _telemetryService.GetCoordinates(id); return Json(coordinates); } }
It seems all okay but when we think a few steps further we can see that part of this class can easily grow messy, as, over time, we'll probably inject more services into the controller.
public class HomeController : Controller { private readonly ICustomerDAO _customerDao; private readonly ISmsService _smsService; private readonly IVehicleTelemetryService _telemetryService; private readonly IMailService _mailService; /* More injected services here */ public HomeController(ICustomerDAO customerDao, ISmsService smsService, IMailService mailService, /* More injected services here */ IVehicleTelemetryService telemetryService) { _customerDao = customerDao; _smsService = smsService; _mailService = mailService; _telemetryService = telemetryService; /* More injected services here */ } // Controller actions follow }
But at the same time, we have services used only by one controller action and there is no reason to have these services available in the class scope. The action scope would be enough for us.
Injecting Services to the Controller Action
The solution to our problem is called controller action injection
. It means we can inject services into controller actions instead of controller constructors. When we add some service to an action parameters list we confuse the MVC, as it doesn't know, by default, that we want something from the services. We have to apply FromServicesAttribute
to the action parameters to tell MVC that this parameter is coming from dependency-injection. As a sample, let's use controller action injection with the SendSms()
method of our sample controller.
public IActionResult SendSms(int id, string text, [FromServices]ISmsService smsService) { var customer = _customerDao.GetById(id); smsService.Send(customer.Phone, text); }
But SendSms()
is not the only action that needs an instance of some service that the actions don't use. We also have the SendMail()
and GetCoordinates()
actions. After moving to the controller action injection, our class looks smaller and cleaner.
public class HomeController : Controller { private readonly ICustomerDAO _customerDao; public HomeController(ICustomerDAO customerDao) { _customerDao = customerDao; } public IActionResult Index(int page = 1) { var customers = _customerDao.ListCustomers(page: 1, pageSize: 25); return View(customers); } public IActionResult SendSms(int id, string text, [FromServices]ISmsService smsService) { var customer = _customerDao.GetById(id); smsService.Send(customer.Phone, text); } public IActionResult SendMail(int id, string subject, string body, [FromServices]IMailService mailService) { var customer = _customerDao.GetById(id); mailService.Send(customer.Email, subject, body); } public IActionResult GetCoordinates(int id, [FromServices]IVehicleTelemetryService telemetryService) { var coordinates = telemetryService.GetCoordinates(id); return Json(coordinates); } }
We leave ICustomerDAO
at the class level and inject it using controller constructor injection because this class is used by multiple controller actions. Our class is now cleaner and we don't have A growing pile of constructor arguments anymore. It also makes it easier to write tests for controllers, as we don't have to initialize controllers with all the dependencies it could possibly be using.
Wrapping Up
Controller action injection is a useful feature that helps us keep services used by one action away from the class scope. This way we don't pile injected services to class level and our controller classes are smaller. If service is used by more than one or few actions it is a good idea to have reference to it at the class level. Otherwise, we can keep controller classes smaller by using controller action injection.
Recommend
-
98
ASP.NET MVC 中的过滤器(Filter)是 AOP(面向切面编程) 思想的一种实现,供我们在执行管道的特定阶段执行代码,通过使用过滤器可以实现 短路请求、缓存请求结果、日志统一记录、参数合法性验证、异常统一处理、返回值格式化 等等,同时...
-
107
连发了几篇ASP.NETCore文章,果不其然接到各方询问:「喵的妈呀,微软又推新东西了?」「WebForm玩完了吗?」「我ASP.NETMVC还没开始玩耶,是不是不用学了?」先简单答复以上疑问:是的,ASP.NETCore 是下一代的ASP.NET,能跨平台执行,预期是
-
13
How to handle unknown actions in ASP.NET Core 5 MVC Handle unknown actions elegantly in ASP.NET 5 by creating routes that dynamically map to the views in your application. ...
-
13
ASP.NET Core Controller与IOC的羁绊 前言
-
17
你可以遵循一些最佳实践来写出更干净的 Controller,一般我们称这种方法写出来的 Controller 为瘦Controller,瘦 Controller 的好处在于拥有更...
-
8
March 18, 2021 Resolve Services In ASP.NET Core Startup
-
8
April 29, 2021 Access Background Services From ASP.NET Core ...
-
11
Use ASP.NET Core hosted services to run a background task 30th January 2022 ...
-
9
Using Background Services in ASP.NET Core I have a small link shortener that I run for myself. I built it mostly so I could update short links when an URL changes (which bitly didn’t let me do). It’s...
-
6
Testing ASP.NET Core gRPC services in JetBrains Rider I was recently chatting to Dan Clarke for
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK