web-dev-qa-db-ja.com

ASP.NET MVC 5の依存性注入を作成する方法は?

ASP.NET Coreを使用した依存性注入の作成は非常に簡単です。ドキュメンテーションはそれを非常によく説明しています ここ そしてこの人はそれを説明するために キラービデオ を持っています.

ただし、ASP.NET MVC 5プロジェクトでも同じことをしたいです。 ASP.MVC 5を使用した依存性注入の処理方法

また、依存性注入はコントローラーのみに制限されていますか、それともどのクラスでも機能しますか?

34
Jaylen

ASP.Net MVCでは、サードパーティの代替の1つではなく、NuGetの.Net Core DIを使用できます。

using Microsoft.Extensions.DependencyInjection

MVC Start/Configurationクラスの場合:-

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);
        }

私のプロジェクトではIdentity Userを使用しており、OWINスタートアップ構成を置き換えて、代わりにサービスベースのアプローチを採用しています。デフォルトのIdentity Userクラスは、静的ファクトリメソッドを使用してインスタンスを作成します。そのコードをコンストラクターに移動し、適切なインジェクションを提供するためにDIに依存しました。それはまだ進行中の作業ですが、ここに私がいる場所があります-

 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)));
        }

Account Controllerクラスには、単一のコンストラクターがあります。

[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;
    }
27
pixelda

この答えのために、私は Microsoft WebApiプロジェクトの例 を例の基礎としてダウンロードし、DIサービスを次のように追加しました。

  • ターゲットフレームワークを4.6.1に更新する
  • NuGet DIパッケージ:-Microsoft.Extensions.DependencyInjection

標準のMapHttpRoute構成の後、必要なサービスを登録するコードを追加します

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;
        }
    }
}

次に、既存のコントローラーを修正して、DIタイプを取得します(1つのアクターのみが存在することに注意してください)

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);
        }
    }
}
17
pixelda

Autofac を使用することをお勧めします。Unity、ninjectなどの別のfwkがあります。autofacのベンチマークには優れたパフォーマンスがあります。

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

これがMVCとの統合です(すべてのクラスで動作します)

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

4
Dei Revoledo

デフォルトの依存関係リゾルバー

/// <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);
    }
}
3
pixelda

ASP.NET MVC 5で依存性注入を実装する最も簡単な方法は、UnityというMicrosoft自身が開発したツールを使用することです。

インターネットに関する多くのリソースを見つけることができ、ここから入手できる公式ドキュメントを読むことから始めることができます: Unity を使用した依存性注入の開発者ガイド

また、依存性注入はコントローラーのみに制限されていますか、それともどのクラスでも機能しますか?

実装に関連するインターフェイスを登録している限り(プロジェクト内の任意のクラスで動作します( IoCパターン を利用したい場合)、その後はすべて行う必要があります)コンストラクタにインターフェイスのインスタンス化を追加することです。

2
Sakuto

このビデオでは、Microsoft MVPがAutoFacを使用したMVC5での依存性注入をデモします。設定方法に関する非常に明確な説明:

依存性注入MVC​​5デモ

ソースコードは GitHub で入手できます。

1
Edward Pescetto