ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用
话不多说,直入主题看我们的解决方案结构:

分别对上面的工程进行简单的说明:
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 类库。
一、实体层

1、定义一个空接口IDependency,后面有妙用,用于一次性注入
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace TianYa.DotNetShare.Model
{
/// <summary>
/// 空接口,用于一次性注入
/// </summary>
public interface IDependency
{
}
}
2、新建一个学生实体 Student
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace TianYa.DotNetShare.Model
{
/// <summary>
/// 学生类
/// </summary>
public class Student
{
/// <summary>
/// 学号
/// </summary>
public string StuNo { get; set; } /// <summary>
/// 姓名
/// </summary>
public string Name { get; set; } /// <summary>
/// 年龄
/// </summary>
public int Age { get; set; } /// <summary>
/// 性别
/// </summary>
public string Sex { get; set; }
}
}
demo中的实体就这样了
二、仓储层

本demo的仓储层需要引用我们的实体层TianYa.DotNetShare.Model
为什么选择用仓储,原因很简单,方便我们进行个性化扩展。在数据操作的底层进行其他个性化逻辑处理。
约定:
1、接口的定义放在根目录下,接口的实现类,统一放到Impl文件夹,表示实现类目录。
2、每个实体,对应一个仓储的接口和实现类,即有多少个实体,就对应创建多少个接口和实现类。
我们新建一个Student的仓储接口 IStudentRepository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Repository
{
/// <summary>
/// 学生类仓储层接口
/// </summary>
public interface IStudentRepository
{
/// <summary>
/// 根据学号获取学生信息
/// </summary>
/// <param name="stuNo">学号</param>
/// <returns>学生信息</returns>
Student GetStuInfo(string stuNo);
}
}
接着在Impl中新建一个Student的仓储实现StudentRepository.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Repository.Impl
{
/// <summary>
/// 学生类仓储层
/// </summary>
public class StudentRepository : IStudentRepository, IDependency
{
/// <summary>
/// 根据学号获取学生信息
/// </summary>
/// <param name="stuNo">学号</param>
/// <returns>学生信息</returns>
public Student GetStuInfo(string stuNo)
{
//数据访问逻辑,此处为了演示就简单些
var student = new Student();
switch (stuNo)
{
case "":
student = new Student() { StuNo = "", Name = "张三", Sex = "男", Age = };
break;
case "":
student = new Student() { StuNo = "", Name = "钱七七", Sex = "女", Age = };
break;
case "":
student = new Student() { StuNo = "", Name = "李四", Sex = "男", Age = };
break;
default:
student = new Student() { StuNo = "", Name = "王五", Sex = "男", Age = };
break;
} return student;
}
}
}
该类同时实现了IStudentRepository接口和IDependency接口,其中实现IDependency接口的目的是为了后面的web端进行一次性注入
三、服务层

本demo的服务层需要引用我们的实体层TianYa.DotNetShare.Model和我们的仓储层TianYa.DotNetShare.Repository
服务层与仓储层类似,它属于仓储层的使用者。定义的方式也与仓储层类似,有接口和Impl实现目录。
但服务层不需要一个实体对应一个,服务层更多的是按照功能模块进行划分,比如一个登录模块,创建一个LoginService。
为了演示,我们新建一个Student的服务层接口IStudentService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.Service
{
/// <summary>
/// 学生类服务层接口
/// </summary>
public interface IStudentService
{
/// <summary>
/// 根据学号获取学生信息
/// </summary>
/// <param name="stuNo">学号</param>
/// <returns>学生信息</returns>
Student GetStuInfo(string stuNo);
}
}
接着我们同样在Impl中新建一个Student的服务层实现StudentService.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; using TianYa.DotNetShare.Model;
using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.Service.Impl
{
/// <summary>
/// 学生类服务层
/// </summary>
public class StudentService : IStudentService, IDependency
{
/// <summary>
/// 定义仓储层学生抽象类对象
/// </summary>
protected IStudentRepository StuRepository; /// <summary>
/// 空构造函数
/// </summary>
public StudentService() { } /// <summary>
/// 构造函数
/// </summary>
/// <param name="stuRepository">仓储层学生抽象类对象</param>
public StudentService(IStudentRepository stuRepository)
{
this.StuRepository = stuRepository;
} /// <summary>
/// 根据学号获取学生信息
/// </summary>
/// <param name="stuNo">学号</param>
/// <returns>学生信息</returns>
public Student GetStuInfo(string stuNo)
{
var stu = StuRepository.GetStuInfo(stuNo);
return stu;
}
}
}
该类同时实现了IStudentService接口和IDependency接口,其中实现IDependency接口的目的是为了后面的web端进行一次性注入
四、Web层

