asp.net的MVC编程、MV编程以及URL重写

 前一段时间做一个网站项目,使用win2003+.net2.0开发;在学习了一些.net的相关知识后,并考虑到此项目需要多人合作,以及架构清晰、URL重写等优点,决定用MVC方式开发。但微软的.net MVC框架据说要下半年才出正式版,而且还需要.net3.5,其他的MVC框架又不熟悉,估计也需要一段时间学习。由于开发时间比较紧,我们开发小组中也没有一个对.net及.net MVC框架非常熟悉的人,所以又想转回使用传统的.net编程方式开发。

  在两难之际,我想也许可以在项目需求出来前,自己试着写一个MVC架构出来,因为以前曾用PHP和JSP写过类似的MVC架构,而Web的运行环境和编程语言,相通的地方还是很多的,于是就有了下面这个.net的MVC架构。

  一、MVC编程:

  针对用户的浏览器来说,网站可以看作一个实体、一个接口,其接收浏览器的请求,并将相应的信息返回给浏览器;因此,网站程序完全可以用一个程序来完成,而实际上也确实如此,IIS、apache等web服务器本身就是一个程序,而运行其中的asp、aspx、php、jsp、html等等的单个页面,只不过是帮助web服务器来实现一定功能而已。

  由此可以引申出:我们完全可以用一个aspx页面来处理针对网站的所有动态请求。

  而这个页面,我们就把它起名为index.aspx吧。

  在apache、tomcat等web服务器,都有相应的技术,将网站符合一定规则的所有http请求,都转向一个程序页面(如index.jsp或index.php)来处理。而IIS在IIS7(前面提到,我们的网站服务器是windows2003,IIS版本为6.0)出来以前,只能借助于第三方组件实现。这其中比较有名的2个是ISAPI_Rewrite(Full版收费,Lite版免费)和IonicIsapiRewriter(免费),而对于我们这个MVC架构来说,ISAPI_Rewrite Lite版(这里有ISAPI_Rewrite Lite版的下载,我们使用的是ISAPI_Rewrite3_0047_Lite.msi)就足够了,由它来控制请求到我们的index.aspx。

  首先需要确定一下网站的目录结构。为了使图片、css文件、js文件、html文件等免于ISAPI_Rewrite处理,需在网站根目录建立一个单独的mvc目录,其中存放MVC架构需要的aspx文件,从而网站的目录结构如下:

       ROOT
  |--App_Code
  |--DotNetMVC
  |--DAL
  |--UserDA.cs
  |--Model
  |--User.cs
  |--Util
  |--ControllerUtil.cs
  |--DBUtil.cs
  |--Bin
  |--log4net.dll
  |--css
  |--images
  |--js
  |--mvc
  |--application
  |--controllers
  |-default.aspx
  |-user.aspx
  |--views
  |--default
  |-index_view.aspx
  |--share
  |--user
  |-home_view.aspx
  |-list_view.aspx
  |--cache
  |--log
  |-index.aspx
  |-Default.aspx
  |-Global.asax
  |-web.config

  上面的结构中,css、images、js放什么文件分别存放站点用的样式文件、图片文件、javascript脚本文件;Bin存放公共组件(目前有一个日志组件log4net.dll,其配置信息在web.config配置文件中),App_Code存放自定义的公共类,这是.net2.0规定的,mvc目录的作用上面说了,不再赘述。

  下面说说App_Code和mvc下的子目录构成:

  App_Code->Util目录,存放一些实用工具类,目前有2个,DBUtil.cs是SQLServer数据库处理工具类,而ControllerUtil.cs则是我们这个MVC架构比较核心的URL路由工具类,其中ParseUri方法解析URI返回控制器、控制分支、参数等,LinkTo方法产生需要的网站链接URL(具体代码参见DotNetMVC示例网站代码)。大家还可以在其中添加一些需要的功能,如上传、Email、字符串、分页、图形处理等。

  而App_Code->DAL和App_Code->Model目录中的内容一起组成MVC架构中M层逻辑,其中Model目录的仅仅是数据库表的数据抽象类(这些类可以自己写,也可以通过工具结合数据库表自动生成),DAL目录中的类则通过访问数据库返回数据抽象类的对象实例或实例列表,供控制层调用。

  mvc根目录下的index.aspx文件,如上所述是MVC架构的入口文件。

  mvc->cache和mvc->log目录分别存放缓存文件和日志文件,如果需要的话。

  mvc->application目录中的controllers目录和views目录分别是控制器文件和视图文件,即MVC架构中的C和V层,其中一个控制器对应一个aspx文件(如user.aspx),并在views目录中有一个视图子目录对应(如views->user),其中存放多个此控制器可能用到的视图文件(如home_view.aspx和list_view.aspx等);views->share目录中,则是一些视图文件可能用到的公共文件,如头尾包含页、母板页等。

  目录结构介绍完了,下面介绍单个的程序文件:

  前面曾经提到,要把所有针对本站点的动态请求,都统一到index.aspx这个文件来集中处理,因此需要借助ISAPI_Rewrite,在ISAPI_Rewrite Lite的配置文件httpd.conf(位于ISAPI_Rewrite Lite的安装目录)中增加下面一条记录即可:

  RewriteRule /mvc/(.*)$ /mvc/index.aspx/?idu=$1 [NC,NE]

  这条规则是将针对/mvc这个URI及其后的所有访问,都导向到index.aspx这个文件来处理,并将URI路径作为idu参数的值传给index.aspx。

  下面看看index.aspx文件的内容:

