it-swarm.com.de

Erstellen einer Abhängigkeitsinjektion für ASP.NET MVC 5

Das Erstellen einer Abhängigkeitseinspritzung mit ASP.NET Core ist ziemlich einfach. Die Dokumentation erklärt es sehr gut hier und dieser Typ hat ein Killervideo , um es zu erklären.

Ich möchte jedoch dasselbe mit meinem ASP.NET MVC 5-Projekt tun. Wie kann die Abhängigkeitsinjektion mit ASP.MVC 5 behandelt werden?

Ist die Abhängigkeitseinspritzung nur auf Controller beschränkt oder kann sie mit jeder Klasse funktionieren?

23
Jaylen

In ASP.Net MVC können Sie das .Net Core DI von NuGet anstelle einer Alternative von Drittanbietern verwenden: -

using Microsoft.Extensions.DependencyInjection

Für die MVC Start/Configuration-Klasse: -

public void Configuration(IAppBuilder app)
        {
            // We will use Dependency Injection for all controllers and other classes, so we'll need a service collection
            var services = new ServiceCollection();

            // configure all of the services required for DI
            ConfigureServices(services);

            // Configure authentication
            ConfigureAuth(app);

            // Create a new resolver from our own default implementation
            var resolver = new DefaultDependencyResolver(services.BuildServiceProvider());

            // Set the application resolver to our default resolver. This comes from "System.Web.Mvc"
            //Other services may be added elsewhere through time
            DependencyResolver.SetResolver(resolver);
        }

Mein Projekt verwendet Identity User und ich habe die OWIN-Startkonfiguration ersetzt, um stattdessen einen dienstbasierten Ansatz zu verfolgen. Die standardmäßigen Identity User-Klassen verwenden statische Factory-Methoden zum Erstellen von Instanzen. Ich habe diesen Code in die Konstruktoren verschoben und bin auf DI angewiesen, um die entsprechende Injektion bereitzustellen. Es ist noch in Arbeit, aber hier bin ich an: -

 public void ConfigureServices(IServiceCollection services)
        {               
            //====================================================
            // Create the DB context for the IDENTITY database
            //====================================================
            // Add a database context - this can be instantiated with no parameters
            services.AddTransient(typeof(ApplicationDbContext));

            //====================================================
            // ApplicationUserManager
            //====================================================
            // instantiation requires the following instance of the Identity database
            services.AddTransient(typeof(IUserStore<ApplicationUser>), p => new UserStore<ApplicationUser>(new ApplicationDbContext()));

            // with the above defined, we can add the user manager class as a type
            services.AddTransient(typeof(ApplicationUserManager));

            //====================================================
            // ApplicationSignInManager
            //====================================================
            // instantiation requires two parameters, [ApplicationUserManager] (defined above) and [IAuthenticationManager]
            services.AddTransient(typeof(Microsoft.Owin.Security.IAuthenticationManager), p => new OwinContext().Authentication);
            services.AddTransient(typeof(ApplicationSignInManager));

            //====================================================
            // ApplicationRoleManager
            //====================================================
            // Maps the rolemanager of identity role to the concrete role manager type
            services.AddTransient<RoleManager<IdentityRole>, ApplicationRoleManager>();

            // Maps the role store role to the implemented type
            services.AddTransient<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>();
            services.AddTransient(typeof(ApplicationRoleManager));

            //====================================================
            // Add all controllers as services
            //====================================================
            services.AddControllersAsServices(typeof(Startup).Assembly.GetExportedTypes()
                .Where(t => !t.IsAbstract && !t.IsGenericTypeDefinition)
            .Where(t => typeof(IController).IsAssignableFrom(t)
            || t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase)));
        }

Die Account Controller-Klasse hat den einzigen Konstruktor: -

[Authorize]
public class AccountController : Controller
{
    private ApplicationSignInManager _signInManager;
    private ApplicationUserManager _userManager;
    private RoleManager<IdentityRole> _roleManager;

    public AccountController(ApplicationUserManager userManager, ApplicationSignInManager signInManager, RoleManager<IdentityRole> roleManager)
    {
        UserManager = userManager;
        SignInManager = signInManager;
        RoleManager = roleManager;
    }
14
pixelda

Für diese Antwort habe ich ein Microsoft-Beispiel für ein WebApi-Projekt als Grundlage für das Beispiel heruntergeladen und DI-Dienste wie folgt hinzugefügt:

  • Aktualisieren Sie das Target Framework auf 4.6.1
  • NuGet das DI-Paket: - Microsoft.Extensions.DependencyInjection

Fügen Sie nach der standardmäßigen MapHttpRoute-Konfiguration Code hinzu, um zu registrieren, welche Dienste Sie benötigen

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

using Microsoft.Extensions.DependencyInjection;
using System.Web.Http.Dependencies;
using ProductsApp.Controllers;

namespace ProductsApp
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );


            // create the DI services and make the default resolver
            var services = new ServiceCollection();
            services.AddTransient(typeof(DefaultProduct));
            services.AddTransient(typeof(ProductsController));

            var resolver = new MyDependencyResolver(services.BuildServiceProvider());
            config.DependencyResolver = resolver;
        }
    }

    public class DefaultProduct : ProductsApp.Models.Product
    {
        public DefaultProduct()
        {
            this.Category = "Computing";
            this.Id = 999;
            this.Name = "Direct Injection";
            this.Price = 99.99M;
        }
    }

    /// <summary>
    /// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods
    /// </summary>
    public class MyDependencyResolver : IDependencyResolver
    {
        protected IServiceProvider _serviceProvider;

        public MyDependencyResolver(IServiceProvider serviceProvider)
        {
            this._serviceProvider = serviceProvider;
        }

        public IDependencyScope BeginScope()
        {
            return this;
        }

        public void Dispose()
        {

        }

        public object GetService(Type serviceType)
        {
            return this._serviceProvider.GetService(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this._serviceProvider.GetServices(serviceType);
        }

        public void AddService()
        {

        }
    }

    public static class ServiceProviderExtensions
    {
        public static IServiceCollection AddControllersAsServices(this IServiceCollection services, IEnumerable<Type> serviceTypes)
        {
            foreach (var type in serviceTypes)
            {
                services.AddTransient(type);
            }

            return services;
        }
    }
}