本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上引用:

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


名称:nuget.org
源:https://api.nuget.org/v3/index.json
添加新的包源后点击确定(如果已经有此包源就忽略该步骤),接下来就从NuGet上安装我们需要的程序集。

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

到了这里我们所有的工作都已经准备好了,接下来就是重头戏,开始做注入工作了。
打开我们的Global.asax文件进行注入工作
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing; using Autofac;
using Autofac.Integration.Mvc;
using TianYa.DotNetShare.Model;
using TianYa.DotNetShare.Repository.Impl;
using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.MvcDemo
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); AutofacRegister(); //Autofac依赖注入
} /// <summary>
/// Autofac依赖注入
/// </summary>
private void AutofacRegister()
{
var builder = new ContainerBuilder();
//注册MVC控制器(注册所有到控制器,控制器注入,就是需要在控制器的构造函数中接收对象)
builder.RegisterControllers(typeof(MvcApplication).Assembly);
//构造函数注入,对StudentRepository与接口进行注入
builder.RegisterType<StudentRepository>().As<IStudentRepository>(); //设置依赖解析器
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
}
至此,我们就完成了依赖注入工作,此方式为构造函数注入,接下来我们来看看控制器里面怎么弄:
using System.Web.Mvc;
using TianYa.DotNetShare.Repository; namespace TianYa.DotNetShare.MvcDemo.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 定义仓储层学生抽象类对象
/// </summary>
protected IStudentRepository StuRepository; /// <summary>
/// 通过构造函数进行注入
/// 注意:参数是抽象类,而非实现类,因为已经在Global.asax中将实现类映射给了抽象类
/// </summary>
/// <param name="stuRepository">仓储层学生抽象类对象</param>
public HomeController(IStudentRepository stuRepository)
{
this.StuRepository = stuRepository;
} public ActionResult Index()
{
var stu = StuRepository.GetStuInfo("");
string msg = $"学号:10000,姓名:{stu.Name},性别:{stu.Sex},年龄:{stu.Age}。";
return Content(msg);
}
}
}
至此,完成处理,接下来就是见证奇迹的时刻了,我们访问 /home/index,看看是否能返回学生信息。

我们可以发现,返回了学生的信息,说明我们注入成功了。
总结:
1、采用的是构造函数注入的方式,在构造函数中初始化赋值。
2、StuRepository对象不需要实例化,即不需要new,降低了系统资源的消耗。
3、需要在Global.asax中对StudentRepository写映射,如果仓储类比较多的时候,就需要写很多了,如何避免,这个在后面的篇幅中会讲解到。
扩展: 上面讲解了构造函数注入的方式,下面扩展属性注入的方式,在Global.asax中稍微修改下注入语句即可。
将:
builder.RegisterControllers(typeof(MvcApplication).Assembly);
改为:
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
PropertiesAutowired:表示允许属性注入。
接下来我们来看下怎么使用,修改下我们的依赖注入语句,新增服务层学生类注入:
/// <summary>
/// Autofac依赖注入
/// </summary>
private void AutofacRegister()
{
var builder = new ContainerBuilder();
//注册MVC控制器(注册所有到控制器,控制器注入,就是需要在控制器的构造函数中接收对象)
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
//构造函数注入,对StudentRepository与接口进行注入
builder.RegisterType<StudentRepository>().As<IStudentRepository>();
builder.RegisterType<StudentService>().As<IStudentService>(); //设置依赖解析器
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
修改我们的控制器代码:
using System.Web.Mvc;
using TianYa.DotNetShare.Service; namespace TianYa.DotNetShare.MvcDemo.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 通过属性注入,访问修饰符必须为public,否则会注入失败
/// </summary>
public IStudentService StuService { get; set; } public ActionResult Index()
{
var stu = StuService.GetStuInfo("");
string msg = $"学号:10001,姓名:{stu.Name},性别:{stu.Sex},年龄:{stu.Age}。";
return Content(msg);
}
}
}
再访问一下我们的/home/index

