`
happmaoo
  • 浏览: 4309577 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

在ASP.NET中实现Model-View-Controller模式(一)

阅读更多
在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中实现Model-View-Controller

    返回页首实现策略为了解释如何在ASP.NET中实现Model-View-Controller模式,并说明在软件中分离模型、视图和控制器角色的好处,下面的示例将一个没有分离所有三个角色的单页面解决方案重构为分离这三个角色的解决方案...

    ASP.NET Core: Cloud-ready, Enterprise Web Application Development

    ASP.NET Core MVC helps you build robust web applications using the Model-View-Controller design. This guide will help you in building applications that can be deployed on non-Windows platforms such ...

    asp.net mvc视频1-2

    MVC架构模式是近年来编程世界里最长被提及的模式之一,Model View Controller(模型-视图-控制器,MVC)模式将你的软件组织并分解成三个截然不同的角色: ◆Model封装了你的应用数据、应用流程和业务逻辑。 ◆View从...

    信息系统开发与实践项目 图书管理系统 大学编程作业(TUST 天津科技大学 2023 年)

    本图书管理系统,我使用了 ASP.NET MVC(Model-View-Controller)架构来制作,使用了 Visual Studio 2022 作为开发环境,使用了 C# 编程语言进行开发,使用了 Razor 页面模板引擎。实现了让管理员能够快速添加、查看...

    ASP.NET设计模式-杨明军译(源码)

    《asp.net设计模式》涵盖了开发企业级asp.net应用程序的知名模式和最佳实践。本书用到的模式可以用于从asp.net1.0到asp.net 4.0的任何版本。不必管模式本身所用的语言,可以将模式用于任何面向对象编程语言。  ...

    ASP.NET MVC in Action

    ASP.NET MVC implements the Model-View-Controller pattern on the ASP.NET runtime. It works well with open source projects like NHibernate, Castle, StructureMap, AutoMapper, and MvcContrib. ASP.NET MVC...

    professional asp.net mvc 3 PDF

    Shows developers and programmers how to use ASP.NET MVC 3, Microsoft's new version of its Model-View-Controller technology for developing dynamic, data-driven web sites Features an expert author team...

    ASP.NET-MVC-Framework-Unleashed

    The ASP.NET MVC framework enables you to build web applications ... The Model View Controller pattern encourages a clear separation of concerns. The framework encourages good software design patterns.

    Programming Microsoft ASP.NET MVC, 3rd Edition

    Web development expert Dino Esposito takes you through the web framework’s Model-View-Controller (MVC) design model, and covers the tools you need to cleanly separate business logic from the user ...

    Professional ASP.NET MVC 3

    Shows developers and programmers how to use ASP.NET MVC 3, Microsoft's new version of its Model-View-Controller technology for developing dynamic, data-driven web sites Features an expert author ...

    [ASP.NET MVC] ASP.NET MVC 1.0

    ASP.NET MVC 1.0 provides a new Model-View-Controller (MVC) framework on top of the existing ASP.NET 3.5 runtime; ☆ 文件清单:☆ ASP.NET MVC 1.0.7z ☆ 相关网址:☆ ASP.NET MVC 1.0 主页网址: ...

    [ASP.NET MVC 小牛之路] 文章系列

    一、[ASP.NET MVC 小牛之路]01 - 理解MVC模式 二、[ASP.NET MVC 小牛之路]02 - C#知识点提要 三、[ASP.NET MVC 小牛之路]03 - Razor语法 四、[ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject 五、[ASP.NET MVC ...

    Asp.net MVC2 Preview2

    ASP.NET MVC Framework是微软在ASP.NET中所添加的一组类别库,这组类库可利用Model-View-Controller的设计模式来开辟ASP.NET的应用法度圭臬标准    Model:包含数据、验证规定规矩、数据接见和营业逻辑等应用...

    Learning ASP.NET Core MVC Programming

    ASP.NET Core MVC helps you build robust web applications using the Model-View-Controller design. This guide will help you in building applications which can be deployed on non-windows platforms such ...

    简明 ASP.NET Core 手册

    MVC (Model-View-Controller) 模式的基本内容 前端代码(HTML、CSS、JavaScript)怎样与后端代码交互 什么是依赖注入以及它的实用之处 如何进行数据库的读写操作 如何添加 登录、注册功能,以及如何提升安全性 如何...

    ASP.NET_Core-Elastic_APM-Docker:该项目在Docker上为单页ASP.NET核心应用程序(Model-View-Controller)设置了Elastic APM

    Docker中的ASP.NET Core Web应用程序+弹性APM Docker是一组平台即服务(PaaS)产品,它们使用操作系统级虚拟化来以称为容器的程序包交付软件。 容器彼此隔离,并将它们自己的软件,库和配置文件捆绑在一起; 他们...

    Professional ASP.NET MVC 2

    A new update to Microsoft’s Model-View-Controller technologies, MVC 2 enables developers to build dynamic, data-driven Web sites. Professional ASP.NET MVC 2 shows you step-by-step how to use MVC 2. ...

    Professional ASP.NET MVC 5

    Jon Galloway, Brad Wilson, K. Scott Allen, David Matson ...Professional ASP.NET MVC 5 is the comprehensive resource you need to make the best use of the updated Model-View-Controller technology.

Global site tag (gtag.js) - Google Analytics