ASP.NET Core-Windsor Castleによる汎用登録

7990 ワード

問題の導入


ASP.NET Core-依存注入この文章では、ASPをどのように利用するかを知っています.NET Core原生の容器で依存注入を実現しているのに、なぜデフォルトのIoC容器を置き換えるのでしょうか.ASPからNET Core-依存注入この文章を見ると、デフォルトのIoCコンテナはいくつかの小型プロジェクトにとって基本的に十分であり、基本的なAddXXXXメソッドを提供してインスタンス関係をバインドしているが、大型プロジェクトにとっては難しい.大型プロジェクトには汎用的な登録が必要であり、各オブジェクトの解析関係を手動で追加することはできない.これこそ私たちが直面している痛みである.

ソリューション


ここではCastleの内容を詳しく理解するつもりはなく,Castleを用いて汎用登録と原生のIoC容器の置き換えを実現する方法に焦点を当てる.
まず、ITransientDependencyの継承をプログラムセットで満たすと、実装クラスにTransientのライフサイクルとして登録され、ISingletonDependencyは実装クラスにSingletonのライフサイクルとして登録されます.
    /// 
    ///                    
    /// 
    public class BasicConventionalRegistrar
    {
        private readonly WindsorContainer _container = new WindsorContainer();

        /// 
        ///             
        /// 
        /// 
        /// 
        public WindsorContainer RegisterAssembly(List assemblies)
        {
            foreach (var assembly in assemblies)
            {
                //Transient
                _container.Register(
                    Classes.FromAssembly(assembly)
                           .IncludeNonPublicTypes()
                           .BasedOn()
                           .If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
                           .WithService.Self()
                           .WithService.DefaultInterfaces()
                           .LifestyleTransient()
                );

                //Singleton
                _container.Register(
                    Classes.FromAssembly(assembly)
                           .IncludeNonPublicTypes()
                           .BasedOn()
                           .If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
                           .WithService.Self()
                           .WithService.DefaultInterfaces()
                           .LifestyleSingleton()
                );
            }
            return _container;
        }
    }

使用方法   

  有个这个类,我们需要把各个程序集中满足条件的类注册进来,首先需要在NuGet下载Castle.Windsor.MsDependencyInjection包,并且在ConfigureServices方法中修改返回类型为IServiceProvider,然后通过RegistBasicConventionalRegistrar把各个需要注册的程序集注册进来。

  这里需要非常注意的是,在ASP.NET Core - 依赖注入这篇文章里面提到ConfigureServices是可以返回一个IServiceProvider对象的,这里是基于这个返回对象引入了第三方容器替换。

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    var container = RegistBasicConventionalRegistrar();
  
    //    
    return WindsorRegistrationHelper.CreateServiceProvider(container, services);
}

//      
private WindsorContainer RegistBasicConventionalRegistrar()
{
    var list = new List();
    list.Add(Assembly.GetExecutingAssembly ());
    list.Add(yourProjectAssembly);
    ...
    return BasicConventionalRegistrar.RegisterAssembly(list); 
}

プログラムセット別登録


上記のコードでは、WindsorRegistrationHelperというクラス実装を主に利用してWindsor Castleコンテナに登録し、コアメソッドRegistBasicConventionalRegistrarはプログラムセットに基づいて登録されていることがわかります.正式なアプリケーションシーンでは、複数のプログラムセットを約束通りに登録する必要がある可能性が高い.個人的には、登録する必要があるプログラムセットごとに、そのプログラムセットを示すベースクラスを追加することをお勧めします.例えば、サービスというプログラムセットにIServiceBaseインタフェースを追加し、typeof(IServiceBase)を通過することができます.Assemblyはこのプログラムセットを取得して登録します

約束どおり引き継ぐ


サービス・ビジネス・レイヤ(または登録が必要な場所)では、登録が必要なクラスを汎用登録インタフェース(ライフサイクル独自選択)に継承します.
public interface IPostBlogService : ITransientDependency
{
  Result Post(BlogDto dto); }
public class PostBlogService : IPostBlogService { public Result Post(BlogDto dto)
  {
    //todo: post this blog
  } }

インスタンス解析


任意の必要な場所で構造方法で注入(または属性注入)する
[ApiController]
[Route("api/
Blog")]
public
class BlogController: Controller { public readonly IBlogService _blogService; public BlogController(IBlogService blogService) { _blogService = blogService; }   [HttpPost] public Result PostBlog(BlogDto dto) { return _blogService.Post(dto); } }

これにより完全な汎用登録解析プロセスが実現され、実際の応用では、個人的にこれらの汎用解析方法をインフラモジュールに置くことを提案した.これは、本プロジェクトだけでなく、インフラストラクチャを抽出してインフラフレームワークとし、nugetによってバージョン制御を会社のすべてのプロジェクトの汎用登録基礎フレームワークとすることができるからである.
 
もしあなたがもっと良い考えやアドバイスがあれば、私に知らせてください.