我们可以发现,返回了学习信息,说明我们注入成功了。
另外通过这个例子我们可以发现在注入仓储层对象StudentRepository时,不仅控制器中注入成功了,而且在服务层中也注入成功了,说明我们的Autofac的注入是全局的。
总结:
1、通过属性注入,访问修饰符必须为public,否则会注入失败。
2、Autofac的注入是全局的。
扩展:以上例子我们都是将实现类映射给对应的实现类接口,那能不能直接注入实现类呢,答案是可以的。
修改下我们的依赖注入,新增我们的实现类注入语句:
/// <summary>
/// Autofac依赖注入
/// </summary>
private void AutofacRegister()
{
var builder = new ContainerBuilder();
//注册MVC控制器(注册所有到控制器,控制器注入,就是需要在控制器的构造函数中接收对象)
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired();
//构造函数注入,对StudentRepository与接口进行注入
builder.RegisterType<StudentRepository>().As<IStudentRepository>(); //实现类映射给接口
builder.RegisterType<StudentService>().As<IStudentService>();
builder.RegisterType<StudentRepository>(); //实现类注入 //设置依赖解析器
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
再来看下我们的控制器
using System.Web.Mvc;
using TianYa.DotNetShare.Repository.Impl; namespace TianYa.DotNetShare.MvcDemo.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 定义仓储层学生实现类对象
/// </summary>
public StudentRepository StuRepositoryImpl { get; set; } public ActionResult Index()
{
var stu = StuRepositoryImpl.GetStuInfo("");
string msg = $"学号:10002,姓名:{stu.Name},性别:{stu.Sex},年龄:{stu.Age}";
return Content(msg);
}
}
}
再访问一下我们的/home/index

可以看出已经实现了我们具体的实现类注入
到了这里,大家可能会发现在我们的Global.asax文件中,所有仓储层、服务层的类都需要一个个注册,那如果很多类的话,那可就写老长了,那有什么解决方法吗,答案是肯定的。Autofac还提供了其他方式注入,下面就介绍下我们的解决办法。
还记得我们上面介绍仓储层和服务层实现类的时候都实现了我们的IDependency接口吗,接下来就派上大用场了,我们可以一次性注册所有实现了IDependency接口的类。
修改一下我们的依赖注入方式来实现一次性注入:
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Reflection;
using System.IO; using Autofac;
using Autofac.Integration.Mvc;
using TianYa.DotNetShare.Model; namespace TianYa.DotNetShare.MvcDemo
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); AutofacRegister(); //Autofac依赖注入
} /// <summary>
/// Autofac依赖注入
/// </summary>
private void AutofacRegister()
{
var builder = new ContainerBuilder();
//注册MVC控制器(注册所有到控制器,控制器注入,就是需要在控制器的构造函数中接收对象)
//PropertiesAutowired:允许属性注入
builder.RegisterControllers(typeof(MvcApplication).Assembly).PropertiesAutowired(); //一次性注册所有实现了IDependency接口的类
Type baseType = typeof(IDependency);
Assembly[] assemblies =
Directory.GetFiles(AppDomain.CurrentDomain.RelativeSearchPath, "*.dll").Select(Assembly.LoadFrom).ToArray();
builder.RegisterAssemblyTypes(assemblies)
.Where(type => baseType.IsAssignableFrom(type) && !type.IsAbstract)
.AsSelf().AsImplementedInterfaces()
.PropertiesAutowired().InstancePerLifetimeScope(); //设置依赖解析器
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
}
}
最后再来看下我们的控制器
using System.Web.Mvc;
using TianYa.DotNetShare.Service;
using TianYa.DotNetShare.Repository;
using TianYa.DotNetShare.Repository.Impl; namespace TianYa.DotNetShare.MvcDemo.Controllers
{
public class HomeController : Controller
{
/// <summary>
/// 定义仓储层学生实现类对象
/// </summary>
public StudentRepository StuRepositoryImpl { get; set; } /// <summary>
/// 定义仓储层学生抽象类对象
/// </summary>
protected IStudentRepository StuRepository; /// <summary>
/// 通过属性注入,访问修饰符必须为public,否则会注入失败
/// </summary>
public IStudentService StuService { get; set; } /// <summary>
/// 通过构造函数进行注入
/// 注意:参数是抽象类,而非实现类,因为已经在Global.asax中将实现类映射给了抽象类
/// </summary>
/// <param name="stuRepository">仓储层学生抽象类对象</param>
public HomeController(IStudentRepository stuRepository)
{
this.StuRepository = stuRepository;
} public ActionResult Index()
{
var stu1 = StuRepository.GetStuInfo("");
var stu2 = StuService.GetStuInfo("");
var stu3 = StuRepositoryImpl.GetStuInfo("");
string msg = $"学号:10000,姓名:{stu1.Name},性别:{stu1.Sex},年龄:{stu1.Age}<br />";
msg += $"学号:10001,姓名:{stu2.Name},性别:{stu2.Sex},年龄:{stu2.Age}<br />";
msg += $"学号:10002,姓名:{stu3.Name},性别:{stu3.Sex},年龄:{stu3.Age}";
return Content(msg);
}
}
}
再次访问一下我们的/home/index

