ASP. NET Core Chapter 4 MVC (4.4) Dependency injection and controller, coremvc
Original article: Dependency Injection and Controllers
Author: Steve Smith
Translation: Liu Hao Yang
Proofreading: Meng Shuai Yang (Shu yuan)
ASP. NET Core MVC controllers should explicitly request their dependencies through their constructors. In some cases, a single controller operation may require a service, and requests at the Controller level may be meaningless. In this case, you can also select the service as the parameter of the action method.
Chapter:
- Dependency Injection
- Constructor Injection
- Action injection and FromServices
- Access settings from Controller
View or download sample code
Dependency Injection
Dependency injection (DI) is a technology shown in Dependency Inversion Principle that allows applications to consist of loosely coupled modules. ASP. NET Core has built-in dependency injection, which makes the application easier to test and maintain.
Constructor Injection
The constructor-based dependency injection built in ASP. NET Core supports scaling to the MVC controller. By adding only one service type as the constructor parameter to your controller, ASP. NET Core will try to parse this type using the built-in service container. Services are usually, but they are not always defined using interfaces. For example, if your application is based on the business logic of the current time, You can inject a time-based service (instead of hard coding it ), this will allow your test to pass an implementation that uses the set time.
using System;namespace ControllerDI.Interfaces{ public interface IDateTime { DateTime Now { get; } }}
To implement such an interface, the system clock used during runtime is negligible:
using System;using ControllerDI.Interfaces;namespace ControllerDI.Services{ public class SystemDateTime : IDateTime { public DateTime Now { get { return DateTime.Now; } } }}
With this code, we can use this service in our controller. In this exampleHomeController
OfIndex
The method adds some logic to display greetings to users based on the time of the day.
Using ControllerDI. interfaces; using Microsoft. aspNetCore. mvc; namespace ControllerDI. controllers {public class HomeController: Controller {private readonly IDateTime _ dateTime; // manually highlight public HomeController (IDateTime dateTime) // manually highlight {_ dateTime = dateTime; // manually highlight} public IActionResult Index () {var serverTime = _ dateTime. now; // manually highlight if (serverTime. hour <12) // manually highlight {ViewData ["Message"] = "It's m Orning here-Good Morning! "; // Manual highlight} else if (serverTime. Hour <17) // Manual highlight {ViewData [" Message "] =" It's afternoon here-Good Afternoon! "; // Manual highlight} else // Manual highlight {ViewData [" Message "] =" It's evening here-Good Evening! "; // Manual highlight} return View (); // Manual highlight }}}
If we run the application now, we may encounter an exception:
An unhandled exception occurred while processing the request.InvalidOperationException: Unable to resolve service for type 'ControllerDI.Interfaces.IDateTime' while attempting to activate 'ControllerDI.Controllers.HomeController'.Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
When this error occursStartup
ClassConfigureServices
Method. Request to specifyIDateTime
UseSystemDateTime
To add the highlighted rows in the following list to yourConfigureServices
Method:
Public void ConfigureServices (IServiceCollection services) {// Add application services. services. AddTransient <IDateTime, SystemDateTime> (); // manually highlight}
Note:
This special service can be implemented using any different lifecycle options (Transient
,Scoped
OrSingleton
). Refer to dependency injection to learn how each scope option affects your service behavior.
Once the service is configured, run the application and navigate to the homepage to display the expected time-based message:
Prompt
Refer to Testing Controller Logic to learn how to display request dependency http://deviq.com/explicit-dependencies-principle in the Controller to make code easier to test.
The built-in dependency injection of ASP. NET Core supports only one constructor for the request service type. If you have more than one constructor, you may get an exception description:
An unhandled exception occurred while processing the request.InvalidOperationException: Multiple constructors accepting all given argument types have been found in type 'ControllerDI.Controllers.HomeController'. There should only be one applicable constructor.Microsoft.Extensions.DependencyInjection.ActivatorUtilities.FindApplicableConstructor(Type instanceType, Type[] argumentTypes, ConstructorInfo& matchingConstructor, Nullable`1[]& parameterMap)
As an error message status, you can correct the problem of only one constructor. You can also refer to replace the default dependency injection support with a third party implementation to support multiple constructors.
Action injection and FromServices
Sometimes you do not need to use more than one Action in your controller. In this case, it makes sense to use the service as a parameter of the Action method. This is through the use of features[FromServices]
Tag parameter implementation:
Public IActionResult About ([FromServices] IDateTime dateTime) // manually highlight {ViewData ["Message"] = "Currently on the server the time is" + dateTime. now; return View ();}
Access settings from Controller
Accessing application settings or configuration settings in the controller is a common mode. The access mode described in configuration should be used. Generally, you should not use dependency injection to directly request settings from your controller. A better way is to requestIOptions<T>
Instance,T
Is the configuration type you need.
To use the option mode, you must create an option type, for example:
namespace ControllerDI.Model{ public class SampleWebSettings { public string Title { get; set; } public int Updates { get; set; } }}
Then you need to configure the application to use the option modelConfigureServices
Add your configuration class to the Service set:
Public Startup (IHostingEnvironment env) {var builder = new ConfigurationBuilder () // manually highlight. setBasePath (env. contentRootPath) // manually highlight. addJsonFile ("samplewebsettings. json "); // manually highlight Configuration = builder. build (); // Manual highlight} public IConfigurationRoot Configuration {get; set ;}// manual highlight // This method gets called by the runtime. use this method to add services to the container. // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940public Void ConfigureServices (IServiceCollection services) {// Required to use the Options <T> pattern services. addOptions (); // manually highlight // Add settings from configuration services. configure <SampleWebSettings> (Configuration); // manually highlight // Uncomment to add settings from code/services. configure <SampleWebSettings> (settings => // {// settings. updates = 17; //}); services. addMvc (); // Add application services. services. addTransient <IDateTime, SystemDateTime> ();}
Note:
In the above list, we configure the application to read the settings from a file in JSON format. You can also configure the settings in the Code as shown in the code above. Refer to configuration for more configuration options.
Once you specify a strongly typed configuration object (in this example,SampleWebSettings
), And added to the Service set, you can request from any controller or Action MethodIOptions<T>
(In this example,IOptions<SampleWebSettings>
). The following code demonstrates how to request settings from the Controller.
Public class SettingsController: Controller {private readonly SampleWebSettings _ settings; // manually highlight public SettingsController (IOptions <SampleWebSettings> settingsOptions) // manually highlight {_ settings = settingsOptions. value; // manually highlight} public IActionResult Index () {ViewData ["Title"] = _ settings. title; ViewData ["Updates"] = _ settings. updates; return View ();}}
The following option mode allows the settings and configurations to be separated from each other and ensures that the controller complies with the separation of concerns because it does not need to know how or where to find the settings. The absence of static cling or the direct instantiation of setting classes in the controller makes unit testing easier for the controller.
Returned directory
Reference page: http://qingqingquege.cnblogs.com/p/5933752.html