<%@ Page Language="C#" %>
<%@ import namespace="System.Threading" %>
<%
     string controller;
     string method;
     string[] parameters;
     string uri_string = Request.QueryString["idu"];
     DotNetMVC.Util.ControllerUtil.ParseUri(uri_string, out controller, out method, out parameters);

     Context.Items.Add("method", method);
     Context.Items.Add("parameters", parameters);
    
     string ctlpage = "system/application/controllers/" + controller + ".aspx";
     try
     {
         Server.Transfer(ctlpage, true);
     }
     catch (HttpException e)
     {
         log4net.LogManager.GetLogger("LogFile").Error("/r/n客户机IP:" + Request.UserHostAddress + "/r/n错误地址:" + Request.Url, e);
     }
%>

  上面代码的关键是,通过对idu值的解析,取得controller、method、parameters这3个参数;其中controller对应于一个控制器文件,method对应控制器中的一个控制分支,parameters则是参数的字符串数组(参数顺序自己把握),其对应URI如下:

  /mvc/controller/method/parameter1/parameter2/parameterN

  目前这个MVC架构的URI,都是一个控制器,后跟一个分支,再后跟多个参数,如果没有controller、method、parameters,则默认调用default控制器的index分支,如果没有method、parameters,则默认调用本控制器的index分支;如果以上不满足要求,大家可以自己更改ControllerUtil类的ParseUri方法。Server.Transfer方法的第2个参数为true,是确保request、cookie、session等变量能够传递到控制器程序中。

  下面通过default.aspx这个控制器(可以一个功能或一个模块作为一个控制器)说明一下控制器的流程:

<%@ Page Language="C#" %>
<%@ import namespace="DotNetMVC.Util" %>
<%
string method = (string)Context.Items["method"];
string[] parameters = (string[])Context.Items["parameters"];
try
{
     if (method == "index")
     {
         Context.Items.Add("loginurl", ControllerUtil.LinkTo("user", "login", ""));
         Context.Items.Add("userlisturl", ControllerUtil.LinkTo("user", "list", ""));
         Server.Execute("application/views/default/index_view.aspx");
     }
}
catch (HttpException e)
{
     log4net.LogManager.GetLogger("LogFile").Error("/r/n客户机IP:" + Request.UserHostAddress + "/r/n错误地址:" + Request.Url, e);
}
%>

  上面代码中,首先通过Context获取index.aspx中得到的method、parameters参数,然后根据method值的不同,走不同的处理分支(这里可以调用M层获取数据)产生数据并保存在Context(目前仅找到用Context来传递数据到视图)中,再调用不同的视图;这里只有一个默认index分支,去调用首页视图index_view.aspx。

  最后看看views->default目录下index_view.aspx这个视图文件内容:

<%@ Page Language="C#" EnableViewStateMac="false"%>
<%
     string loginurl = (string)Context.Items["loginurl"];
     string userlisturl = (string)Context.Items["userlisturl"];
