Categories
Uncategorized

C # Dependency Injection

Dependency Injection

1. What is Dependency Injection

We need to create a SkiCardController application of a number of other services to process view, create and edit requests. Specifically, he visited with SkiCardContext data, access the current user’s information with UserManager, with IAuthorizationService check whether the current user has permission to view or edit all requests.
    If you do not DI or other mode, SkiCardController is responsible for creating new instances of these services.
    No DI of SkiCardController

public class SkiCardController:Controller
{
    private readonly SkiCardContext _SkiCardContext;
    private readonly UserManager _UserManager;
    private readonly IAuthorizationService _AuthorizationService;
    public SkiCardController()
    {
        _SkiCardContext = new SkiCardContext(new DbContextOptions());

        _UserManager = new UserManager();

        _AuthorizationService = new DefaultAuthorizationService();
    }
}

These seem pretty simple, but in fact this code is not compiled by. First of all, we do not have designated as SkiCardContext or database connection strings, so he did not create DbContext correct. UserManager no default constructor, the only constructor UserManager public needs nine parameters.
    Discloses a class constructor UserManager

public UserManager(IUserStore store, IOption optionsAccessor, IPasswordHasher passwordHasher, IEnumerable> userValidator, IEnumerable> passwordValidator, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, IServiceProvider service, ILogger> logger)
{
    // ...
}

So, now we SkiCardController also need to know how to create these services. DefaultAuthorizationService constructor has three parameters. Whether it is our controller, or other service applications, all the services need to interact with their own hands to create, which is clearly inappropriate.
    This approach has brought a lot of duplicate code in addition, lead to a tight coupling of code. For example, SkiCardController now know the specific knowledge DefaultAhtorizationService this class, rather than a general idea of ​​the open method IAuthorizationService interfaces. If we want to change the constructor DefaultAuthorizationService, we also need to change SkiCardController and other uses DefaultAuthorizationService class.
    Tight coupling will increase the difficulty of implementation replacement. While we are unlikely to achieve their own authorized a new service, but the ability to achieve the replacement is still very important, he makes mocking easier. Mocking the importance of this technology is that it makes it easier for interaction between application services.

2. Using the service is easy to resolve dependencies

Dependency injection is a common mode used to resolve the dependencies. After using dependency injection, like creating and instance management responsibilities to be transferred to a container. In addition, each class needs to declare other categories on which he relies. The container can resolve these dependencies during operation and demand delivery. Dependency injection is a pattern form Inversion of Control (IoC), meaning that component itself without direct dependency instantiators duties. You may have heard IoC container, which is another name for DI implementation.
    The most common method is to use injection dependency constructor injection technique. When using constructor injection, the class will declare a constructor that takes all the services it needs in the form of parameters. For example, SkiCardController has a receiving SkiCardContext, UserManager and IAuthorizationService constructor vessel during operation will be responsible for transmitting it to the instances of those classes.

public class SkiCardController : Controller
{
    private readonly SkiCardContext _SkiCardContext;
    private readonly UserManager _UserManager;
    private readonly IAthorizationService _AuthorizationService;

    public SkiCardController(SkiCardContext skiCardContext, UserManager userManager, IAthorizationService autherizationService)
    {
        _SkiCardContext = skiCardContext;
        _UserManager = userManager;
        _AuthorizationService = autherizationService
    }
}

Constructor injection can be clearly reflected to a given class dependent needed. Even the compiler will help us, because they do not pass the necessary class can not be created SkiCardController. As we have said before, the main benefit of this approach is the ability to make unit testing easier.
    The other method is injection injection properties, may be used to modify a characteristic of a property disclosure, one to indicate the value of this attribute should be set easily during operation. Properties injected as good as constructor injection so common, not all IoC container supports this approach.
    When the application starts, you can register to the service container. The method of registration services depending on the container used.

note:
    Currently, dependency injection is the most popular mode of resolving dependencies, but not the only mode available. Service Locator pattern for some time had been sought after by the .Net community, when using this mode, the service will be registered to a centralized service locator. If a service needs another example of a service that will instantiate the request to the service type of the service locator. The main disadvantage of the Service Locator pattern is a service explicitly dependent on both the service locator.

The dependency injection ASP.NET Core

ASP.NET Core provides a basic implementation of the container, native support constructor injection. When the application starts, the service can be registered in ConfigureService method Startup class.
    Startup method of ConfigureService

    public void ConfigureService(IServiceCollection service)
    {
        // add service here.
    }

Even in the most simple ASP.NET Core MVC project, in order to make your applications up and running, the container also want to include at least some services for the job. MVC framework itself dependent on container some services, and through them to properly support the controller activates, view rendering, and other core concepts.

Use the built-in container

First of all you have to do is add ASP.NET Core Services framework provides. If each service ASP.NET Core provides all you need to manually register the words, ConfigureService method will soon be out of control. Fortunately Add * extension method all the functions provided by the framework has a corresponding, you can use these methods to easily add extensions serve the desired function. For example, AddDbContext method is used to register DbContext Entity Framework. The method also provides the option to delegate, to allow you to make some additional settings at the time of registration services. For example, when registering DbContext class, with the option to delegate the context associated with the connection string DefaultConnection specified SQL Server database.
    DbContext registered in AlpineSkiHouse.Web in.

    service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));

