请选择 进入手机版 | 继续访问电脑版

马上加入IBC程序猿 各种源码随意下,各种教程随便看! 注册 每日签到 加入编程讨论群

C#教程 ASP.NET教程 C#视频教程程序源码享受不尽 C#问题入口 ASP.NET问题入口

【C#问题提交】 社群合作 申请版主 程序开发 【远程协助】 每天乐一乐 每日签到 【承接毕业设计】 面试-葵花宝典下载

官方一群:

官方二群:

查看: 82|回复: 0

ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用

[复制链接]
  • TA的每日心情
    开心
    前天 19:06
  • 签到天数: 1469 天

    [LV.10]以坛为家III

    1177

    主题

    3082

    帖子

    9万

    积分

    管理员

    IBC编程社区-原道楠

    Rank: 9Rank: 9Rank: 9

    积分
    94058

    推广达人突出贡献优秀版主荣誉管理论坛元老

    发表于 2019-8-13 19:00:25 | 显示全部楼层 |阅读模式

    马上加入IBC,查看更多教程

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x

    话不多说,直入主题看我们的解决方案结构:

    190035pdwqddzlaosocads.png

    分别对上面的工程进行简单的说明:

    1、TianYa.DotNetShare.Model:为demo的实体层

    2、TianYa.DotNetShare.Repository:为demo的仓储层即数据访问层

    3、TianYa.DotNetShare.Service:为demo的服务层即业务逻辑层

    4、TianYa.DotNetShare.MvcDemo:为demo的web层项目,MVC框架

    约定:本demo的web项目为ASP.NET Web 应用程序(.NET Framework 4.5) MVC框架,实体层、仓储层、服务层均为.NET Framework 4.5 类库。

    一、实体层

    190035jsjb3esimjj39qpz.png

    1、定义一个空接口IDependency,后面有妙用,用于一次性注入

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. namespace TianYa.DotNetShare.Model
    7. {
    8. /// <summary>
    9. /// 空接口,用于一次性注入
    10. /// </summary>
    11. public interface IDependency
    12. {
    13. }
    14. }
    复制代码

    2、新建一个学生实体 Student

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. namespace TianYa.DotNetShare.Model
    7. {
    8. /// <summary>
    9. /// 学生类
    10. /// </summary>
    11. public class Student
    12. {
    13. /// <summary>
    14. /// 学号
    15. /// </summary>
    16. public string StuNo { get; set; }
    17. /// <summary>
    18. /// 姓名
    19. /// </summary>
    20. public string Name { get; set; }
    21. /// <summary>
    22. /// 年龄
    23. /// </summary>
    24. public int Age { get; set; }
    25. /// <summary>
    26. /// 性别
    27. /// </summary>
    28. public string Sex { get; set; }
    29. }
    30. }
    复制代码

    demo中的实体就这样了

    二、仓储层

    190035rk8yx9a6bz6tta9c.png

    本demo的仓储层必要引用我们的实体层TianYa.DotNetShare.Model

    为什么选择用仓储,原因很简单,方便我们进行个性化扩展。在数据操作的底层进行其他个性化逻辑处理。

    约定:

    1、接口的定义放在根目录下,接口的实现类,同一放到Impl文件夹,表示实现类目录。

    2、每个实体,对应一个仓储的接口和实现类,即有多少个实体,就对应创建多少个接口和实现类。

    我们新建一个Student的仓储接口 IStudentRepository.cs

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using TianYa.DotNetShare.Model;
    7. namespace TianYa.DotNetShare.Repository
    8. {
    9. /// <summary>
    10. /// 学生类仓储层接口
    11. /// </summary>
    12. public interface IStudentRepository
    13. {
    14. /// <summary>
    15. /// 根据学号获取学生信息
    16. /// </summary>
    17. /// <param name="stuNo">学号</param>
    18. /// <returns>学生信息</returns>
    19. Student GetStuInfo(string stuNo);
    20. }
    21. }
    复制代码

    接着在Impl中新建一个Student的仓储实现StudentRepository.cs

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using TianYa.DotNetShare.Model;
    7. namespace TianYa.DotNetShare.Repository.Impl
    8. {
    9. /// <summary>
    10. /// 学生类仓储层
    11. /// </summary>
    12. public class StudentRepository : IStudentRepository, IDependency
    13. {
    14. /// <summary>
    15. /// 根据学号获取学生信息
    16. /// </summary>
    17. /// <param name="stuNo">学号</param>
    18. /// <returns>学生信息</returns>
    19. public Student GetStuInfo(string stuNo)
    20. {
    21. //数据访问逻辑,此处为了演示就简单些
    22. var student = new Student();
    23. switch (stuNo)
    24. {
    25. case "10000":
    26. student = new Student() { StuNo = "10000", Name = "张三", Sex = "男", Age = 20 };
    27. break;
    28. case "10001":
    29. student = new Student() { StuNo = "10001", Name = "钱七七", Sex = "女", Age = 18 };
    30. break;
    31. case "10002":
    32. student = new Student() { StuNo = "10002", Name = "李四", Sex = "男", Age = 21 };
    33. break;
    34. default:
    35. student = new Student() { StuNo = "10003", Name = "王五", Sex = "男", Age = 25 };
    36. break;
    37. }
    38. return student;
    39. }
    40. }
    41. }
    复制代码

    该类同时实现了IStudentRepository接口和IDependency接口,其中实现IDependency接口的目的是为了后面的web端进行一次性注入

    三、服务层

    190036rwk04a1a70ukuiy7.png

    本demo的服务层必要引用我们的实体层TianYa.DotNetShare.Model和我们的仓储层TianYa.DotNetShare.Repository

    服务层与仓储层雷同,它属于仓储层的使用者。定义的方式也与仓储层雷同,有接口和Impl实现目录。

    但服务层不必要一个实体对应一个,服务层更多的是按照功能模块进行划分,比如一个登录模块,创建一个LoginService。

    为了演示,我们新建一个Student的服务层接口IStudentService.cs

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using TianYa.DotNetShare.Model;
    7. namespace TianYa.DotNetShare.Service
    8. {
    9. /// <summary>
    10. /// 学生类服务层接口
    11. /// </summary>
    12. public interface IStudentService
    13. {
    14. /// <summary>
    15. /// 根据学号获取学生信息
    16. /// </summary>
    17. /// <param name="stuNo">学号</param>
    18. /// <returns>学生信息</returns>
    19. Student GetStuInfo(string stuNo);
    20. }
    21. }
    复制代码

    接着我们同样在Impl中新建一个Student的服务层实现StudentService.cs

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Text;
    5. using System.Threading.Tasks;
    6. using TianYa.DotNetShare.Model;
    7. using TianYa.DotNetShare.Repository;
    8. namespace TianYa.DotNetShare.Service.Impl
    9. {
    10. /// <summary>
    11. /// 学生类服务层
    12. /// </summary>
    13. public class StudentService : IStudentService, IDependency
    14. {
    15. /// <summary>
    16. /// 定义仓储层学生抽象类对象
    17. /// </summary>
    18. protected IStudentRepository StuRepository;
    19. /// <summary>
    20. /// 空构造函数
    21. /// </summary>
    22. public StudentService() { }
    23. /// <summary>
    24. /// 构造函数
    25. /// </summary>
    26. /// <param name="stuRepository">仓储层学生抽象类对象</param>
    27. public StudentService(IStudentRepository stuRepository)
    28. {
    29. this.StuRepository = stuRepository;
    30. }
    31. /// <summary>
    32. /// 根据学号获取学生信息
    33. /// </summary>
    34. /// <param name="stuNo">学号</param>
    35. /// <returns>学生信息</returns>
    36. public Student GetStuInfo(string stuNo)
    37. {
    38. var stu = StuRepository.GetStuInfo(stuNo);
    39. return stu;
    40. }
    41. }
    42. }
    复制代码

    该类同时实现了IStudentService接口和IDependency接口,其中实现IDependency接口的目的是为了后面的web端进行一次性注入

    四、Web层

    190036it7j8wetsjekzxec.png

    本demo的web项目必要引用以下几个程序集:

    1、TianYa.DotNetShare.Model 我们的实体层

    2、TianYa.DotNetShare.Service 我们的服务层

    3、TianYa.DotNetShare.Repository 我们的仓储层,正常我们的web项目是不应该使用仓储层的,此处我们引用是为了演示IOC依赖注入

    4、Autofac 依赖注入基础组件

    5、Autofac.Mvc5 依赖注入Mvc5的辅助组件

    其中Autofac和Autofac.Mvc5可以从我们的NuGet上引用:

    190037cesu8suz7ewduu2e.png

    如果从线下已安装的程序包源中找不到我们要的程序集,可以尝试添加我们的程序包源,具体步骤如下:

    190037un0t80nn3o18c6u7.png

    190038mgysyesdg8v4xe4g.png

    1. 名称:nuget.org
    2. 源:https://api.nuget.org/v3/index.json
    复制代码

    添加新的包源后点击确定(如果已经有此包源就忽略该步骤),接下来就从NuGet上安装我们必要的程序集。

    190038mtzntn1g9t92s7s5.png

    依次点击下载以下2个组件

    190038iuzjvg0vbvvrqh70.png

    到了这里我们全部的工作都已经准备好了,接下来就是重头戏,开始做注入工作了。

    打开我们的Global.asax文件进行注入工作

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using System.Web;
    5. using System.Web.Mvc;
    6. using System.Web.Optimization;
    7. using System.Web.Routing;
    8. using Autofac;
    9. using Autofac.Integration.Mvc;
    10. using TianYa.DotNetShare.Model;
    11. using TianYa.DotNetShare.Repository.Impl;
    12. using TianYa.DotNetShare.Repository;
    13. namespace TianYa.DotNetShare.MvcDemo
    14. {
    15. public class MvcApplication : System.Web.HttpApplication
    16. {
    17. protected void Application_Start()
    18. {
    19. AreaRegistration.RegisterAllAreas();
    20. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    21. RouteConfig.RegisterRoutes(RouteTable.Routes);
    22. BundleConfig.RegisterBundles(BundleTable.Bundles);
    23. AutofacRegister(); //Autofac依赖注入
    24. }
    25. /// <summary>
    26. /// Autofac依赖注入
    27. /// </summary>
    28. private void AutofacRegister()
    29. {
    30. var builder = new ContainerBuilder();
    31. //注册MVC控制器(注册全部到控制器,控制器注入,就是必要在控制器的构造函数中接收对象)
    32. builder.RegisterControllers(typeof(MvcApplication).Assembly);
    33. //构造函数注入,对StudentRepository与接口进行注入
    34. builder.RegisterType<StudentRepository>().As<IStudentRepository>();
    35. //设置依赖解析器
    36. var container = builder.Build();
    37. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    38. }
    39. }
    40. }
    复制代码

    至此,我们就完成了依赖注入工作,此方式为构造函数注入,接下来我们来看看控制器内里怎么弄:

    1. using System.Web.Mvc;
    2. using TianYa.DotNetShare.Repository;
    3. namespace TianYa.DotNetShare.MvcDemo.Controllers
    4. {
    5. public class HomeController : Controller
    6. {
    7. /// <summary>
    8. /// 定义仓储层学生抽象类对象
    9. /// </summary>
    10. protected IStudentRepository StuRepository;
    11. /// <summary>
    12. /// 通过构造函数进行注入
    13. /// 注意:参数是抽象类,而非实现类,因为已经在Global.asax中将实现类映射给了抽象类
    14. /// </summary>
    15. /// <param name="stuRepository">仓储层学生抽象类对象</param>
    16. public HomeController(IStudentRepository stuRepository)
    17. {
    18. this.StuRepository = stuRepository;
    19. }
    20. public ActionResult Index()
    21. {
    22. var stu = StuRepository.GetStuInfo("10000");
    23. string msg = $"学号:10000,姓名:{stu.Name},性别:{stu.Sex},年龄:{stu.Age}。";
    24. return Content(msg);
    25. }
    26. }
    27. }
    复制代码

    至此,完成处理,接下来就是见证奇迹的时刻了,我们访问 /home/index,看看是否能返回学生信息。

    190039zzn1cuvv1kpcb7jj.png

    我们可以发现,返回了学生的信息,说明我们注入成功了。

    总结:

    1、采用的是构造函数注入的方式,在构造函数中初始化赋值。

    2、StuRepository对象不必要实例化,即不必要new,降低了系统资源的消耗。

    3、必要在Global.asax中对StudentRepository写映射,如果仓储类比较多的时候,就必要写很多了,如何避免,这个在后面的篇幅中会讲解到。

    扩展: 上面讲解了构造函数注入的方式,下面扩展属性注入的方式,在Global.asax中稍微修改下注入语句即可。

    将:

    1. builder.RegisterControllers(typeof(MvcApplication).Assembly);
    复制代码

    改为:

    1. builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
    复制代码

    PropertiesAutowired:表示答应属性注入。

    接下来我们来看下怎么使用,修改下我们的依赖注入语句,新增服务层学生类注入:

    1. /// <summary>
    2. /// Autofac依赖注入
    3. /// </summary>
    4. private void AutofacRegister()
    5. {
    6. var builder = new ContainerBuilder();
    7. //注册MVC控制器(注册全部到控制器,控制器注入,就是必要在控制器的构造函数中接收对象)
    8. builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
    9. //构造函数注入,对StudentRepository与接口进行注入
    10. builder.RegisterType<StudentRepository>().As<IStudentRepository>();
    11. builder.RegisterType<StudentService>().As<IStudentService>();
    12. //设置依赖解析器
    13. var container = builder.Build();
    14. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    15. }
    复制代码

    修改我们的控制器代码:

    1. using System.Web.Mvc;
    2. using TianYa.DotNetShare.Service;
    3. namespace TianYa.DotNetShare.MvcDemo.Controllers
    4. {
    5. public class HomeController : Controller
    6. {
    7. /// <summary>
    8. /// 通过属性注入,访问修饰符必须为public,否则会注入失败
    9. /// </summary>
    10. public IStudentService StuService { get; set; }
    11. public ActionResult Index()
    12. {
    13. var stu = StuService.GetStuInfo("10001");
    14. string msg = $"学号:10001,姓名:{stu.Name},性别:{stu.Sex},年龄:{stu.Age}。";
    15. return Content(msg);
    16. }
    17. }
    18. }
    复制代码

    再访问一下我们的/home/index

    190040gkctorrymv5r7y0v.png

    我们可以发现,返回了学习信息,说明我们注入成功了。

    另外通过这个例子我们可以发现在注入仓储层对象StudentRepository时,不仅控制器中注入成功了,而且在服务层中也注入成功了,说明我们的Autofac的注入是全局的。

    总结:

    1、通过属性注入,访问修饰符必须为public,否则会注入失败。

    2、Autofac的注入是全局的。

    扩展:以上例子我们都是将实现类映射给对应的实现类接口,那能不能直接注入实现类呢,答案是可以的。

    修改下我们的依赖注入,新增我们的实现类注入语句:

    1. /// <summary>
    2. /// Autofac依赖注入
    3. /// </summary>
    4. private void AutofacRegister()
    5. {
    6. var builder = new ContainerBuilder();
    7. //注册MVC控制器(注册全部到控制器,控制器注入,就是必要在控制器的构造函数中接收对象)
    8. builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
    9. //构造函数注入,对StudentRepository与接口进行注入
    10. builder.RegisterType<StudentRepository>().As<IStudentRepository>(); //实现类映射给接口
    11. builder.RegisterType<StudentService>().As<IStudentService>();
    12. builder.RegisterType<StudentRepository>(); //实现类注入
    13. //设置依赖解析器
    14. var container = builder.Build();
    15. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    16. }
    复制代码

    再来看下我们的控制器

    1. using System.Web.Mvc;
    2. using TianYa.DotNetShare.Repository.Impl;
    3. namespace TianYa.DotNetShare.MvcDemo.Controllers
    4. {
    5. public class HomeController : Controller
    6. {
    7. /// <summary>
    8. /// 定义仓储层学生实现类对象
    9. /// </summary>
    10. public StudentRepository StuRepositoryImpl { get; set; }
    11. public ActionResult Index()
    12. {
    13. var stu = StuRepositoryImpl.GetStuInfo("10002");
    14. string msg = $"学号:10002,姓名:{stu.Name},性别:{stu.Sex},年龄:{stu.Age}";
    15. return Content(msg);
    16. }
    17. }
    18. }
    复制代码

    再访问一下我们的/home/index

    190040nmlf1jocbztx4fpl.png

    可以看出已经实现了我们具体的实现类注入

    到了这里,大家可能会发现在我们的Global.asax文件中,全部仓储层、服务层的类都必要一个个注册,那如果很多类的话,那可就写老长了,那有什么解决方法吗,答案是肯定的。Autofac还提供了其他方式注入,下面就介绍下我们的解决办法。

    还记得我们上面介绍仓储层和服务层实现类的时候都实现了我们的IDependency接口吗,接下来就派上大用场了,我们可以一次性注册全部实现了IDependency接口的类。

    修改一下我们的依赖注入方式来实现一次性注入:

    1. using System;
    2. using System.Linq;
    3. using System.Web.Mvc;
    4. using System.Web.Optimization;
    5. using System.Web.Routing;
    6. using System.Reflection;
    7. using System.IO;
    8. using Autofac;
    9. using Autofac.Integration.Mvc;
    10. using TianYa.DotNetShare.Model;
    11. namespace TianYa.DotNetShare.MvcDemo
    12. {
    13. public class MvcApplication : System.Web.HttpApplication
    14. {
    15. protected void Application_Start()
    16. {
    17. AreaRegistration.RegisterAllAreas();
    18. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    19. RouteConfig.RegisterRoutes(RouteTable.Routes);
    20. BundleConfig.RegisterBundles(BundleTable.Bundles);
    21. AutofacRegister(); //Autofac依赖注入
    22. }
    23. /// <summary>
    24. /// Autofac依赖注入
    25. /// </summary>
    26. private void AutofacRegister()
    27. {
    28. var builder = new ContainerBuilder();
    29. //注册MVC控制器(注册全部到控制器,控制器注入,就是必要在控制器的构造函数中接收对象)
    30. //PropertiesAutowired:答应属性注入
    31. builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
    32. //一次性注册全部实现了IDependency接口的类
    33. Type baseType = typeof(IDependency);
    34. Assembly[] assemblies =
    35. Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath, "*.dll").Select(Assembly.LoadFrom).ToArray();
    36. builder.RegisterAssemblyTypes(assemblies)
    37. .Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
    38. .AsSelf().AsImplementedInterfaces()
    39. .PropertiesAutowired().InstancePerLifetimeScope();
    40. //设置依赖解析器
    41. var container = builder.Build();
    42. DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    43. }
    44. }
    45. }
    复制代码

    最后再来看下我们的控制器

    1. using System.Web.Mvc;
    2. using TianYa.DotNetShare.Service;
    3. using TianYa.DotNetShare.Repository;
    4. using TianYa.DotNetShare.Repository.Impl;
    5. namespace TianYa.DotNetShare.MvcDemo.Controllers
    6. {
    7. public class HomeController : Controller
    8. {
    9. /// <summary>
    10. /// 定义仓储层学生实现类对象
    11. /// </summary>
    12. public StudentRepository StuRepositoryImpl { get; set; }
    13. /// <summary>
    14. /// 定义仓储层学生抽象类对象
    15. /// </summary>
    16. protected IStudentRepository StuRepository;
    17. /// <summary>
    18. /// 通过属性注入,访问修饰符必须为public,否则会注入失败
    19. /// </summary>
    20. public IStudentService StuService { get; set; }
    21. /// <summary>
    22. /// 通过构造函数进行注入
    23. /// 注意:参数是抽象类,而非实现类,因为已经在Global.asax中将实现类映射给了抽象类
    24. /// </summary>
    25. /// <param name="stuRepository">仓储层学生抽象类对象</param>
    26. public HomeController(IStudentRepository stuRepository)
    27. {
    28. this.StuRepository = stuRepository;
    29. }
    30. public ActionResult Index()
    31. {
    32. var stu1 = StuRepository.GetStuInfo("10000");
    33. var stu2 = StuService.GetStuInfo("10001");
    34. var stu3 = StuRepositoryImpl.GetStuInfo("10002");
    35. string msg = $"学号:10000,姓名:{stu1.Name},性别:{stu1.Sex},年龄:{stu1.Age}<br />";
    36. msg += $"学号:10001,姓名:{stu2.Name},性别:{stu2.Sex},年龄:{stu2.Age}<br />";
    37. msg += $"学号:10002,姓名:{stu3.Name},性别:{stu3.Sex},年龄:{stu3.Age}";
    38. return Content(msg);
    39. }
    40. }
    41. }
    复制代码

    再次访问一下我们的/home/index

    190040l1gcz1gw445scgzt.png

    可以看出成功返回了学生信息,说明我们的一次性注入成功了。

    至此我们就介绍完了Autofac依赖注入在MVC中的具体使用,下一章我们将继续简单的介绍下Autofac在普通的WebForm当中的使用。

    demo源码:

    1. 链接:https://pan.baidu.com/s/1jUbf1pk2-bSybf9OfUh8Tw
    2. 提取码:24ki
    复制代码

    参考博文:https://www.cnblogs.com/fei686868/p/10979790.html

    版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!


    来源:https://www.cnblogs.com/xyh9039/p/11318247.html
    免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则