%>
<!-- #include file="../share/top.aspx" -->
<center>
<form name=frm1 method=post action=<%=loginurl %>>
昵称:<input type=text name=nick size=20>&nbsp;&nbsp;
密码:<input type=password name=pass size=20>
<input type=submit value=登陆> &nbsp;<a href=<%=userlisturl %>>去用户列表</a>
</form>
</center>
<!-- #include file="../share/bottom.aspx" -->

  这个视图文件中的代码则通过Context接收控制器传过来的数据并显示它。

  至此,整个MVC的运转流程就完成了;其他更复杂的一些操作,大家可以参照DotNetMVC示例网站代码,相信根据这个示例,就可以直接建立并快速开发自己的MVC网站了,并有URL重写功能;在其中的user控制器及视图中,大家可以看到这种编程有一个好处,那就是可以充分利用visual studio的代码智能感知功能。

  不过,有一点需要大家注意,因为需要经过ISAPI_Rewrite过滤器与Transfer、Execute处理,所以会有一些性能损失。根据流程的复杂程度,其损失所占比重会有所不同:越复杂的流程,其损失所占比重越小,越简单的流程,其损失所占比重越大;所以大家在用这套流程开发网站时,应充分注意这一点,并适当进行程序优化,或者干脆别用它了。

  二、MV编程:

  大家在看上面的DotNetMVC示例网站代码的时候,肯定有一个感觉:在控制层产生数据,要赋给Context,视图层再从Context中取出数据来显示,似乎多此一举;所以引出下面的MV编程(可能会丧失一些灵活性和可维护性,但开发一般的网站应该足够了)。

  我们只需要把DotNetMVC示例网站代码中的代码简单做一下修改就可以了。

  首先,修改index.aspx如下:

<%@ Page Language="C#" %>
<%@ import namespace="System.Threading" %>
<%
     string controller;
     string method;
     string[] parameters;
     string uri_string = Request.QueryString["idu"];
     DotNetMVC.Util.ControllerUtil.ParseUri(uri_string, out controller, out method, out parameters);

     Context.Items.Add("method", method);
     Context.Items.Add("parameters", parameters);

     string ctlpage = "application/views/" + controller + "/" + method + ".aspx";
     try
     {
         //Server.Transfer(ctlpage, true);
         Server.Execute(ctlpage);
     }
     catch (HttpException e)
     {
         log4net.LogManager.GetLogger("LogFile").Error("/r/n客户机IP:" + Request.UserHostAddress + "/r/n错误地址:" + Request.Url, e);
     }
%>

  这里直接用controller和method组合出视图路径,并用Server.Execute去执行它(因为Server.Transfer总是抛出System.Threading.ThreadAbortException异常,虽然不影响运行,这似乎是asp.net的一个小问题)。

  然后删除控制器目录的内容,并将控制器页面中的代码转移到视图中即可,具体请参看DotNetMV示例网站代码。这样,既减少了编程复杂度,又增加的开发效率和运行性能,同时URL重写和代码智能感知等优点仍然得以保留。

  附:

  下载DotNetMVC示例网站代码和DotNetMV示例网站代码到本地后,请注意示例网站代码是一个完整的网站架构,大家可以直接在VS中建立一个新网站(VS2005和VS2008),清空VS自动产生的内容,然后将代码拷入即可,根据实际修改web.config文件;运行调试前,请先安装ISAPI_RewriteLite,并修改其配置文件;调试时,请注意修改站点的“启动选项”使用本地IIS,因为VS中的DevelopWebServer无法加载ISAPI_Rewrite过滤器。

  另外,测试数据表建立脚本给出如下:

CREATE TABLE [dbo].[users](
     [id] [int] IDENTITY(1,1) NOT NULL,
     [nick] [varchar](50) COLLATE Chinese_PRC_CI_AS NULL,
     [pass] [varchar](20) COLLATE Chinese_PRC_CI_AS NULL,
     [reg_date] [datetime] NULL CONSTRAINT [DF_test_inputdate]   DEFAULT (getdate())
) ON [PRIMARY]
时间: 2024-07-31 05:20:53

asp.net的MVC编程、MV编程以及URL重写的相关文章

asp.net2.0使用正规表达式建立URL重写

asp.net A new feature in Asp.Net 2.0 is it's built-in url rewriting support. When i looked into this new feature i found out it lacked regular expressions support, wich is really the point of an Url Mapper. ScottGlu at his blog, explains the reason w

ASP.NET技巧:慎用url重写

