自己动手写ASP.NET的IOC容器!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a1037949156/article/details/73692254

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);

        }

浏览器运行效果如下:
这里写图片描述

展开阅读全文

没有更多推荐了,返回首页