.net企业级架构实战之7——Spring.net整合Asp.net mvc

出处:http://www.cnblogs.com/moye/archive/2008/11/30/1344369.html

既然提到mvc,就不得不说说微软在asp.net上的一个重要创造——postback机制。
但凡用asp.net做web开发的人,都和这个机制打过交道吧。asp.net页面aspx是其于这种自回发机制运转的。
我们平时用到的web控件,诸如TextBox、Button等,无一不是基于postback进行封装,在最终生成的html页中,它们还是会被转化成为<input type='text'>或者<input type='submit'>。
然后我们可以查看一下页面的源文件代码,会发现.net framework为我们写了不少东西:比如__doPostBack()这个js方法,用于提交窗体;WebForm_OnSubmit()方法会进行窗体的验证;一个长长的__VIEWSTATE隐藏字段保存窗体上控件的状态信息等(令人发指)……等等。(详述请参见种玉堂的《再认识asp.net的postback机制:探索__doPostBack的来龙去脉 》)。
多么让人又爱又恨的发明! postback确实方便了开发者,尤其是小型应用,手到擒来;但性能呢?不敢恭维!尤其那一长串__VIEWSTATE,每每看到,都觉得揪心。

所以,在项目中的前端表现界面,决定启用mvc实现。
原来使用monoRail,感觉很好,但一直没有解决与Spring.net整合问题;而后来干脆听说,monoRail已经停止维护这个项目,只得作罢。幸好,此时还有一个选择——asp.net Mvc。
经过一段时间的尝试,终于把它与Spring.net整合在了一起,这意味着,mvc能共享到Spring.net中的所有对象,无缝集成。

由于Asp.net Mvc是ASP.NET 3.5 Extensions Preview 的一个部分,能不能在IIS6+Asp.net 2.0 framework下良好运行,也一度让人担忧,可喜的是,网上很多人都这么干,并且成功了。也就是说,如果决定在.net 2.0下使用asp.net mvc(本实例使用的版本为asp.net mvc Preview 4),除引用mvc的dll外(Microsoft.Web.Mvc.dll、System.Web.Mvc.dll等),还需额外的引用一个.net 3.5的dll(System.core.dll),此处提供这个包的下载:

Asp.net mvc preview 4 和 System.core.dll(v3.5):/Files/moye/Asp.Net_MVC_4.rar

简单说,.net mvc将视图(View)与控制器(Controller)进行了分离,表现与逻辑的关注点不再纠缠于一团。而Model的传递,微软提供了一套DataDictionary(ViewDataDictionary、TempDataDictionary等)。同时,像monoRail一样,.net mvc在页面中也可以其于模板书写表达式,比如:你可以在Controller中传递一个IList<T>过来,这边接收到对象拆箱后,循环迭代输出一个行数等同的<Table>。
关于asp.net mvc的详尽原理,此处不累述,有兴趣可参阅 乱世重典的《Asp.net Mvc Framework 系列》。

欧克,回到重点,说说整合的事:

.net企业级架构实战之7——Spring.net整合Asp.net mvc

以上图示的结构:
将Controller单拿出来,做一个层,用以响应Web/Views中视图的请求。整合的目标就是:让这些Controller能够被注入,运行于Spring.net容器中。

通过学习Fredrik Normén的经验:《ASP.Net MVC Framework - Create your own IControllerFactory and use Spring.Net for DI 》,我们能知道,要创建自己的ControllerFactory,必须实现System.Web.Mvc的IControllerFactory接口。原型如(.net mvc Preview 4,版本不同接口也可能不一样):

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> using System;
using System.Web.Routing;

namespace System.Web.Mvc
{
public interface IControllerFactory
{
IController CreateController(RequestContext context,
string controllerName);
void DisposeController(IController controller);
}
}


在实现的CreateController方法中,将负责对不同的Views派发对应的Controller。这里做一个假设,/Views目录中有一个叫User的目录,那框架就认为,这是一个User视图集合(具体表现在url上,如/User/home、/User/login等),应该有一个叫UserController的控制器对此目录中的所有页面进行响应。

欧克,实践一把:

◆在Web的/Views创建一个web.config文件,并这样配置(它的作用:接管对.aspx页的请求流程):

web.config
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><?xml version="1.0"?>
<configuration>
<system.web>
<httpHandlers>
<remove verb="*" path="*.aspx"/>
<add path="*.aspx" verb="*"
type
="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
</system.web>

<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<remove name="PageHandlerFactory-ISAPI-2.0"/>
<remove name="PageHandlerFactory-ISAPI-1.1"/>
<remove name="PageHandlerFactory-Integrated"/>
<add name="BlockViewHandler" path="*.aspx" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
</handlers>
</system.webServer>
</configuration>


◆在/Views中创建一个叫User的目录,并在其下添加一个Home.aspx页。当然这样是不能用的,需要修改一下页面和.cs:

Home.aspx
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><%@ Page Language="C#" AutoEventWireup="true" CodeFile="Home.aspx.cs" Inherits="mvcApp.Views.User.Home"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>User Home</title>
</head>
<body>
</body>
</html>
Home.aspx.cs
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;

namespace mvcApp.Views.User
{
publicpartialclass Home : ViewPage
{
}
}