Ich habe dann den vorhandenen Controller geändert, um den DI-Typ zu übernehmen (Hinweis, es gibt nur den einen Controller)

using ProductsApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace ProductsApp.Controllers
{
    public class ProductsController : ApiController
    {
        DefaultProduct _dp = null;

        public ProductsController(DefaultProduct dp)
        {
            _dp = dp;
            //
            products.Add(dp);
        }

        List<Product> products = new List<Product>()
        {
            new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 },
            new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M },
            new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M }
        };

        public IEnumerable<Product> GetAllProducts()
        {
            return products;
        }

        public IHttpActionResult GetProduct(int id)
        {
            var product = products.FirstOrDefault((p) => p.Id == id);
            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }
    }
}
7
pixelda

Ich empfehle Ihnen die Verwendung von Autofac , es gibt andere Fwk wie Unity, Ninject, die Benchmarks autofac hat eine hervorragende Leistung.

http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison

Hier ist die Integration mit MVC (und funktioniert mit allen Klassen)

http://docs.autofac.org/de/latest/integration/mvc.html

4
Dei Revoledo

Die einfachste Möglichkeit zum Implementieren von Dependency Injection in ASP.NET MVC 5 besteht in der Verwendung des von Microsoft selbst entwickelten Tools namens Unity.

Sie können im Internet viele Ressourcen dazu finden und zunächst die offizielle Dokumentation lesen, die hier verfügbar ist: Entwicklerhandbuch zur Abhängigkeitseinspritzung mit Unity

Ist die Abhängigkeitseinspritzung nur auf Controller beschränkt oder kann sie mit jeder Klasse funktionieren?

Es funktioniert mit jeder Klasse und in jedem Projekt, solange Sie die mit der Implementierung verknüpfte Schnittstelle registrieren (wenn Sie das IoC-Muster nutzen möchten), müssen Sie lediglich die Schnittstellen-Instantiation hinzufügen in Ihrem Konstruktor.

2
Sakuto

Mein Standardabhängigkeitsauflöser

/// <summary>
/// Provides the default dependency resolver for the application - based on IDependencyResolver, which hhas just two methods
/// </summary>
public class DefaultDependencyResolver : IDependencyResolver
{
    /// <summary>
    /// Provides the service that holds the services
    /// </summary>
    protected IServiceProvider serviceProvider;

    /// <summary>
    /// Create the service resolver using the service provided (Direct Injection pattern)
    /// </summary>
    /// <param name="serviceProvider"></param>
    public DefaultDependencyResolver(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
    }

    /// <summary>
    /// Get a service by type - assume you get the first one encountered
    /// </summary>
    /// <param name="serviceType"></param>
    /// <returns></returns>
    public object GetService(Type serviceType)
    {
        return this.serviceProvider.GetService(serviceType);
    }

    /// <summary>
    /// Get all services of a type
    /// </summary>
    /// <param name="serviceType"></param>
    /// <returns></returns>
    public IEnumerable<object> GetServices(Type serviceType)
    {
        return this.serviceProvider.GetServices(serviceType);
    }
}
2
pixelda

In diesem Video zeigt Microsoft MVP eine Abhängigkeitsinjektion in MVC5 mit AutoFac. Sehr klare Erklärung zum Einrichten:

Abhängigkeitsinjektion MVC5 Demo

Quellcode ist auf GitHub verfügbar.

1
Edward Pescetto

Ich empfehle die Verwendung von Windsor, indem Sie das Nuget-Paket Castle Windsor MVC Bootstrapper installieren. Dann können Sie einen Dienst erstellen, der IWindsorInstaller implementiert.

public class ServiceRegister : IWindsorInstaller
{
    public void Install(Castle.Windsor.IWindsorContainer container,
    Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
    {
        SomeTypeRequiredByConstructor context = new SomeTypeRequiredByConstructor ();

        container.Register(
            Component
                .For<IServiceToRegister>()
                .ImplementedBy<ServiceToRegister>().
             DependsOn(Dependency.OnValue<SomeTypeRequiredByConstructor>(context))//This is in case your service has parametrize constructoe
                .LifestyleTransient());
    }
}

Dann in Ihrem Controller so etwas:

public class MyController 
{
    IServiceToRegister _serviceToRegister;

    public MyController (IServiceToRegister serviceToRegister)
    {
        _serviceToRegister = serviceToRegister;//Then you can use it inside your controller
    }
}

Standardmäßig wird die Bibliothek das Senden des richtigen Dienstes an Ihren Controller ausführen, indem Sie beim Start install() von ServiceRegister aufrufen, da sie IWindsorInstaller implementiert.

0
Ali Ezzat Odeh