asp.net|技巧     为了使url地址更加友好(当然可能有别的原因),很多站点使用了url重写,如http://www.cnblogs.com/life,在asp.net中通常要处理这样的url重写,必须在IIS中将*.*映射到aspnet_isapi.dll(C:\WINDOWS\Microsoft.NET\Framework\v1.1.432\aspnet_isapi.dll),然后在web.config进行相应的配置,最后在写相应的处理程序,多数情况我们是那么做的,搏客园也是那么做

关于asp.net下Url重写问题?

问题描述 1.你好,请问一下,asp.net下RewritePath是否只能进行aspx网页的重写,比如,一个站点(http://jd.abc.com)要被写为http://jd.abc.com/fff/index.asp,行不?,其中fff这是一个目录,它放了一下小的asp网站?行吗?2.在写Url重写过程中,请问有什么方法能直接对请求(HttpApplication.Request.Url属性进行重写,赋给新的值,达到当IIS在处理请求前将请求包中的Url改变成想要的Url?谢谢. 解决方案

基于asp.net的百度地图API编程

问题描述 基于asp.net的百度地图API编程 在地图上的给某个覆盖物添加事件,点击这个覆盖物后出现信息框,信息框的数据从数据库里读出. 解决方案 http://developer.baidu.com/map/jsdemo.htm#d0_2http://developer.baidu.com/map/jsdemo.htm#d0_1http://developer.baidu.com/map/jsdemo.htm#d0_4http://developer.baidu.com/map/jsdemo

asp.net的三层结构在编程的过程中怎么体现?

问题描述 asp.net的三层结构在编程的过程中怎么体现? 我理解的是:在"设计"处布局按钮什么的,在按钮的事件里写方法.主要以前见老师给的网上书店里还有什么book类,comment类了,我不是很理解,因为有文章说asp.net天然是三层,我理解的对吗?求大牛告知. 解决方案 关于ASP.NET的三层结构关于ASP.NET的三层结构ASP.NET中的三层结构 解决方案二: 其实三层不止是三层 我们都称作是三层架构而已 还有Model实体层 和Utility工具层 用于添加实体 你的B

asp.net中使用vb.net编程读取oracle数据库

问题描述 asp.net中使用vb.net编程读取oracle数据库 小弟刚学asp.net现在数据库连接完成,我在某一列插入了数据,我想在页面中读取出来,我使用的代码为 Dim sqlStr As String = "select*from AGVNEW1 where agvId" Dim myCmd As OracleCommand = New OracleCommand(sqlStr, myconnection) myCmd.Parameters.Clear() myCmd.Pa

我是学asp.net. 现在都不知道学编程该怎么学了.?

问题描述 我是学asp.net.现在都不知道学编程该怎么学了.? 解决方案 解决方案二:选择了就不要放弃!解决方案三:多做项目就知道了解决方案四:你以前怎么学??解决方案五:引用2楼xutao888的回复: 多做项目就知道了 解决方案六:我建议学习下架构!解决方案七:我也是初学者,我想应该多做项目吧,在这其中你会慢慢的碰到学多的问题,自然就会感觉有所收获了..解决方案八:1.webcontrols和htmlcontrols2.验证控件(正则表达式很重要的)3.Session,Cookie,Vie

《windows应用高级编程-C#编程篇》书中程序的小问题及改进

window|编程|程序|高级|问题 清华大学出版社<windows应用高级编程-C#编程篇>,2003年1月第1版,Benny Johansen & Matthew Reynolds等著,张哲峰译,在第八章文件操作中的一个记事本小程序,有三个小问题,其中两个同性质问题问题一:StreamReader streamReader=new StreamReader(fileStream); 当打开的文件是中文字符时,会出现乱码.当打开文件的同时,将读取的文件内容转化为StreamReade

使用shieldUI Chart控件在ASP.NET和MVC应用程序中创建一个销售仪表板

本文中,我们将处理一个常见的数据可视化任务,即创建一个销售仪表板 (dashboard).在商业演示中经常会使用销售仪表板来展现某个商业流程或商业 目标的关键绩效指标,而完成这样一个演示的关键不仅在于对数据进行良好的可 视化展示,还要有赏心悦目的外观.为了完成这一任务,我会使用相关的图表组 件,它提供了全部的所需功能.这个示例中将使用ShieldUI中的图表组件,这一 系列产品可以从网站的免费下载. 完成后的展示请见下图: 本示例将使用ASP.NET与MVC两种方式讲解. 使用代码 ASP.NE