Other features frameworks need to add further comprises means for authentication and authorization of Identity, enable Options and enable the configuration of strongly typed MVC routing, controller and all other built-in features.

    service.AddIdentity()
        .AddEntityFrameworkStore()
        .AddDefaultTokenProviders();
    service.AddOptions();
    service.AddMvc();

The next step is to register the application you’re writing services or third-party libraries included in the service. To ensure that any service required for any controllers are properly registered. In the registration application services, be sure to consider the life cycle of the service.

Note:
One of the responsibilities of the container is to manage the life cycle of the service. The lifetime of a service refers to the time the service exists (from the time the dependency injection container was created until the container releases all instances of the service).

Life cycle

description

Every time you call, will create a new instance. This life-cycle services for lightweight

Create an instance for each HTTP request

Every time you call, create an instance for the service

And Singleton similar, but when the application starts up the instance is registered to a container

Transient
Scoped
Singleton
Instance

When you add a DBContext using the AddDBContext method, the context is registered using the Scoped lifecycle class. When a request enters the pipeline, if its subsequent routing requires an instance of the DBContext, an instance is created and made available to all services that require the database connection. In fact, the services created by the container are limited to the corresponding HTTP request and used to satisfy all dependencies during the request execution. When the request is complete, the container releases all occupied services so that the runtime can clean up.
Here are some examples of application services in the Alpineskihouse.web project. Their service lifecycle is specified through the appropriate Add* method.

    service.AddSingleton();
    service.AddTransient();
    service.AddTransient();
    service.AddScoped();

As application services grow, you can simplify the ConfiguReservice method by creating extension methods. For example, if your application has many IauthorizationHandler classes that need to be registered, you can create an addauthorizationHandlers extension method.
Examples of extension methods used to add a set of services

public static void AddAuthorizationHandlers(this IServiceCollection services)
{
    services.AddSingleton();
    // Add other authorization handlers
}

After adding service IServiceCollection, the frame will be used to connect the constructor dependency injection during operation. For example, if a request is routed to SkiCardController, frame constructor SkiCardController disclosed will be used to create instances of it, while passing it to the desired service. The controller no longer know how to create these services and how to manage their life cycle.

Note:
When developing new features, you may occasionally receive an InvalidOperationException like: Can to resolve service for type ‘ServiceType’ while tried to activate ‘ Somecontroller’ error message.
The most likely reason is to forget to add the corresponding service type in the ConfiguReservices method. Adding CSRinformationService in this example resolves this error.

    services.AddScoped()

Using third-party container

The containers built into the ASP.NET Core framework provide only the necessary features to support most applications. But the.NET platform has many more feature-rich mature dependency injection frameworks. Fortunately, ASP.NET Core has a built-in way to replace the default container with a third-party container.
Some IoC containers popular with.NET platforms include Niniject, StructureMap, and Autofac. The best support for ASP.NET Core is Autofac, so we’ll use it as a paradigm. The first step refers to the NuGet package Autofac.extensions.dependencyInjection. Next, we need to make some changes to the ConfiguReservice method in Startup. Modify it to return IServiceProvider instead of returning the original void. The framework service will still be added to iServericecollection, and our application services will be registered with the Autofac container. Finally returns an AutoFaceProvider that provides the Autofac container to replace the built-in container with ASP.NET Core.
ConfiguReservoices using Autofac

    public IServiceProvider ConfigureServices(IServiceCollectioin services)
    {
        // Add framework services
        service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));
        service.AddDbContext(options=>options.UserSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity()
        .AddEntityFrameworkStores()
        .AddDefaultTokenProviders();

        services.AddOptions();
        services.AddMvc();

        // Now register our services with Autofac container
        var builder = new ContainerBuilder();
        builder.RegisterType().As();
        builder.Populate(services);
        var container = builder.Build();

        // Create the IServiceProvider based on the container.
        return new AutofaceServiceProvider(container);
    }

This example is quite simple, Autofac also provides some advanced features, such as scanning assemblies can be used to find qualified class of your choice. For example, we can automatically register all IAuthorizationHandler implement projects using the scan assembly.
    Use an assembly to automatically scan the type of registration.

    var currentAssembly = Assembly.GetEntryAssembly();
    builder.RegisterAssemblyTypes(currentAssembly)
    .Where(t => t.IsAssignableTo())
    .As();

Another great feature is to configure Autofac isolated module. Module is very simple, it is a class that contains a set of configuration-related services. In the simplest case, Autofac module is similar to creating an extension method for the IServiceCollection. But the module can be used to implement some of the more advanced features. Because they are kind, they can also be found and loaded during operation, so that we can implement a plug-in framework of.
    Module simple example Autofac

    public class AuthorizationHandlerModule:Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            var currentAssembly = Assembly.GetEntryAssembly();
            builder.RegisterAssemblyTypes(currentAssembly)
            .Where(t=>t.IsAssignableTo())
            .As();
        }
    }

In the loading module Startup.ConfigureServices

    builder.RegisterModule(new AuthorizationHandlerModule());

Leave a Reply