自己动手写ASP.NET的IOC容器!
IOC容器(动态反转),这个概念就不多解释了,想必大家都知道,IOC框架也有很多,如spring.net,unity,castle windsor,autofac等,这里不多作介绍了,下面我为大家展现如何自己动手写IOC容器纵观各IOC容器,其内部实现原理几乎都是从配置文件(web.config)中读取信息,如何实例化相应的对象,本篇博客也不例外。即把web.config里面每一个section映
IOC容器(控制反转),这个概念就不多解释了,想必大家都知道,IOC框架也有很多,如spring.net,unity,castle windsor,autofac等,这里不多作介绍了,下面我为大家展现如何自己动手写IOC容器
纵观各IOC容器,其内部实现原理几乎都是从配置文件(web.config)中读取信息,如何实例化相应的对象,本篇博客也不例外。即把web.config里面每一个section映射成相关类,我们来看一下webconfig
<configuration>
<configSections>
<!--IOC工厂声明-->
<sectionGroup name="MyIocContainer">
<section name="objects" type="WebApplicationTest.Ioc.IocContainer,WebApplicationTest"/>
</sectionGroup>
</configSections>
<MyIocContainer>
<!--DI 依赖注入设置-->
<objects>
<add key="UserInfo" value="WebApplicationTest.UserInfo,WebApplicationTest"></add>
</objects>
</MyIocContainer>
非常清楚,我们可以通过section节点来添加一个IOC工厂,然后再根据纵观section写一个相关的参数节点MyIocContainer。这里名字可以随便写,其中section节点中的type属性中的内容分别是全类名+程序集名称。
写好了配置文件,我们可以通过ConfigurationManager.GetSection(“MyIocContainer/objects”)方法来获取相关信息。
这时我们需要写一个类,即上面的IocContainer这个类,继承IConfigurationSectionHandler,
**并实现 public object Create(object parent, object configContext, XmlNode section)这个方法。**ConfigurationManager.GetSection(“MyIocContainer/objects”)当这个方法被调用时,就会执行我们实现的这个Create方法,Create方法中的三个参数的意思分别是父对象,程序集内容,section节点中的内容。我们需要用到的只有XmlNode section这个参数,它封装了我们webconfig中的<add key="UserInfo" value="WebApplicationTest.UserInfo,WebApplicationTest">
这个节点的内容。
下面来看看我们在Create方法中写的代码。
using System.Xml;
namespace WebApplicationTest.Ioc
{
/// <summary>
/// 自己写的Ioc容器工厂
/// </summary>
public class IocContainer : IConfigurationSectionHandler
{
public object Create(object parent, object configContext, XmlNode section)
{
/*
* 获取需要注入的类的相关信息
*/
NameValueCollection paramCollection = (NameValueCollection) new NameValueSectionHandler().Create(parent, configContext, section);
//获取类名
string className = IocDomain.className;
string classInfo = paramCollection[className].ToString();
//获取全类名
string classFullName = classInfo.Split(',')[0];
//获取程序集名称
string assemblyName = classInfo.Split(',')[1];
/*
* 根据反射,取得对象
*/
Assembly assembly = Assembly.Load(assemblyName);
Type t= assembly.GetType(classFullName);
Object obj = Activator.CreateInstance(t);
return obj;
}
}
}
代码的相关解释都在代码的注释中了,相信大家都能看得懂。这里需要用到两个参数类,NameValueCollection 和NameValueSectionHandler,通过NameValueSectionHandler和section参数创建一个NameValueCollection 对象,这是一个键值对集合,通过这个集合我们就能获取 <add key="UserInfo" value="WebApplicationTest.UserInfo,WebApplicationTest">
这个里面的内容。然后根据这些内容,实例化对象!
这里面有个小注意点,就是大家有没有看到我写的IocDomain这个类,这个类作用是域功能,存放一些全局的东西,这里我用来存放我们需要实例化的类的名称。
这就是我们所封装的IOC工厂类,那这个工厂类是在哪使用的呢?前面说到了ConfigurationManager.GetSection(“MyIocContainer/objects”)这个方法,这个方法被调用,就会调用到我们的Create方法。下面是我对这个方法的封装。
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
namespace WebApplicationTest.Ioc
{
/// <summary>
/// Ioc操作类
/// </summary>
public class IocService
{
public static object GetObject(string className)
{
IocDomain.className = className;
return ConfigurationManager.GetSection("MyIocContainer/objects");
}
}
}
这个非常简单,一目了然,我们通过className,即我们想实例化的类的名字,来传给一个全局域对象,然后就可以实现上面的功能了。这里要注意一点就是:ConfigurationManager.GetSection方法调用,只有在第一次调用或者配置文件中相关内容改变后,才会调用到我们IOC工厂中的Create方法,之后的调用都不会执行Create方法,但Create方法的返回值会存放在内存中,直接供我们使用
好了,到这里我们自己写的一个简单的IOC容器就完事了,至于对象中属性的值的初始化,我这里没做,相信大家看到这里应该会自己扩展了,这边就不多做介绍了。下面看看我是如何应用的
首先我写了一个非常简单的页面,里面只有一个按钮,点击按钮,向后台的ashx发请求,然后将值alert出来,我这里展示ashx的代码。如下:
public class UserInfoHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
UserInfo userInfo=(UserInfo)IocService.GetObject("UserInfo");
userInfo.UserName = "奥特曼打怪兽";
JavaScriptSerializer serializer = new JavaScriptSerializer();
string data = serializer.Serialize(userInfo);
context.Response.ContentType = "text/plain";
context.Response.Write(data);
}
更多详细信息可以查询官网文档:https://docs.microsoft.com/zh-cn/previous-versions/dotnet/netframework-2.0/ms228114(v=vs.80)
浏览器运行效果如下:
更多推荐
所有评论(0)