可以看出成功返回了学生信息,说明我们的一次性注入成功了。
至此我们就介绍完了Autofac依赖注入在MVC中的具体使用,下一章我们将继续简单的介绍下Autofac在普通的WebForm当中的使用。
demo源码:
链接:https://pan.baidu.com/s/1jUbf1pk2-bSybf9OfUh8Tw
提取码:24ki
参考博文:https://www.cnblogs.com/fei686868/p/10979790.html
版权声明:如有雷同纯属巧合,如有侵权请及时联系本人修改,谢谢!!!
ASP.NET MVC IOC依赖注入之Autofac系列(一)- MVC当中应用的更多相关文章
- ASP.NET MVC IOC依赖注入之Autofac系列(二)- WebForm当中应用
上一章主要介绍了Autofac在MVC当中的具体应用,本章将继续简单的介绍下Autofac在普通的WebForm当中的使用. PS:目前本人还不知道WebForm页面的构造函数要如何注入,以下在Web ...
- ASP.NET MVC IOC依赖注入之Autofac系列开篇
Autofac为IOC组件,实现控制反转,主要结合面向接口编程,完成较大程度的解耦工作. 使用IOC,必须面向接口编程,所谓的面向接口编程,即程序中依赖于抽象,而不依赖于具体实现. 需要所有的业务逻辑 ...
- asp.net core ioc 依赖注入
1.生命周期 内置的IOC有三种生命周期: Transient: Transient服务在每次被请求时都会被创建.这种生命周期比较适用于轻量级的无状态服务. Scoped: Scoped生命周期的服务 ...
- 大比速:remoting、WCF(http)、WCF(tcp)、WCF(RESTful)、asp.net core(RESTful) .net core 控制台程序使用依赖注入(Autofac)
大比速:remoting.WCF(http).WCF(tcp).WCF(RESTful).asp.net core(RESTful) 近来在考虑一个服务选型,dotnet提供了众多的远程服务形式.在只 ...
- 浅谈(IOC)依赖注入与控制反转(DI)
前言:参考了百度文献和https://www.cnblogs.com/liuqifeng/p/11077592.html以及http://www.cnblogs.com/leoo2sk/archive ...
- ASP.NET Core之依赖注入
本文翻译自:http://www.tutorialsteacher.com/core/dependency-injection-in-aspnet-core ASP.NET Core支持依赖注入,依赖 ...
- Asp.net core自定义依赖注入容器,替换自带容器
依赖注入 在asp.net core程序中,众所周知,依赖注入基本上贯穿了整个项目,以通用的结构来讲解,控制器层(Controller层)依赖业务层(Service层),业务层依赖于仓储层(Repos ...
- MVC Castle依赖注入实现代码
1.MVc 实现依赖注入 public class WindsorControllerFactory : DefaultControllerFactory { private readonly IKe ...
- ASP.NET 5:依赖注入
ASP.NET 5:依赖注入 1.背景 如果某个具体的(或类)对象被客户程序所依赖,通常把它们抽象成抽象类或接口.简单说,客户程序摆脱所依赖的具体类型,称之为面向接口编程. 那么问题来了?如何选择客户 ...
随机推荐
- sql为什么用0,1表示男女?在sql语句里转好还是在页面转好?
转化语句:SELECT CASE `user_gender` WHEN '1' THEN '男' WHEN '0' THEN '未知'ELSE '女' END AS gender FROM `info ...
- 初步了解JVM第二篇
在一篇<初步了解JVM第一篇>中,我们已经了解了: 类加载器:负责加载*.class文件,将字节码内容加载到内存中.其中类加载器的类型有如下: 启动类加载器(Bootstrap) 扩展类加 ...
- ubuntu14.04编译gnu global 6.6.3
打算重新折腾下环境,看中了gtags ,可参考 Vim 8 中 C/C++ 符号索引:GTags 篇 ,先记录下编译过程 源码 下载并解压源码 最新的代码到官方下载页面获取 https://www.g ...
- 一起学Spring之Web基础篇
概述 在日常的开发中Web项目集成Spring框架,已经越来越重要,而Spring框架已经成为web开发的主流框架之一.本文主要讲解Java开发Web项目集成Spring框架的简单使用,以及使用Spr ...
- iOS核心动画高级技巧 - 7
13. 高效绘图 高效绘图 不必要的效率考虑往往是性能问题的万恶之源. ——William Allan Wulf 在第12章『速度的曲率』我们学习如何用Instruments来诊断Core Anima ...
- Java面试题_第四阶段
1.1 电商行业特点 1.分布式 垂直拆分:根据功能模块进行拆分 水平拆分:根据业务层级进行拆分 2.高并发 用户单位时间内访问服务器数量,是电商行业中面临的主要问题 3.集群 抗击高兵发的有效手段, ...
- Elasticsearch7.5.0源码编译
环境及工具 JDK12 Gradle5.6.2 GIT 源码及预处理 到github将代码clone下来,可以根据自己的需求来获取版本,例如 git checkout v7.5.0 提前下载gradl ...
- python--推倒式(列表、字典、集合)
python的各种推导式(列表推导式.字典推导式.集合推导式) 推导式comprehensions(又称解析式),是Python的一种独有特性.推导式是可以从一个数据序列构建另一个新的数据序列的结构体 ...
- 激光炸弹 HYSBZ - 1218
激光炸弹 HYSBZ - 1218 Time limit:10000 ms Memory limit:165888 kB OS:Linux Source:HNOI2003 一种新型的激光炸弹,可以摧毁 ...
- C# -- LinkedList的使用
C# -- LinkedList的使用 private static void TestLinkList() { LinkedList<Person> linkListPerson = n ...