◆此时,还需要一个Controller来负责响应User视图中的请求,如前结构图所示,在woodigg.controllers层中,创建一个UserController类,担当控制器角色:

UserControllers.cs
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->using System;
using System.Text;
using System.Collections.Generic;
using woodigg.model;
using woodigg.Interface.DAO;
using System.Data;
using System.Web;
using System.Web.Routing;
using System.Web.Mvc;
using System.IO;
using woodigg.controllers;
using woodigg.DAO.Tool;
using woodigg.bll.Tool;

namespace woodigg.controllers.Controllers
{
publicclass UserControllers : Controller
{
#region 注入对象
private IUserMainDAO _UserMainDaoSpring;
public IUserMainDAO UserMainDaoSpring
{
get { return _UserMainDaoSpring; }
set { _UserMainDaoSpring = value; }
}
#endregion

/*--------------------- USER ---------------------*/
///<summary>
/// Home页
///</summary>
[HandleError]
[OutputCache(Duration
=60, VaryByParam ="id")]
#region ActionResult Home(int id)
public ActionResult Home(int id)
{
ViewData[
"Title"] ="用户中心 -- Haphere.com";

return View();
}
#endregion

}
}


◆在控制器中,有一个Home方法,它刚好与Home.aspx同名,所以它就是负责响应Home页请求的方法。Home方法有一个整型的参数,说明这个请求也是传递参数的,形如http://localhost/User/Home/1(在.net 2.0 url没这么完美,它形如http://localhost/User.mvc/Home/1),那么1就是这个id参数,然后就去查数据库吧,1号用户的数据将它展示出来,当然这个示例没有取任何东西,只是传递了一个ViewData数据。
而我们也注意到,这里还进行了注入,欧克,开始整合Spring.net和.net mvc控制器工厂吧

◆做一个spring.net配置文件,controllers.xml,还放在web的/config目录中:

controllers.xml
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --><?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:xsi
="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation
="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd"
>
<!--controllers-->
<object id="UserController"
type
="woodigg.controllers.Controllers.UserControllers, woodigg.controllers" autowire="byName">
</object>
</objects>


◆然后,为实现IControllerFactory,在bll层中创建一个SpringControllerFactory类(一旦此bll程序集被引用,所有Views请求都将视这个实现类为Handler,控制器由它派发,这是.net mvc一个很妙的设计):

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> using System;
using System.Collections.Generic;
using System.Text;
using Spring.Core.IO;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Xml;
using System.Web.Mvc;
using System.Web.Routing;
using System.IO;
using woodigg.DAO.Tool;
using Spring.Context;
using Spring.Context.Support;

namespace woodigg.bll.Handler
{
/**////<summary>
///控制器工厂
///</summary>

publicclassSpringControllerFactory:IControllerFactory
{
/**////<summary>
///实现接口
///</summary>
///<paramname="context"></param>
///<paramname="controllerType"></param>
///<returns></returns>

publicIControllerCreateController(RequestContextcontext,stringname)
{
if(File.Exists(ParameterFactory.CfgControllersFilePath))
{
//配置上下文
IApplicationContextconfigContext=newXmlApplicationContext(
ParameterFactory.CfgFilePath,
ParameterFactory.CfgBusinessFilePath,
ParameterFactory.CfgControllersFilePath,
ParameterFactory.CfgBusinessMediaFilePath
);
//首字母大写的控制器名字
stringcontrollName=GetFirstUpcaseName(name)+"Controller";
//返回对应的对象:IOC
if(configContext.ContainsObject(controllName))
return(IController)configContext.GetObject(controllName);
else
returnnull;
}

else
{
IControllerFactoryfa
=ControllerBuilder.Current.GetControllerFactory();
returnfa.CreateController(context,name);
}


}


publicvoidDisposeController(IControllercontroller)
{

}


//首字母大写
privatestringGetFirstUpcaseName(stringname)
{
stringtemp=name.Replace(".mvc","").ToLower();
stringfirst=temp[0].ToString();
returntemp.Replace(first,first.ToUpper());
}

}

}

◆这里需要说明的是ParameterFactory:一个静态参数工厂。它将当前站点的SERVER端物理目录存在static string类型的变量中,此处用到的三个变量CfgFilePath、CfgBusinessFilePath、CfgControllersFilePath,分别为三个spring.net xml配置文件所在的物理路径。
显然,当Views/User/Home.aspx发出请求时,它会在/config/controllers.xml中找到UserController控制器,并不算完——UserController请求注入UserMainDaoSpring对象,它又会在/config/business.xml中找到这个对象的定义。完了吗?那得看UserMainDaoSpring是否也有注入别的对象了。
这种情况会乱吗?一点也不,即使你不用spring.net 整合它们,也一样会用到这些对象,只是使用的流程会有一些不同罢了。那么,在这个工厂中,只要捋清楚,你会用到哪些配置就行了(对这些配置xml文件,还是按用途分类比较好,如页面一个,访问层一个,web services一个……然后,去管理它们!)。

◆最后,把它们联结起来,在web/下新建一个Global.asax全局程序文件:

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> void Application_Start( object sender, EventArgs e)
{

// 控制器与spring整合
System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory
(
typeof (woodigg.bll.Handler.SpringControllerFactory));
}

你可能感兴趣的:(.net,mvc,企业应用,asp.net,asp)