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?
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;
}
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:
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);
}
}
}
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)
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.
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);
}
}
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.
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.