malaikuangren

What is the purpose or drive to build thing like (xxx),How can it achieve the original goal of design?
Asp.net MVS 集成Spring.net机制原理及实现

 

我们都知道Asp.net MVC自有一套执行机制。


通过分析MVC的MvcHandler关键代码


 


ProcessRequest 

        protected internal virtual void ProcessRequest(HttpContextBase httpContext) {
            AddVersionHeader(httpContext);

            
// Get the controller type
            string controllerName = RequestContext.RouteData.GetRequiredString("controller");

            
// Instantiate the controller and call Execute
            IControllerFactory factory = ControllerBuilder.GetControllerFactory();
            IController controller 
= factory.CreateController(RequestContext, controllerName);
            
if (controller == null) {
                
throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentUICulture,
                        MvcResources.ControllerBuilder_FactoryReturnedNull,
                        factory.GetType(),
                        controllerName));
            }
            
try {
                controller.Execute(RequestContext);
            }
            
finally {
                factory.ReleaseController(controller);
            }
        }

 


 


我们可以认为MVC中Controller都是基于工厂模式来创建对象的。

 

但是要利用Spring.net实现IOC和AOP,就必须管理这个框架中具体对象的创建工作。

即通过配置文件的方式决定一个具体对象的生或死!


Objects 

<objects xmlns="http://www.springframework.net/">
  
  
<object id="Demos.Domain.Object">
    
<property name="Target">
      
<object type="Demos.Domain.Object,Demos.Domain">
        
<property name="Manager" ref="Demos.Domain.Manager"/>
      
</object>
    
</property>
  
</object>
</objects>

 

 

但是MVC框架自己的运行机制决定了Controller的创建不会经过Spring。

 

幸好,MVC留下了一个叫做SetControllerFactory的扩展。

即,程序运行之初我们就可以用自己的ControllerFactory替换默认的ControllerFactory.



        protected void Application_Start()
        {
            //用自定义的构造工厂替换默认的
            ControllerBuilder.Current.SetControllerFactory(typeof(Demo.Core.ControllerFactory));


            RegisterRoutes(RouteTable.Routes);
        }


 


 

这样我们自己的工厂进行替换默认的Controller工厂后,就可以控制Controller的创建了。

 


我们自己的Controller工厂的代码


ControllerFactory 

using System.Web.Mvc;
using System.Web.Routing;
using Spring.Context;

namespace Demo.Core
{
    
public class ControllerFactory : IControllerFactory
    {
        
/// <summary>
        
/// Default ControllerFactory
        
/// </summary>
        private static DefaultControllerFactory defalutf = null;

        
public IController CreateController(RequestContext requestContext, string controllerName)
        {
            
string controller = controllerName + "Controller";
            IApplicationContext ctx 
= Container.GetContext();

            
if (ctx.ContainsObject(controller))
            {
                
object controllerf = ctx.GetObject(controller);
                
return (IController)controllerf;
            }
            
else
            {
                
if (defalutf == null)
                {
                    defalutf 
= new DefaultControllerFactory();
                }
                    
                
return defalutf.CreateController(requestContext, controllerName);
            }
        }

        
public void ReleaseController(IController controller)
        {
            IApplicationContext ctx 
= Container.GetContext();

            
if (!ctx.ContainsObject(controller.GetType().Name))
            {
                
if (defalutf == null)
                {
                    defalutf 
= new DefaultControllerFactory();
                }

                defalutf.ReleaseController(controller);
            }
        }
    }
}

 


 


 Spring.net 容器包装的代码


 


Container 

using System;
using System.Collections;
using System.Collections.Generic;
using Spring.Context;
using Spring.Context.Support;

namespace Demo.Core
{
    
public class Container
    {
        
/// <summary>
        
/// 获取应用程序上下文.
        
/// </summary>
        
/// <returns><see cref="IApplicationContext"/>应用程序上下文.</returns>
        public static IApplicationContext GetContext()
        {
            
if (FApplicationContext == null)
            {
                FApplicationContext 
= ContextRegistry.GetContext();
            }
            
return FApplicationContext;
        }

        
/// <summary>
        
/// 获取应用程序上下文.
        
/// </summary>
        
/// <param name="name"><see cref="IApplicationContext"/>应用程序上下文名称.</param>
        
/// <returns><see cref="IApplicationContext"/>应用程序上下文.</returns>
        public static IApplicationContext GetContext(string name)
        {
            
return ContextRegistry.GetContext(name);
        }

        
/// <summary>
        
/// 获取对象.
        
/// </summary>
        
/// <typeparam name="T">对象的类型.</typeparam>
        
/// <param name="id">标识.</param>
        
/// <returns></returns>
        public static T GetObject<T>(string id)
        {
            
return (T)GetContext().GetObject(id);
        }

        
/// <summary>
        
/// 获取对象类表.
        
/// </summary>
        
/// <typeparam name="T">对象的类型.</typeparam>
        
/// <returns></returns>
        public static IList<T> GetObjects<T>()
        {
            IEnumerable items 
= GetContext().GetObjectsOfType(typeof(T));
            IList
<T> objects = new List<T>();
            
foreach (DictionaryEntry item in items)
            {
                objects.Add((T)item.Value);
            }
            
return objects;
        }

        [ThreadStatic]
        
private static IApplicationContext FApplicationContext;
    }
}

 


 


然后我们再新建个Demos.Controllers的项目。






using System.Web.Mvc;


namespace Demo.Controllers
{
    public class DemoController : Controller
    {
        public ViewResult Index()
        {
            ViewData["Message"] = "Welcome to IOC MVC";
            return View();
        }
    }
}


 

 

相应Dll的配置文件


<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net/">
  <object id="DemoController" type="Demo.Controllers.DemoController, Demo.Controllers" singleton="false" >
  </object>
</objects> 

 


并把配置文件设置为嵌入资源


然后再在Web.config中添加相应配置


 


Web.config 

  <sectionGroup name="spring">
      
<section name="context" type="Spring.Context.Support.WebContextHandler, Spring.Web" />
      
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
  
</sectionGroup>

  
<spring>
    
<context>
      
<resource uri="config://spring/objects" />
      
<resource uri="assembly://Demo.Controllers/Demo.Controllers/Controllers.xml" />
    
</context>
    
<objects xmlns="http://www.springframework.net" />
  
</spring>

 


 


 

测试运行,我们可以发现这个DemoController已在Spring的容器中。

posted on 2012-02-22 17:24  malaikuangren  阅读(262)  评论(0编辑  收藏  举报