zoukankan      html  css  js  c++  java
  • NET Core3.1 用 Autofac 实现IOC容器

    一、IOC容器

    IOC(Inversion of Control,控制反转),他不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合,更优良的程序。

    DI(依赖注入)。IOC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。

    使用依赖注入,有以下优点:

    • 传统的代码,每个对象负责管理与自己需要依赖的对象,导致如果需要切换依赖对象的实现类时,需要修改多处地方。同时,过度耦合也使得对象难以进行单元测试。
    • 依赖注入把对象的创造交给外部去管理,很好的解决了代码紧耦合(tight couple)的问题,是一种让代码实现松耦合(loose couple)的机制。
    • 松耦合让代码更具灵活性,能更好地应对需求变动,以及方便单元测试。

    二、使用——Autofac

    1、引入nuget包

    在Nuget中引入两个:Autofac.Extras.DynamicProxy(Autofac的动态代理,它依赖Autofac,所以可以不用单独引入Autofac)、Autofac.Extensions.DependencyInjection(Autofac的扩展)

    2、在Startup类下面创建 ConfigureContainer 方法

    Core 3.0以上版本写法请注意和2.2是不一样的,完整代码如下

            public void ConfigureContainer(ContainerBuilder builder)
            {
                var basePath = Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath;
                //注册要通过反射创建的组件
                //builder.RegisterType<AdvertisementServices>().As<IAdvertisementServices>();
    
                #region 带有接口层的服务注入
    
           //项目引用接口, 服务层和仓储层的bin文件直接使用,实现解耦 var servicesDllFile = Path.Combine(basePath, "Blog.Core.Services.dll"); var repositoryDllFile = Path.Combine(basePath, "Blog.Core.Repository.dll"); if (!(File.Exists(servicesDllFile) && File.Exists(repositoryDllFile))) { throw new Exception("Repository.dll和service.dll 丢失,因为项目解耦了,所以需要先F6编译,再F5运行,请检查 bin 文件夹,并拷贝。"); } // AOP 开关,如果想要打开指定的功能,只需要在 appsettigns.json 对应对应 true 就行。 var cacheType = new List<Type>();// 获取 Service.dll 程序集服务,并注册 var assemblysServices = Assembly.LoadFrom(servicesDllFile); builder.RegisterAssemblyTypes(assemblysServices) .AsImplementedInterfaces() .InstancePerDependency() .EnableInterfaceInterceptors()//引用Autofac.Extras.DynamicProxy; .InterceptedBy(cacheType.ToArray());//允许将拦截器服务的列表分配给注册。 // 获取 Repository.dll 程序集服务,并注册 var assemblysRepository = Assembly.LoadFrom(repositoryDllFile); builder.RegisterAssemblyTypes(assemblysRepository) .AsImplementedInterfaces() .InstancePerDependency(); #endregion #region 没有接口层的服务层注入 //因为没有接口层,所以不能实现解耦,只能用 Load 方法。 //注意如果使用没有接口的服务,并想对其使用 AOP 拦截,就必须设置为虚方法 //var assemblysServicesNoInterfaces = Assembly.Load("Blog.Core.Services"); //builder.RegisterAssemblyTypes(assemblysServicesNoInterfaces); #endregion #region 没有接口的单独类 class 注入 //只能注入该类中的虚方法 builder.RegisterAssemblyTypes(Assembly.GetAssembly(typeof(Love))) .EnableClassInterceptors() .InterceptedBy(cacheType.ToArray()); #endregion }
    没有接口的单独类 class 注入,只能注入该类中的虚方法
        /// <summary>
        /// 这是爱
        /// </summary>
        public class Love
        {
         //虚方法
    public virtual string SayLoveU() { return "I ♥ U"; } }

    3、在program类下面build

    
    
    public static IHostBuilder CreateHostBuilder(string[] args) =>
       Host.CreateDefaultBuilder(args)
         .UseServiceProviderFactory(new AutofacServiceProviderFactory()) //<--NOTE THIS
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder
               .UseStartup<Startup>()
               .UseUrls("http://localhost:8081")
               .ConfigureLogging((hostingContext, builder) =>
               {
                   builder.ClearProviders();
                   builder.SetMinimumLevel(LogLevel.Trace);
                   builder.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                   builder.AddConsole();
                   builder.AddDebug();
               });
         });
    
    

    4、构造函数方式来注入

    依赖注入有三种方式(构造方法注入、setter方法注入和接口方式注入),我们平时基本都是使用其中的构造函数方式实现注入,
            
         //接口
         readonly IAdvertisementServices _advertisementServices; /// <summary> /// 构造函数 /// </summary> /// <param name="advertisementServices"></param> public BlogController(IAdvertisementServices advertisementServices) { _advertisementServices = advertisementServices; }     [HttpGet("{id}", Name = "Get")] public async Task<List<Advertisement>> Get(int id) { //IAdvertisementServices advertisementServices = new AdvertisementServices(); //不依赖注入是需要引用两个命名空间IServices层和Services层        //使用 return await _advertisementServices.Query(d => d.Id == id); }
    
    

    5、程序集注入 —— 实现层级引用的解耦

    这是一个学习的思路,大家要多想想,可能会感觉无聊或者没用,但是对理解项目启动和加载,还是很有必要的。

    1、项目最终只依赖抽象

    最终的效果是这样的:工程只依赖抽象,把两个实现层删掉,引用这两个接口层。

    2、配置仓储和服务层的程序集输出

    将 Blog.Repository 层和 Service 层项目生成地址改成相对路径,这样大家就不用手动拷贝这两个 dll 了,F6编译的时候就直接生成到了 api 层 bin 下了:


    “..Blog.CoreinDebug”

     好了,项目启动就可以运行了


    常见错误:

    经常会遇到一个错误:None of the constructors found with ........,

    查看你的service服务,是不是用了其他的仓储repository,但是又缺少了构造函数。

     参考自:https://www.cnblogs.com/laozhang-is-phi/p/9541414.html
    如果写的不明白可以看看大神原文,我是在跟着大神学习的,下节学习AOP切面
  • 相关阅读:
    BZOJ 1103 Poi2007 大都市meg
    BZOJ 2815 ZJOI2012 灾难
    【bzoj】1046: [HAOI2007]上升序列
    P1168跳房子(焫鷄如我)
    HAIO2017[打酱油的旅行!?]
    [haoi2013]花卉节
    P1298(矩阵切割)DP
    P1216 (list加强版)
    p1219最佳贸易(两边bfs写的)
    p1150[noip2013普及]表达式求值
  • 原文地址:https://www.cnblogs.com/shuaichao/p/12386855.html
Copyright © 2011-2022 走看看