ASP.NET MVC IOC依赖注入之Autofac系列(一)
话不多说,直入主题看我们的解决方案结构:
分别对上面的工程进行简单的说明:
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 "10000": student = new student() { stuno = "10000", name = "张三", sex = "男", age = 20 }; break; case "10001": student = new student() { stuno = "10001", name = "钱七七", sex = "女", age = 18 }; break; case "10002": student = new student() { stuno = "10002", name = "李四", sex = "男", age = 21 }; break; default: student = new student() { stuno = "10003", name = "王五", sex = "男", age = 25 }; 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
添加新的包源后点击确定(如果已经有此包源就忽略该步骤)
依次点击下载以下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; using system.collections.generic; using system.linq; using system.web; using system.web.mvc; using tianya.dotnetshare.model; using tianya.dotnetshare.service; 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("10000"); string msg = $"学号:10000,姓名:{stu.name},性别:{stu.sex},年龄:{stu.age}。"; return content(msg); } public actionresult about() { viewbag.message = "your application description page."; return view(); } public actionresult contact() { viewbag.message = "your contact page."; return view(); } } }
至此,完成处理,接下来就是见证奇迹的时刻了,我们访问 /home/index,看看是否能返回学生信息。
我们可以发现,返回了学生的信息,说明我们注入成功了。
总结:
1、采用的是构造函数注入的方式,在构造函数中初始化赋值。
2、sturepository对象不需要实例化,即不需要new,降低了系统资源的消耗。
3、需要在global.asax中对studentrepository写映射,如果仓储类比较多的时候,就需要写很多了,如何避免,这个在后面的篇幅中会讲解到。
扩展: 上面讲解了构造函数注入的方式,下面扩展属性注入的方式,在global.asax中稍微修改下注入语句即可。
将:
builder.registercontrollers(typeof(mvcapplication).assembly);
改为:
builder.registercontrollers(typeof(mvcapplication).assembly).propertiesautowired();
propertiesautowired:表示允许属性注入。
推荐阅读
-
ASP.NET MVC IOC依赖注入之Autofac系列(一)
-
解读ASP.NET 5 & MVC6系列教程(7):依赖注入
-
ASP.NET MVC IOC依赖注入之Autofac系列开篇
-
ASP.NET Core 2.2 WebApi 系列【三】AutoFac 仓储接口的依赖注入
-
ASP.NET MVC IOC依赖注入之Autofac系列(一)
-
ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下
-
大话DI依赖注入+IOC控制反转(一) 之 定义
-
ASP.NET Core依赖注入系列教程之控制反转(IoC)
-
ASP.NET MVC IOC 之AutoFac攻略
-
ASP.NET Core Web 应用程序系列(二)- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)