在ASP.NET中实现Model-View-Controller模式(一)
背景: 当利用ASP.NET创建Web应用程序时,基于程序的复杂性,必须把程序分割成不同的部分以减少代码的重复及减少日后变革时所引起的改动。 实现策略:
为了解释如何在ASP.NET中实现(MVC)模型-视图-控制器模式,以及说明将软件分离成模型、视图、及控制器角色的好处,在此以一个示例程序为例进行说明。这个示例程序是一个带有下拉框的单页程序,它的功能是显示数据库中的数据。如下图。
当用户在下拉框中选择了一个记录,并单击Submit按钮的时候,程序从数据库中搜索与选中记录相关的数据库记录,并以列表的形式显示出来。下面,将以三种不同的实现方式进行实现。
单页模式
在ASP.NET中有许多解决这个问题的办法,其中最简单也是最直接的办法就是把所有的代码都放到一个文件中,并起名为Solution.aspx,实现代码如下: <%@ImportNamespace="System.Data"%> <%@ImportNamespace="System.Data.SqlClient"%> <html> <head> <title>start</title> <scriptlanguage="c#"runat="server"> voidPage_Load(objectsender,System.EventArgse) { StringselectCmd="select*fromRecording";
SqlConnectionmyConnection= newSqlConnection( "server=(local);database=recordings;Trusted_Connection=yes"); SqlDataAdaptermyCommand=newSqlDataAdapter(selectCmd, myConnection);
DataSetds=newDataSet(); myCommand.Fill(ds,"Recording");
recordingSelect.DataSource=ds; recordingSelect.DataTextField="title"; recordingSelect.DataValueField="id"; recordingSelect.DataBind(); }
voidSubmitBtn_Click(Objectsender,EventArgse) { StringselectCmd= String.Format( "select*fromTrackwhererecordingId={0}orderbyid", (string)recordingSelect.SelectedItem.Value);
SqlConnectionmyConnection= newSqlConnection( "server=(local);database=recordings;Trusted_Connection=yes");
SqlDataAdaptermyCommand=newSqlDataAdapter(selectCmd, myConnection);
DataSetds=newDataSet(); myCommand.Fill(ds,"Track");
MyDataGrid.DataSource=ds; MyDataGrid.DataBind(); } </script> </head> <body> <formid="start"method="post"runat="server"> <h3>Recordings</h3> SelectaRecording:<br/> <asp:dropdownlistid="recordingSelect"runat="server"/> <asp:buttonrunat="server"text="Submit"OnClick="SubmitBtn_Click"/> <p/> <asp:datagridid="MyDataGrid"runat="server"width="700" backcolor="#ccccff"bordercolor="black"showfooter="false" cellpadding="3"cellspacing="0"font-name="Verdana" font-size="8pt"headerstyle-backcolor="#aaaadd" enableviewstate="false"/> </form> </body> </html>
这个实现文件包含了模型、视图、控制器这三种角色,但是没有将它们分割为不同的文件或类。其中的视图对象用HTML实现,用一个数据绑定控件来显示从数据库返回的DataSet中的数据。模型角色在Page_Load和SubmitBtn_Click函数中实现。而控制器角色并没有显式的实现,而是由ASP.NET隐式实现。程序运行时,当用户发出页面的请求,页面随着用户的选择更新。 在ASP.NET中实现Model-View-Controller模式(二) MVC模式形容这种实现方式是一种被动的实现机制,ASP.NET充当了程序执行中的控制器的角色,但程序员必须将具体的事件处理方法添加到事件的响应函数中。如在这个例子中,控制器在页面加载之前调用Page_Load函数并执行其中的代码,当用户点击Submit按钮时由系统调用SubmitBtn_Click函数并执行。
这种将代码都包含在一个文件中的实现方式非常的直接,而且当应用程序很小并不经常修改的时候也可以说是一种好的方法,但是如果下面的一些情况出现的话你也许会开始考虑修改这种实现方法:
使编程的工作并行并减少由此带来的发生错误的可能性。为了增加工作的并行性,提高效率,你可能想让不同的人编写视图的代码及模型代码并尽力减少这种工作方式所带来的出错的可能性。例如:当所有的代码都在一个文件中的话,那么一个编程人员可能会在改变DataGrid显示格式的时候无意中修改数据访问的代码。这种错误是很难被发现的,直到页面整体被编译的时候才会显现出来。。
使你的数据访问代码在其它页面中重用。在这种单文件的实现方式中,除了拷贝代码,没有其它的方法能够做到代码的重用。拷贝的代码是很难被维护的,因为一旦代码发生了变化,你必须在所有的页面都进行修改。
为了避免上面这些情况的发生,ASP.NET引入了代码分离(Code-behind)机制。
用代码分离机制进行重构 MicrosoftVisualStudio.NET中的代码分离机制使视图层的代码与模型及控制器的代码能够很容易的分离。每个ASP.NET页面都有一种机制,能够使其要调用的方法在一个与其分离的类中实现。这种方式使用起来非常的方便,而且也可以利用VisualStudio.NET中的一些其它特性共同完成开发工作。比如如当你利用代码分离的机制开发你的页面的时候,可以利用智能感知(IntelliSensetechnology)显示出一个可用方法的列表方便编程。而智能感知技术在.aspx页面中是不能使用的。
下面给出的是上面例子利用代码分离机制的实现。
视图部分:
视图层的代码现在一个单独的文件中实现。Solution.aspx:
<%@Pagelanguage="c#"Codebehind="Solution.aspx.cs" AutoEventWireup="false"Inherits="Solution"%> <html> <head> <title>Solution</title> </head> <body> <formid="Solution"method="post"runat="server"> <h3>Recordings</h3> SelectaRecording:<br/> <asp:dropdownlistid="recordingSelect"runat="server"/> <asp:buttonid="submit"runat="server"text="Submit" enableviewstate="False"/> <p/> <asp:datagridid="MyDataGrid"runat="server"width="700" backcolor="#ccccff"bordercolor="black"showfooter="false" cellpadding="3"cellspacing="0"font-name="Verdana"font-size="8pt" headerstyle-backcolor="#aaaadd"enableviewstate="false"/> </form> </body> </html> 大部分代码都与前面的解决方案的代码相同。主要的不同点是第一行: <%@Pagelanguage="c#"Codebehind="Solution.aspx.cs" AutoEventWireup="false"Inherits="Solution"%>
这行告诉ASP.NET执行环境,这个页面的具体实现机制在一个单独的类中。因为这个页面是独立的,因此如果数据访问的代码发生变化,这个页面并不需要做任何改动。同样,一些设计师也可以改变这个页面的代码而不会引起任何数据访问的错误。
在ASP.NET中实现Model-View-Controller模式(三)
模型及控制器部分: 这个解决方案的第二个部分是被隐藏的后台代码: usingSystem; usingSystem.Data; usingSystem.Data.SqlClient;
publicclassSolution:System.Web.UI.Page { protectedSystem.Web.UI.WebControls.Buttonsubmit; protectedSystem.Web.UI.WebControls.DataGridMyDataGrid; protectedSystem.Web.UI.WebControls.DropDownListrecordingSelect;
privatevoidPage_Load(objectsender,System.EventArgse) { if(!IsPostBack) { StringselectCmd="select*fromRecording";
SqlConnectionmyConnection= newSqlConnection( "server=(local);database=recordings;Trusted_Connection=yes"); SqlDataAdaptermyCommand=newSqlDataAdapter(selectCmd,myConnection);
DataSetds=newDataSet(); myCommand.Fill(ds,"Recording");
recordingSelect.DataSource=ds; recordingSelect.DataTextField="title"; recordingSelect.DataValueField="id"; recordingSelect.DataBind(); } }
voidSubmitBtn_Click(Objectsender,EventArgse) { StringselectCmd= String.Format( "select*fromTrackwhererecordingId={0}orderbyid", (string)recordingSelect.SelectedItem.Value);
SqlConnectionmyConnection= newSqlConnection( "server=(local);database=recordings;Trusted_Connection=yes"); SqlDataAdaptermyCommand=newSqlDataAdapter(selectCmd,myConnection);
DataSetds=newDataSet(); myCommand.Fill(ds,"Track");
MyDataGrid.DataSource=ds; MyDataGrid.DataBind(); }
#regionWebFormDesignergeneratedcode overrideprotectedvoidOnInit(EventArgse) { // //CODEGEN:ThiscallisrequiredbytheASP.NETWebFormDesigner. // InitializeComponent(); base.OnInit(e); }
///<summary> ///RequiredmethodforDesignersupport-donotmodify ///thecontentsofthismethodwiththecodeeditor. ///</summary> privatevoidInitializeComponent() { this.submit.Click+=newSystem.EventHandler(this.SubmitBtn_Click); this.Load+=newSystem.EventHandler(this.Page_Load);
} #endregion }
这里将代码从上个实现方法单独的文件移动到了一个它自己的文件中。并通过一些机制把视图以及模型控制器这两个部分连接成一个整体,如这个类中的成员变量与Solution.aspx文件中所用的控件是同名的。另外一个必须显示指出的是控制器如何将行为与其所对应的事件进行连接。在这个例子中InitializeComponent函数连接了两个事件。第一个将Load事件与Page_Load函数连接,第二个是Click事件,当Submit按钮被点击时调用SubmitBtn_Click函数。
代码分离是一种将视图部分与模型及控制器部分相分离的一种优秀的机制。但当你想把分离出的后台的代码给其它页面重用时可能还是不足的。在技术上,将页面背后的代码复用是可行的,但随着你需要共享的页面的增加,把页面与后台代码相连接是很困难的。
在ASP.NET中实现Model-View-Controller模式(四) 模型-视图-控制器分离的重构 为了解决上面所遗留的问题,你必须将模型与控制器角色分离。 视图的实现代码与前部分相同。 模型 下面的代码例子使模型角色仅仅依赖于数据库,而不包含任何与视图相依赖的代码。 usingSystem; usingSystem.Collections; usingSystem.Data; usingSystem.Data.SqlClient;
publicclassDatabaseGateway { publicstaticDataSetGetRecordings() { StringselectCmd="select*fromRecording";
SqlConnectionmyConnection= newSqlConnection( "server=(local);database=recordings;Trusted_Connection=yes"); SqlDataAdaptermyCommand=newSqlDataAdapter(selectCmd,myConnection);
DataSetds=newDataSet(); myCommand.Fill(ds,"Recording"); returnds; }
publicstaticDataSetGetTracks(stringrecordingId) { StringselectCmd= String.Format( "select*fromTrackwhererecordingId={0}orderbyid", recordingId);
SqlConnectionmyConnection= newSqlConnection( "server=(local);database=recordings;Trusted_Connection=yes"); SqlDataAdaptermyCommand=newSqlDataAdapter(selectCmd,myConnection);
DataSetds=newDataSet(); myCommand.Fill(ds,"Track"); returnds; }
现在的代码只依赖于数据库,这个类是一个优秀的数据库的通道,它持有访问表或视图的所用的SQL语句,其它的代码调用一些方法来完成与数据库的交互。 控制器 这种重构方式利用代码隐藏机制,在负责数据访问的模型部分相对独立的情况下,由控制器负责事件与方法的控制工作。模型的任务很明确的,它仅返回一个DataSet对象。这种实现方式就像视图代码一样,不依赖于数据是如何从数据库中返回的。 usingSystem; usingSystem.Data; usingSystem.Collections; usingSystem.Web.UI.WebControls;
publicclassSolution:System.Web.UI.Page { protectedSystem.Web.UI.WebControls.Buttonsubmit; protectedSystem.Web.UI.WebControls.DataGridMyDataGrid; protectedSystem.Web.UI.WebControls.DropDownListrecordingSelect;
privatevoidPage_Load(objectsender,System.EventArgse) { if(!IsPostBack) { DataSetds=DatabaseGateway.GetRecordings(); recordingSelect.DataSource=ds; recordingSelect.DataTextField="title"; recordingSelect.DataValueField="id"; recordingSelect.DataBind(); } }
voidSubmitBtn_Click(Objectsender,EventArgse) { DataSetds= DatabaseGateway.GetTracks( (string)recordingSelect.SelectedItem.Value);
MyDataGrid.DataSource=ds; MyDataGrid.DataBind(); }
#regionWebFormDesignergeneratedcode overrideprotectedvoidOnInit(EventArgse) { // //CODEGEN:ThiscallisrequiredbytheASP.NETWebFormDesigner. // InitializeComponent(); base.OnInit(e); }
///<summary> ///RequiredmethodforDesignersupport-donotmodify ///thecontentsofthismethodwiththecodeeditor. ///</summary> privatevoidInitializeComponent() { this.submit.Click+=newSystem.EventHandler(this.SubmitBtn_Click); this.Load+=newSystem.EventHandler(this.Page_Load);
} #endregion
在ASP.NET中实现Model-View-Controller模式(五)
测试 将模型部分从ASP.NET环境中分离出来能够使模型部分更容易的被测试。在ASP.NET环境中进行测试的话,你必须同时测试很多方面,如HTML代码是否正确,而读取HTML代码的工作是非常烦闷的。将模型部分分离出来,使你能够对模型部分做单独的单元测试。下面是NUnit(http://nunit.org)对模型部分进行单元测试的例子。 usingSystem;
usingNUnit.Framework; usingSystem.Collections; usingSystem.Data; usingSystem.Data.SqlClient;
[TestFixture] publicclassGatewayFixture { [Test] publicvoidTracks1234Query() {
DataSetds=DatabaseGateway.GetTracks("1234"); Assertion.AssertEquals(10,ds.Tables["Track"].Rows.Count); }
[Test] publicvoidTracks2345Query() { DataSetds=DatabaseGateway.GetTracks("2345"); Assertion.AssertEquals(3,ds.Tables["Track"].Rows.Count); }
[Test] publicvoidRecordings() { DataSetds=DatabaseGateway.GetRecordings(); Assertion.AssertEquals(4,ds.Tables["Recording"].Rows.Count);
DataTablerecording=ds.Tables["Recording"]; Assertion.AssertEquals(4,recording.Rows.Count);
DataRowfirstRow=recording.Rows[0]; stringtitle=(string)firstRow["title"]; Assertion.AssertEquals("Up",title.Trim()); } }
结论: 在ASP.NET中实现MVC模式有如下优缺点: 优势: 能够减少依赖。程序员可以在一个ASP.NET页面中实现所有的代码。单页的实现方式,对于一些小型的且生存周期不长的程序是适用的。但如果想在不断增加的页面间共享代码的话,将代码的不同部分进行分离是非常有效果的。 能够减少代码的复制。DatabaseGateway类中的GetRecordings和GetTracks方法能够直接被其它的页面使用,减少了必须将方法的代码拷贝到不同页面的情况。 能够把不同人员的责任分开。修改页面的外观与修改数据访问的代码所用的技术是不同的,将模型与视图分开能够使负责不同工作的专家协同的工作。 使性能优化的成为可能按将系统不同的职责分成不同的类,使性能的优化成为可能。前面的例子中,由于每次请求页面的时都要从数据库中读取数据。因此可在某种情况下将数据缓存,从而提高整个程序的性能。如果不将代码进行分离的话是无法做到的这点的。 易测试性将模型与视图相分离使在ASP.NET环境外进行单元测试成为可能。 缺点: 增加了代码的数量及复杂度。这个例子在早期单页的实现方式的基础上增加了新的文件和代码,在无形中增加了维护的开销。一旦修改系统的话,会修改所有三种角色的代码。在一些情况下,一个文件中的修改比一些文件中修改要方便。所以在考虑是否使用MVC模式时。这种额外的开销一定要被计算在内,对一些小的程序来说,这种开销是不值得的 |
相关推荐
通过本文的学习,我们可以了解到在ASP.NET MVC中如何通过`ViewData`和`TempData`实现Controller与View之间的数据传递。这两种方式各有特点,开发者可以根据实际需求选择合适的方法来满足应用的需求。在日常开发中,...
3. **MVC(Model-View-Controller)模式**:ASP.NET MVC 是一种轻量级、测试驱动的开发模式,分离了业务逻辑、数据和用户界面。它提供了更好的代码组织和测试能力。 4. **Web Forms**:是ASP.NET最初提供的开发模型...
ASP.NET还包括了ASP.NET MVC(Model-View-Controller)框架,这是一种流行的设计模式,鼓励分离关注点,提高代码可读性和可维护性。通过MVC,开发者可以更清晰地组织代码,更好地实现业务逻辑、数据访问和用户界面的...
这个新闻发布系统显然利用了ASP.NET的MVC(Model-View-Controller)模式或者Web Forms架构,这两种模式都可以有效地组织代码并分离业务逻辑、数据处理和用户界面。 用户登录和注册功能是任何具有用户权限管理系统的...
1. **ASP.NET MVC框架**:ASP.NET MVC(Model-View-Controller)是一种用于构建可测试和可维护的Web应用的模式。在这个博客系统中,MVC模式用于分离业务逻辑、数据模型和用户界面,使得代码结构清晰,易于维护。 2....
10. MVC模式:尽管ASP.NET 3.5主要关注Web Forms,但也会提及Model-View-Controller (MVC)架构,它是ASP.NET的一个重要补充,尤其适用于大型、复杂应用的开发。 通过学习《ASP.NET 3.5入门经典--涵盖C#和VB.NET(第5...
虽然ASP.NET最初是基于Web Forms模型,但后来引入了Model-View-Controller(MVC)架构。视频可能对比两种模式,解释各自的优点和适用场景。 【ASP.NET配置和部署】 视频也可能介绍如何配置ASP.NET应用程序,包括...
其次,ASP.NET提供了多种网页开发技术,包括ASP.NET Web Forms、ASP.NET MVC(Model-View-Controller)以及ASP.NET Core。Web Forms允许开发者使用拖放控件和事件驱动编程模式,类似于Windows桌面应用开发。MVC模式...
在ASP.NET框架下,TimeTracker1模板利用了MVC(Model-View-Controller)架构,这是一种广泛采用的软件设计模式,它将应用程序的业务逻辑、用户界面和数据访问分离开来,使得代码更加模块化,易于维护和扩展。...
ASP.NET提供了多种开发模型,包括Web Forms、MVC(Model-View-Controller)和Web API,每种模型都有其特定的应用场景和优势。 Web Forms是ASP.NET早期的主要开发模型,它允许开发者通过拖放控件的方式来创建用户...
3. **MVC(Model-View-Controller)模式**:介绍ASP.NET MVC框架,这是一种轻量级、测试驱动的开发模式,适用于构建可维护性和扩展性更强的Web应用。 4. **ASP.NET Core**:讲解ASP.NET Core,它是跨平台的开源版本...
另一个重要的概念是ASP.NET MVC(Model-View-Controller),这是一个设计模式,鼓励分离关注点,使得代码更加可维护和测试。MVC模式在ASP.NET中得到了很好的支持,开发者可以通过它构建更现代、更灵活的Web应用。...
MVC模式,全称为Model-View-Controller模式,是一种软件架构设计模式,最初由Trygve Reenskaug在20世纪70年代末期为Smalltalk平台提出。它主要用于简化程序结构,提高代码的复用性和维护性。 - **Model(模型)**:...
Asp.net的MVC(Model-View-Controller)架构模式使得代码组织清晰,便于维护和扩展。同时,Asp.net提供了诸如身份验证、授权等内置安全机制,对于OA系统的安全性有显著保障。"UDS"可能代表该OA系统的一个独特模块或...
3. **ASP.NET MVC**:ASP.NET MVC(Model-View-Controller)是一种设计模式,它将业务逻辑、数据和用户界面分离,提供了更灵活的开发方式。这部分可能涉及路由、控制器、视图和模型的概念,以及如何实现MVC模式来...
此外,教程中可能还会涉及ASP.NET的MVC(Model-View-Controller)模式,这是一种设计模式,它将业务逻辑、数据和用户界面分离,使代码更易于维护和扩展。 数据库访问是ASP.NET应用的常见需求,ADO.NET或Entity ...
它支持多种模式,如Web Forms、MVC(Model-View-Controller)和Web API,适用于不同类型的Web应用程序开发。 在Web Forms模式下,ASP.NET使用控件模型,允许开发者通过拖放方式在页面上添加和配置控件,这些控件在...
此外,ASP.NET MVC(Model-View-Controller)框架也在这一版本中首次亮相,为Web开发提供了一种模式驱动的方法。 静默安装版的.NET Framework 2.0-3.0-3.5是针对系统管理员或者自动化部署场景设计的,可以通过...