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

既然提到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 系列》。

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

以上图示的结构:
将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,版本不同接口也可能不一样):

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页的请求流程):

ContractedBlock.gif ExpandedBlockStart.gif web.config
<?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:

ContractedBlock.gif ExpandedBlockStart.gif Home.aspx
<%@ 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>
ContractedBlock.gif ExpandedBlockStart.gif Home.aspx.cs
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;

namespace mvcApp.Views.User
{
   
public partial class Home : ViewPage
    {
    }
}


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

ContractedBlock.gif ExpandedBlockStart.gif UserControllers.cs
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
{
   
public class 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目录中:

ContractedBlock.gif ExpandedBlockStart.gif controllers.xml
<?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一个很妙的设计):

 

 

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
ExpandedBlockStart.gifContractedBlock.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**//// <summary>
    
/// 控制器工厂
    
/// </summary>

    public class SpringControllerFactory : IControllerFactory
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**//// <summary>
        
/// 实现接口 
        
/// </summary>
        
/// <param name="context"></param>
        
/// <param name="controllerType"></param>
        
/// <returns></returns>

        public IController CreateController(RequestContext context, string name)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{           
            
if (File.Exists(ParameterFactory.CfgControllersFilePath))
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//配置上下文
                IApplicationContext configContext = new XmlApplicationContext(
                    ParameterFactory.CfgFilePath,
                    ParameterFactory.CfgBusinessFilePath,
                    ParameterFactory.CfgControllersFilePath,
                    ParameterFactory.CfgBusinessMediaFilePath
                    );                
                
//首字母大写的控制器名字
                string controllName = GetFirstUpcaseName(name) + "Controller";
                
//返回对应的对象:IOC                
                if(configContext.ContainsObject(controllName))
                    
return (IController)configContext.GetObject(controllName);
                
else
                    
return null;
            }

            
else
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                IControllerFactory fa 
= ControllerBuilder.Current.GetControllerFactory();
                
return fa.CreateController(context, name);
            }

            
        }


        
public void DisposeController(IController controller)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
        }


        
//首字母大写
        private string GetFirstUpcaseName(string name)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
string temp = name.Replace(".mvc","").ToLower();
            
string first = temp[0].ToString();
            
return temp.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全局程序文件:

 

void Application_Start( object sender, EventArgs e) 
{

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

 

转载于:https://www.cnblogs.com/moye/archive/2008/11/30/1344369.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值