ASP.NET Core - 利用Windsor Castle实现通用注册

  问题引入

  在ASP.NET Core - 依赖注入这篇文章里面,咱们知道了如何利用ASP.NET Core原生的容器来实现依赖注入的,那咱们为何要替换掉默认的 IoC容器呢?从ASP.NET Core - 依赖注入这篇文章来看的话,默认的IoC容器对于一些小型的项目基本够用,它提供了基本的AddXXXX方法来绑定实例关系,可是对于大型项目来讲,仍是挺困难的,大型的项目须要的是通用的注册,不可能手动添加每一个对象的解析关系,这才是咱们面临的痛点。html

  解决方案

  这里不打算详解Castle的内容,专一于如何使用Castle实现通用注册和替换掉原生的IoC容器。api

  首先咱们须要一个通用的注册类,是基于咱们自定义规则来注册的,好比说在程序集中知足继承ITransientDependency的话咱们会给实现类注册为Transient的生命周期,ISingletonDependency会给实现类注册为Singleton的生命周期。框架

    /// <summary>
    /// 经过输入的程序集来注册知足约定的全部类
    /// </summary>
    public class BasicConventionalRegistrar
    {
        private readonly WindsorContainer _container = new WindsorContainer();

        /// <summary>
        /// 注册程序集中知足约定的类
        /// </summary>
        /// <param name="assemblies"></param>
        /// <returns></returns>
        public WindsorContainer RegisterAssembly(List<Assembly> assemblies)
        {
            foreach (var assembly in assemblies)
            {
                //Transient
                _container.Register(
                    Classes.FromAssembly(assembly)
                           .IncludeNonPublicTypes()
                           .BasedOn<ITransientDependency>()
                           .If(type => !type.GetTypeInfo().IsGenericTypeDefinition)
                           .WithService.Self()
                           .WithService.DefaultInterfaces()
                           .LifestyleTransient()
                );

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

  如何使用?   

  有个这个类,咱们须要把各个程序集中知足条件的类注册进来,首先须要在NuGet下载Castle.Windsor.MsDependencyInjection包,而且在ConfigureServices方法中修改返回类型为IServiceProvider,而后经过RegistBasicConventionalRegistrar把各个须要注册的程序集注册进来。ide

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

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

    var container = RegistBasicConventionalRegistrar();
  
    //替换容器
    return WindsorRegistrationHelper.CreateServiceProvider(container, services);
}

//通用规则注册
private WindsorContainer RegistBasicConventionalRegistrar()
{
    var list = new List<Assembly>();
    list.Add(Assembly.GetExecutingAssembly ());
    list.Add(yourProjectAssembly);
    ...
    return BasicConventionalRegistrar.RegisterAssembly(list); 
}

  按程序集注册  

  上面的代码咱们能够看到,主要是利用了WindsorRegistrationHelper这个类实现注册到Windsor Castle容器中,且核心方法RegistBasicConventionalRegistrar是基于程序集注册的。在正式的应用场景中,咱们是很是可能须要把多个程序集都按约定来注册的,我的建议的作法是,在每一个须要注册的程序集中添加一个标志该程序集的基类,好比说我会在Service这个程序集中添加一个IServiceBase接口,这样就能够经过typeof(IServiceBase).Assembly获取到这个程序集进而用来注册this

  按约定进行继承

  在咱们的service业务层(或者任何须要注册的地方),把须要注册的类继承通用注册接口(生命周期本身选择)spa

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使用版本控制做为公司全部项目的通用注册础框架。code

 

  让我知道若是你有更好的想法或建议!htm

相关文章
相关标签/搜索