zoukankan      html  css  js  c++  java
  • .Net Core 3.x Api开发笔记 -- IOC,使用Autofac实现依赖注入(三)

    本节演示在 .net Core ApI项目中引入 Autofac 容器

    项目前提条件:

    .net Core ApI项目

    服务层--Service层

    仓储层--Repository层

    。。

    第一步:安装 NuGet 相关包,安装如下两个Autofac 包即可,目前版本 Autofac 6.0

    第二步: 注册

    Program.cs 文件中需要加入一句话:.UseServiceProviderFactory(new AutofacServiceProviderFactory())

            /// <summary>
            /// 默认初始化系统内置的配置
            /// </summary>
            /// <param name="args"></param>
            /// <returns></returns>
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .UseServiceProviderFactory(new AutofacServiceProviderFactory())   //autofac 依赖注入
                    .ConfigureWebHostDefaults(webBuilder =>
                    {
                        webBuilder.UseStartup<Startup>();
                    });

    Startup.cs 文件中加入如下方法,固定写法,方法内容暂时先空着,下边继续。。。

            /// <summary>
            /// Autofac引用
            /// </summary>
            /// <param name="builder"></param>
            public void ConfigureContainer(ContainerBuilder builder)
            {
                //注册逻辑
            }

    到这里,配置操作基本上结束了,接下来根据业务具体操作!

    业务场景:假如有一个通知系统,具体业务就是公司老板通过电话系统通知手下都需要干什么事情!

    在服务层 MyShop.Services 创建一个通知接口,并且实现该接口:

        public interface IMessageNotice
        {
            string Send(string arg);  //发送通知
        }
    
    
        /// <summary>
        /// 实现类1 电话通知
        /// </summary>
        public class MobileNotice : IMessageNotice
        {
            public string Send(string arg)
            {
                return $"电话通知系统,通知内容:{arg}";
            }
        }

    在 Startup.cs 文件中注册上边接口,builder.RegisterType<MobileNotice>().As<IMessageNotice>()

            /// <summary>
            /// Autofac引用
            /// </summary>
            /// <param name="builder"></param>
            public void ConfigureContainer(ContainerBuilder builder)
            {
                //单个注册
                builder.RegisterType<MobileNotice>().As<IMessageNotice>();
            }

    在控制器Controller中注入 IMessageNotice接口

        public class NoticeController : ControllerBase
        {
            private readonly IMessageNotice messageNotice;
    
            public NoticeController(IMessageNotice _messageNotice)
            {
                messageNotice = _messageNotice;
            }
    
    
            /// <summary>
            /// 电话通知
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            public async Task<IActionResult> MobileNotice()
            {
                string content = "下午不用上班";
                var result = await messageNotice.Send(content);
                return Ok(result);
            }
    
        }

    然后运行测试:

    假如:现在业务需求变了,老板说了,现在互联网时代,电话沟通已经不是唯一的工具了,还要系统可以通过微信沟通,同时以前的电话通知也要支持!

    很简单,再写个微信通知类,实现通知接口: IMessageNotice

     1     /// <summary>
     2     /// 微信通知
     3     /// </summary>
     4     public class WebChatNotice : IMessageNotice
     5     {
     6         //普通发送
     7         public string Send(string arg)
     8         {
     9             return  $"微信通知系统,通知内容:{arg}";
    10         }
    11 
    12         //异步发送
    13         public Task<string> SendAsync(string arg)
    14         {
    15             return Task.Run(() => { return $"微信通知系统,通知内容:{arg}"; });
    16         }
    17 
    18     }

    同时在 Startup 中注册微信接口

            /// <summary>
            /// Autofac引用
            /// </summary>
            /// <param name="builder"></param>
            public void ConfigureContainer(ContainerBuilder builder)
            {
                //注册电话接口
                builder.RegisterType<MobileNotice>().As<IMessageNotice>();
    
                //注册微信接口
                builder.RegisterType<WebChatNotice>().As<IMessageNotice>();
    
            }

    再次运行,发现电话通知变成微信通知了!但是电话通知却没有了,这是因为上边 微信接口注册时,自动把电话接口注册覆盖了!

    老板的要求是同时支持电话通知和微信通知,现在明显不符合需求,那就继续改!

    修改注册类,使用 Named<T>方法区分不同的实现类

            /// <summary>
            /// Autofac引用
            /// </summary>
            /// <param name="builder"></param>
            public void ConfigureContainer(ContainerBuilder builder)
            {
                //注册电话接口
                builder.RegisterType<MobileNotice>().Named<IMessageNotice>("mobile");
    
                //注册微信接口
                builder.RegisterType<WebChatNotice>().Named<IMessageNotice>("webchat");
    
            }

    然后新建个Manager文件夹,添加一个通知管理类:NoticeManager,使用Autofac内置接口 ILifetimeScope 来实现接口调用

        /// <summary>
        /// 通知管理类
        /// </summary>
        public class NoticeManager
        {
            //ILifetimeScope 是Autofac内置类
            private readonly ILifetimeScope messageNotice;
    
            public NoticeManager(ILifetimeScope _messageNotice)
            {
                messageNotice = _messageNotice ?? throw new ArgumentNullException(nameof(_messageNotice));
            }
    
    
            //发送通知
            public List<string> SendNotice(string arg)
            {
                var list = new List<string>();
    
                //使用 ResolveNamed<T>方法区分
                var mobile = messageNotice.ResolveNamed<IMessageNotice>("mobile");   //电话通知
                var webchat = messageNotice.ResolveNamed<IMessageNotice>("webchat");   //微信通知
    
                list.Add(mobile.Send(arg));   //调用发送电话通知
                list.Add(webchat.Send(arg));  //调用发送微信通知
    
                return list;
            }
        }

    同时在 Startup.cs 中注册 NoticeManager 类,自己注册自己,相当于new了一个实例

    然后在控制器Controller里,通过构造方法注入通知管理类 NoticeManager

            private readonly NoticeManager messageNotice;
            public NoticeController(NoticeManager _messageNotice)
            {
                messageNotice = _messageNotice;
            }
    
            /// <summary>
            /// 通知
            /// </summary>
            /// <returns></returns>
            [HttpGet]
            public async Task<IActionResult> MobileNotice()
            {
                string content = "下午不用来上班";
                var getlist = await Task.Run(() => { return messageNotice.SendNotice(content); });
                return Ok(getlist);
            }

    现在再次运行,已经按照老板的需求同时支持电话和微信通知了!

    第三步:批量注册

    使用 RegisterAssemblyTypes 方法可以按照程序集实现批量注册,好处就不多说了!

    批量注册和单个类型注册不冲突,可以同时存在!

            /// <summary>
            /// Autofac引用
            /// </summary>
            /// <param name="builder"></param>
            public void ConfigureContainer(ContainerBuilder builder)
            {
                //注册电话接口
                builder.RegisterType<MobileNotice>().Named<IMessageNotice>("mobile");
    
                //注册微信接口
                builder.RegisterType<WebChatNotice>().Named<IMessageNotice>("webchat");
    
                //注册管理类 自己注册自己
                //builder.RegisterType<NoticeManager>();
    
                //批量注册程序集 没有接口,并且以Manager结尾的类,可以代替上边的 NoticeManager类注册
                var myshopapibll = Assembly.Load("MyShopApi");
                builder.RegisterAssemblyTypes(myshopapibll)
                .Where(t=>t.Name.EndsWith("Manager"));
    
    
                //批量注册程序集  有接口
                var basedir = AppContext.BaseDirectory;
                var bllservice = Path.Combine(basedir, "MyShop.Services.dll");
                if (!File.Exists(bllservice))
                {
                    var msg = "MyShop.Services.dll不存在";
                    throw new Exception(msg);
                }
                var assemblysServices = Assembly.LoadFrom(bllservice);  //Assembly.Load("MyShop.Services");
                builder.RegisterAssemblyTypes(assemblysServices)   //多个程序集用逗号","分割
                .AsImplementedInterfaces()   //批量关联,让所有注册类型自动与其继承的接口进行关联
                .InstancePerDependency();    //瞬时模式
            }

    批量注册类型,当一个接口存在多个实现类时,如果不用 Named<T> 方法区分,也可以使用 IEnumerable<T> 方式注入构造函数获取实例,两者效果相同,如下标红部分:

        public class NoticeManager
        {
            private readonly ILifetimeScope lifetimeScope;                //ILifetimeScope 是Autofac内置类
            private readonly IEnumerable<IMessageNotice> messageNotices;  //使用IEnumerable<IMessageNotice>格式注入
            public NoticeManager(ILifetimeScope _lifetimeScope, IEnumerable<IMessageNotice> _messageNotices)
            {
                lifetimeScope = _lifetimeScope ?? throw new ArgumentNullException(nameof(_lifetimeScope));
                messageNotices = _messageNotices ?? throw new ArgumentNullException(nameof(_messageNotices));
            }
    
    
            //发送通知
            public List<string> SendNotice(string arg)
            {
                var list = new List<string>();
    
                //方式1:使用 ResolveNamed<T>方法区分
                //var mobile = lifetimeScope.ResolveNamed<IMessageNotice>("mobile");   //电话通知
                //var webchat = lifetimeScope.ResolveNamed<IMessageNotice>("webchat");   //微信通知
    
    
                //方式2 使用IEnumerable<IMessageNotice> 获取实例,效果和 Named<T> 注册相同
                var mobile = messageNotices.Where(t=>t.GetType()==typeof(MobileNotice)).FirstOrDefault();   //电话通知
                var webchat = messageNotices.Where(t => t.GetType() == typeof(WebChatNotice)).FirstOrDefault();   //微信通知
    
                list.Add(mobile.Send(arg));   //发送电话通知
                list.Add(webchat.Send(arg));  //发送微信通知
    
                return list;
            }
        }

    测试结果跟上边一样

    第四步:扩展 

    为了使代码显的更整洁,可以对 Autofac注册内容进行封装!

    新建一个扩展文件夹:Extensions,然后在里边新建一个扩展类:AutofacExtension 并继承 Autofac.Module,然后把 Startup.cs 中Autofac的注册内容剪切过来!

     1     public class AutofacExtension : Autofac.Module
     2     {
     3         //重写Load函数
     4         protected override void Load(ContainerBuilder builder)
     5         {
     6             //注册电话接口
     7             builder.RegisterType<MobileNotice>().Named<IMessageNotice>("mobile");
     8 
     9             //注册微信接口
    10             builder.RegisterType<WebChatNotice>().Named<IMessageNotice>("webchat");
    11 
    12             //注册管理类 自己注册自己
    13             //builder.RegisterType<NoticeManager>();
    14 
    15             //批量注册程序集 没有接口,并且以Manager结尾的类,可以代替上边的 NoticeManager类注册
    16             var myshopapibll = Assembly.Load("MyShopApi");
    17             builder.RegisterAssemblyTypes(myshopapibll)
    18             .Where(t => t.Name.EndsWith("Manager"));
    19 
    20 
    21             //批量注册程序集  有接口
    22             var basedir = AppContext.BaseDirectory;
    23             var bllservice = Path.Combine(basedir, "MyShop.Services.dll");
    24             if (!File.Exists(bllservice))
    25             {
    26                 var msg = "MyShop.Services.dll不存在";
    27                 throw new Exception(msg);
    28             }
    29             var assemblysServices = Assembly.LoadFrom(bllservice);  //Assembly.Load("MyShop.Services");
    30             builder.RegisterAssemblyTypes(assemblysServices)   //多个程序集用逗号","分割
    31             .AsImplementedInterfaces()   //批量关联,让所有注册类型自动与其继承的接口进行关联
    32             .InstancePerDependency();    //瞬时模式
    33         }
    34     }

    同时修改 Startup 文件中的内容如下:

    1         /// <summary>
    2         /// Autofac引用
    3         /// </summary>
    4         /// <param name="builder"></param>
    5         public void ConfigureContainer(ContainerBuilder builder)
    6         {
    7             builder.RegisterModule(new AutofacExtension());
    8         }

    这里只是记录常用的一部分,还有很多扩展没有记录,比如实现AOP等,以后再慢慢补充吧! 到此结束!

  • 相关阅读:
    Python常用第三方库总结
    Python爬虫技术--入门篇--爬虫介绍
    X sql解惑 25 里程碑问题 答案
    X sql解惑 34 咨询顾问收入问题
    从小变大的照片
    获取属性的顺序
    for...in
    判断元素是否存在
    自由的元素名称
    ES6语法糖-简洁属性表示
  • 原文地址:https://www.cnblogs.com/peterzhang123/p/14004134.html
Copyright © 2011-2022 走看看