我们都知道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);
}
}
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>
<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);
}
}
}
}
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;
}
}
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>
<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>
<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的容器中。