Unity是微软Patterns & Practices团队所开发的一个轻量级的,并且可扩展的依赖注入(Dependency Injection)容器,通过使用Unity,我们能轻松构建松耦合结构的程序,从而让整个程序框架变得清晰和易于维护。下面我通过两个具体的mvc的例子来说明一下怎么用代码和配置文件来实现IOC。
1、用编程方式实现注入
使用Unity来管理对象与对象之间的关系可以分为以下几步:
A、创建一个UnityContainer对象
B、通过UnityContainer对象的RegisterType方法来注册对象与对象之间的关系
C、通过UnityContainer对象的Resolve方法来获取指定对象关联的对象
2、配置文件方式
通过配置文件配置Unity信息需要有以下几个步骤:
A、在配置文件<configSections> 配置节下注册名为unity的section
B、在<configuration> 配置节下添加Unity配置信息
C、在代码中读取配置信息,并将配置载入到UnityContainer中
一,测试数据准备:
1.1、创建ASP.NET MVC项目(ioc)和三个类库(IInterFace,IService,Model),如图:
ioc为UI层:
注:记得引用其他类库:
1.2、ioc.IInterFace为抽象层(接口):这里写了两个接口(IUser和IStudent)
1、IUser用于测试:只使用代码,不使用配置文件实现IOC
2、IStudent用于测试:使用配置文件实现IOC
IStudent 接口代码:
using ioc.Model;<br/>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ioc.IInterFace
{
public interface IStudent
{
IEnumerable<Student> GetAll();
Student Get(int id);
Student Add(Student item);
bool Update(Student item);
bool Delete(int id);
}
}
IUser 接口代码:
using ioc.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ioc.IInterFace
{
public interface IUser
{
List<UserInfo> GetUsers();
}
}
1.3、ioc.IService为业务层(继承对应抽象类):这里创建两个实现类(SimpleStudent,SimpleUser)
SimpleStudent 类(继承自IStudent)代码:
using ioc.IInterFace;
using ioc.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ioc.IService
{
public class SimpleStudent : IStudent
{
private readonly List<Student> Articles = new List<Student>();
public SimpleStudent()
{
//添加演示数据
Add(new Student { Id = 1, Name = "大司马", Major = "软件工程", Graduation = "2021年", School = "清华大学" });
Add(new Student { Id = 2, Name = "茄子", Major = "计算机科学与技术", Graduation = "2021年", School = "清华大学" });
Add(new Student { Id = 3, Name = "呆妹", Major = "自动化", Graduation = "2021年", School = "清华大学" });
}
/// <summary>
/// 添加文章
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public Student Add(Student item)
{
if (item == null)
{
throw new ArgumentNullException("item is null");
}
Articles.Add(item);
return item;
}
/// <summary>
/// 获取全部文章
/// </summary>
/// <returns></returns>
public IEnumerable<Student> GetAll()
{
return Articles;
}
/// <summary>
/// 通过ID获取文章
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public Student Get(int id)
{
return Articles.Find(p => p.Id == id);
}
/// <summary>
/// 更新文章
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public bool Update(Student item)
{
if (item == null)
{
throw new ArgumentNullException("item");
}
int index = Articles.FindIndex(p => p.Id == item.Id);
if (index == -1)
{
return false;
}
Articles.RemoveAt(index);
Articles.Add(item);
return true;
}
/// <summary>
/// 删除文章
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public bool Delete(int id)
{
Articles.RemoveAll(p => p.Id == id);
return true;
}
}
}
SimpleUser(继承自IUser)类代码:
using ioc.IInterFace;
using ioc.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ioc.IService
{
public class SimpleUser : IUser
{
public List<UserInfo> GetUsers()
{
var list = new List<UserInfo>();
for (int i = 0; i < 10; i++)
{
list.Add(new UserInfo() { ID = i, UserName = "Uer" + i, Age = i });
}
return list;
}
}
}
1.4、ioc.Model为实体类:这里创建两个实体类(Student,UserInfo)
Student类代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ioc.Model
{
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Graduation { get; set; }
public string School { get; set; }
public string Major { get; set; }
}
}
UserInfo类代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ioc.Model
{
public class UserInfo
{
public int ID { get; set; }
public string UserName { get; set; }
public int Age { get; set; }
}
}
二、基本的数据层和代码准备好之后,我们开始引入容器 Unity:
2.1、右键UI层的引入,点击(管理NuGet程序包),安装这些程序包:
注:或许有些程序包用不到,但我全都引用了(PS:因为本人研究IOC的时候掉了很多坑)
2.2、Unity容器的一些程序包引用完成后就进入正题:
1.首先开始编写只用代码不使用配置文件实现IOC:
1)创建 UserController 这个控制类用来测试光用代码实现IOC注入:
UserController 代码部分:
using ioc.IInterFace;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ioc.Controllers
{
public class UserController : Controller
{
private IUser service;
public UserController(IUser service)
{
this.service = service;
}
public ActionResult Index()
{
var data = this.service.GetUsers();
return View(data);
}
}
}
然后我们在 Global.asax 中初始化 IOC:
Global.asax代码部分:
using ioc.IInterFace;
using ioc.IService;
using ioc.OtherUtil;
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 Unity;
using Unity.Mvc5;
namespace ioc
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//配置文件注入
//UnityConfig.RegisterComponents(BootStrapper.Init());
//代码注入Ioc
var container = this.BuildUnityContainer();
//这里的UnityDependencyResolver类在测试配置文件注入的时候创建了,所以需要这样区分开
DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
}
/// <summary>
/// 代码注入ioc方法
/// </summary>
/// <returns></returns>
protected IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
container.RegisterType<IUser, SimpleUser>();
//container.RegisterType<IStudent, SimpleStudent>();
return container;
}
}
}
接下来我们回到 UserController 中 右键Index方法添加视图:
添加完成后是这样的:
User 的 Index.cshtml 的代码:
@using ioc.Model;
@model List<UserInfo>
@{
ViewBag.Title = "UserIndex";
}
<h2>Index</h2>
<table class="table">
<tr>
<th>ID</th>
<th>UserName</th>
<th>Age</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>@item.ID</td>
<td>@item.UserName</td>
<td>@item.Age</td>
</tr>
}
</table>
然后右键这个Index.cshtml 点击在浏览器中查看(这里使用谷歌浏览器),效果如下:
出现👆👆👆👆👆页面就说明我们的使用代码注入IOC就成功了。
2)接下来我们创建 StudentController 这个控制类用来测试使用配置文件实现IOC注入:
StudentController 代码:
using ioc.IInterFace;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ioc.Controllers
{
public class StudentController : Controller
{
IStudent repository;
//构造器注入
public StudentController(IStudent repository)
{
this.repository = repository;
}
public ActionResult Index()
{
var data = this.repository.GetAll();
return View(data);
}
}
}
然后还是右键Index方法添加试图,Student视图的Index.cshtml代码为:
@using ioc.Model;
@model List<Student>
@{
ViewBag.Title = "Index";
}
<table class="table">
<tr>
<th>序号</th>
<th>专业</th>
<th>姓名</th>
<th>学校</th>
</tr>
@foreach (var item in Model)
{
<tr>
<td>@item.Id</td>
<td>@item.Major</td>
<td>@item.Name</td>
<td>@item.School</td>
</tr>
}
</table>
然后我们新建两个文件夹:OtherConfig 和 OtherUtil
1、在 OtherConfig 文件夹中创建文件:Unity.config;
2、在 OtherUtil 文件夹中创建文件:
BootStrapper:引导类,用于初始化工作;
UnityControllerFactory:继承DefaultControllerFactory,重载GetControllerInstance方法,实现自己的UnityControllerFactory类,并通过IoC容器将之注册为IControllerFactory的实现;
UnityDependencyResolver:实现IDependencyResolver接口并通过DependencyResolver.SetResolver告知MVC,将部分类型实例解析工作交由IoC容器Unity来处理;
如图:
Unity.config 配置文件的代码:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<!--unity配置文件-->
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Unity.Configuration" />
</configSections>
<unity>
<containers>
<container name="IQueryContainer">
<!--<register type="抽象类,抽象类的命名空间" mapTo="继承这个抽象类的实现类,实现类的命名空间"/>-->
<register type="ioc.IInterFace.IStudent,ioc.IInterFace" mapTo="ioc.IService.SimpleStudent,ioc.IService"/>
<!--<register type="ioc.IInterFace.IUser,ioc.IInterFace" mapTo="ioc.IService.SimpleUser,ioc.IService"/>-->
</container>
</containers>
</unity>
<system.serviceModel>
<bindings />
<client />
</system.serviceModel>
</configuration>
BootStrapper 类的代码:
using Microsoft.Practices.Unity.Configuration;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Unity;
namespace ioc.OtherUtil
{
public class BootStrapper
{
public static IUnityContainer Init()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
return container;
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
fileMap.ExeConfigFilename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "OtherConfig\\Unity.config");
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap,ConfigurationUserLevel.None);
UnityConfigurationSection section = (UnityConfigurationSection)configuration.GetSection(UnityConfigurationSection.SectionName);
section.Configure(container, "IQueryContainer");
return container;
}
}
}
UnityControllerFactory 类的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Unity;
namespace ioc.OtherUtil
{
/// <summary>
/// 继承DefaultControllerFactory,重载GetControllerInstance方法,
/// 实现自己的UnityControllerFactory类,并通过IoC容器将之注册为IControllerFactory的实现
/// 在配置文件(unity.config)的System.Web.Mvc.IControllerFactory后的mapTo后注册
/// </summary>
public class UnityControllerFactory : DefaultControllerFactory
{
IUnityContainer container;
public UnityControllerFactory(IUnityContainer container)
{
this.container = container;
}
protected override IController GetControllerInstance(RequestContext reqContext, Type controllerType)
{
return container.Resolve(controllerType) as IController;
}
}
}
UnityDependencyResolver 类的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Unity;
namespace ioc.OtherUtil
{
/// <summary>
/// 实现IDependencyResolver接口并通过DependencyResolver.SetResolver告知MVC
/// ,将部分类型实例解析工作交由IoC容器Unity来处理
/// </summary>
public class UnityDependencyResolver : IDependencyResolver
{
IUnityContainer container;
public UnityDependencyResolver(IUnityContainer container)
{
this.container = container;
}
public object GetService(Type serviceType)
{
if (!this.container.IsRegistered(serviceType))
{
return null;
}
return container.Resolve(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return container.ResolveAll(serviceType);
}
}
}
接下来我们在UnityConfig.cs类 和 Global.asax 中初始化容器,代码为:
ps:UnityConfig.cs类是引入Unity.Mvc5时自动创建在App_Start文件夹下的。
UnityConfig.cs类代码:
using ioc.OtherUtil;
using System.Web.Mvc;
using Unity;
using Unity.Mvc5;
namespace ioc
{
public static class UnityConfig
{
public static void RegisterComponents(IUnityContainer container)
{
//var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
}
}
}
Global.asax代码:
using ioc.IInterFace;
using ioc.IService;
using ioc.OtherUtil;
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 Unity;
using Unity.Mvc5;
namespace ioc
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
//配置文件注入
UnityConfig.RegisterComponents(BootStrapper.Init());
代码注入Ioc
//var container = this.BuildUnityContainer();
这里的UnityDependencyResolver类在测试配置文件注入的时候创建了,所以需要这样区分开
//DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));
}
/// <summary>
/// 代码注入ioc方法
/// </summary>
/// <returns></returns>
//protected IUnityContainer BuildUnityContainer()
//{
// var container = new UnityContainer();
// container.RegisterType<IUser, SimpleUser>();
// //container.RegisterType<IStudent, SimpleStudent>();
// return container;
//}
}
}
最后我们右键Student下的Index.cshtml点击在浏览器中查看,这是运行结果: