7天学会MVC——第1天

时间:2022-03-14 19:09:31

原文地址
这是我在CodeProject上面看到的一篇文章,这里是我翻译的中文版,如果有任何翻译不恰当之处,还望各位不吝赐教!

本文将带领大家在7天内逐步学习MVC5——第1天
下载源码

简介

  正如文章标题所承诺的一样——“7天学会MVC”——本系列文章一共有7篇,一天一篇。那么,挑选一个舒适的星期一开始阅读本系列文章,在一周结束的时候,你就会将使用MVC的新技能收入囊中了!
  
  第1天基本上是热身的内容。我们将会尝试着去理解,为何选择ASP.NET MVC而不是Web Forms?Web Forms存在哪些问题?我们也会围绕Controller和Views进行两个实验。
  


7天学会MVC——第1天

  每次实验完成之后,我们都会进行一个小小的问答环节,讨论一些关于实验中涉及的概念。因此,本文的行文结构都是在每个实验环节之后跟随了一个问答环节。
  如果关于任何实验,你有疑问在问答环节中没有得到解答,欢迎进入原文地址进行提问。

学习使用ASP.NET MVC之前我们需要准备什么

  我们需要的只是Visual Studio,幸运的是Visual Studio完全免费。如果没有的朋友可以在http://www.visualstudio.com下载Visual Studio。

ASP.NET与MVC与WebForms之间比较

“你在阅读本文,说明你了解 ASP.NET,并且想让自己掌握MVC相关知识”

  如果各位亲爱的读者认同上面这句话,那么,本节内容您一定不能错过。

  许多ASP.NET开发人员在第一次接触MVC的时候,都认为MVC跟ASP.NET完全不一样,是全新的技术。事实上,ASP.NET是创建web application的框架,而MVC是一种非常棒的代码构架方式,让我们的代码拥有更好的层次结构。因此,与其说MVC,不如说ASP.NET MVC。

  好,如果说ASP.NET MVC是新技术,那么言外之意老技术是什么呢?答案是:“ASP.NET Web Forms”。

让我来更正你的认知:
  “你在阅读本文,说明你了解ASP.NET Webforms,并且想让自己掌握ASP.NET MVC相关知识”。

  现在你的认知已经正确,欢迎来到ASP.NE T MVC的世界,让我们开始我们的旅程吧。

为何使用ASP.NETWebForms?

  ASP.NET Webfroms已经成功地为web application服务了12年。让我们来试着了解,Webforms如此流行和成功背后的秘密。

  如果你从VB时代就开始见证了微软编程语言的成功,你应该知道这都归功于RAD(Rapid Application Development)快速应用程序开发和可视化编程方法。可视化编程是如此地普及和成功,微软简单直白地将它的IDE命名为“Visual Studio”。


7天学会MVC——第1天

  使用Visual Studio,开发人员可以通过“拖拽”UI元素的方式创建前端界面,在后端Visual Studio会为这些UI元素自动生成相应的C#或者VB代码。这些代码术语叫做“Behind Code”或者“Code Behind”,在这些后置代码中,开发人员可以书写逻辑代码操作UI元素。

7天学会MVC——第1天

  微软的可视化RAD构架由两部分组成,其一是UI元素,其二是后置代码。在ASP.NET Webforms中有ASPX文件和ASPX.CS文件,在WPF中有XAML文件和XAML.CS文件。

ASP.NET Web Forms的一些问题

  既然ASP.NET Webforms如此成功,为何微软要推出ASP.NET MVC呢?ASP.NET最大问题在于效率、效率还是效率!在web application中,效率主要体现在两个方面

- 1.响应时间:服务器响应请求有多快呢?
- 2.带宽消耗:发送了多少数据?

响应时间的问题

  让我们尝试着去理解为何ASP.NET Webforms的响应时间会更长,我们做了一个小小的加载时间测试的实验,加过显示ASP.NET MVC网站的加载时间为ASP.NET Webforms网站加载时间的一半!


7天学会MVC——第1天
点击 这里了解我们如何进行测试

  让我们试着去理解为何ASP.NET MVC在上述的加载测试中有更高的效率。下面是一段简单的UI代码和它的后置代码。
  假设ASPX代码有下面这个简单的textbox。

<asp:TextBox ID="TextBox1" runat="server">

  在后置代码中,书写一些逻辑代码操作text box的值和背景色

protected void Page_Load(object sender , EventArgs e)
{
TextBox1.Text = "Make it simple ";
TextBox1.BackColor = Color.Aqua;
}

  运行代码,HTML效果如下:


7天学会MVC——第1天

  上面的HTML效果,和以下代码的运行结果相似:

<input name="TextBox1" type="text" value="Make it simple" id="TextBox1" style="background-color:Aqua" />

  现在我们停一会儿,闭上眼思考以下问题:

- 1.这是一种高效率的生成HTML的方式吗?为了在浏览器上获得这些简单的HTML,我们真的需要翻山越岭地去请求服务器吗?
- 2.开发人员就不能直接书写HTML吗?这有这么难吗?
-


7天学会MVC——第1天

  仔细观察网页的每一次请求,你会发现存在着一个将服务器端控件转换为HTML输出的转换逻辑。当HTML中有Grid、TreeView等等控件,或者有复杂的表格的时候,转换逻辑将变得糟糕和笨重。由于这种不必要的转换,响应速度变慢。

  解决方法:“远离后置代码”,挽起衣袖来书写纯HTML代码吧!

带宽消耗

  Viewstate对于ASP.NET开发人员,可以说是超过10年的亲密朋友了。Viewstate自动帮我们保存本次post back 和上次post back的状态,节省了开发时间。但是,在节省时间的同时,也带来了巨大的消耗,viewstate让页面的大小增大了相当多。在加载测试里面我们发现,viewstate让页面大小增加了一倍,相比ASP.NET MVC。

  下图展示了Webform和ASP.NET MVC发出的内容的长度:


7天学会MVC——第1天

  由于viewstate产生了额外的字节,使得内容大小增加,下图是viewstate的截图。许多朋友会说,可以禁用viewstate。但是只要存在可能性,开发人员一定会找出解决的途径!


7天学会MVC——第1天

  解决方案:“远离服务器控件 !”
  提示:接下来列出的三个其他问题,也是由于后置代码和服务器控件带来的问题,但是最重要的永远是效率!

HTML定制

  现在我们都是后置代码和ASP.NET服务器控件的奴隶,我们完全不知道会产生什么样的HTML以及其效率如何。例如,你可以猜测一下,以下的ASPX代码会产生什么样的HTML:

<asp:Label ID="Label1" runat="server" Text="I am label">
<asp:Literal ID="Literal1" runat="server" Text="I am a literal">
<asp:Panel ID="Panel1" runat="server">I am a panel

  Label控件会生成DIV标签或者SPAN标签吗?运行上面的代码,你会发现Label生成了SPAN标签,Literal生成纯文本,Panel生成DIV等等。

  与其用服务器控件生成HTML,不如直接书写HTML然后全权掌控呢?

  因此这个问题的解决方案是:“不要使用服务器控件”,直接书写HTML。

  直接和HTML打交道的另外一个巨大的好处是,网站UI和开发团队可以很“近距离”地合作。他们可以使用最喜欢的设计工具来比如Dream Weaver、front page等等,来开发HTML代码。如果我们使用了服务器控件,这些设计工具可能就不能轻易地识别它们了。

后置代码类的可重用性

  如果你观察任何专业的ASP.NET Webform工程,你会发现在后置代码类中存在着大量的复杂的代码。页面的后置代码类继承自“System.Web.UI.Page”类,这个类并不像普通的类可以在任何地方重用和实例化,也就是说,你永远不可能对一个Webform类完成下述代码:

WebForm1 obj = new WebForm1();
obj.Button1_Click();

  因为“WebForm”类不能在没有“请求”和“响应”对象存在的情况下被实例化。如果你曾经见过“WebForm”的“Button_Click”事件,它们应该类似下述代码。从代码中你就可以知道要实例化同样的对象多么困难。

protected void Button1_Click(object sender,EventArgs e)
{
//The logic which you want to reuse and invoke
}

  解决方案:“远离服务器控件和后置代码”

单元测试

  正如前文所述,你不能直接实例化后置代码,因此想对其做单元测试和自动测试十分困难,你需要手动运行程序进行测试。

如何解决?

  如果你阅读了前文提到的四个关于ASP.NET WebFrom的问题,你会知道,罪魁祸首就是“服务器控件”和“后置代码”。下图是我对问题根源做出的图解,我从问题表象开始,分析其出现的原因和解决方案,最后整个图解都汇集到“服务器控件”和“后置代码”两个家伙的身上。


7天学会MVC——第1天

  解决这些问题,我们需要将后置代码转移到独立的简单类库中,同时远离服务器控件,直接和简单的HTML打交道。
  简而言之,我们需要的解决方案应该达到如下效果:

7天学会MVC——第1天

微软ASP.NET MVC如何解决Web Forms中的问题?

  如前文所述,服务器控件和后置代码是问题的根源。如果你观察当下开发人员使用的WebFrom构架,你会发现它们大多数都是3层构架的方式。3层构架包含了一个UI层,UI层包含了ASPX和CS代码。

  这个UI层和.NET类也就是中间层(或者说业务逻辑层)打交道,中间层和数据访问层(DAL)打交道。


7天学会MVC——第1天

  ASP.NET MVC由三个部分组成:Model,View,Controller。后置代码逻辑在Controller中,View就是ASPX也就是纯HTML,Model就是中间层。你可以在上图中看到它们如何分工合作。
  我们可以看到,主要有两个方面的改变:View变成了单纯的HTML,后置代码变成了简单的.NET类也就是Controller。

  在ASP.NET MVC中,请求流转过程如下:
  ● Step 1:请求首先到达Controller
  ● Step 2:Controller根据请求创建相应的Model对象,Model对象访问数据访问层获取数据。
  ● Step 3:Model中的数据传输到View中进行展示。


7天学会MVC——第1天

  
  既然我们已经了解了ASP.NET MVC中不同的组件,我们就开始深入了解它们吧,还是用一些实验作为引子。我们从Controller开始,因为Controller是MVC构架中最重要也是核心的部分。

理解ASP.NET MVC中的Controller?

  为了理解Controller我们首先要理解用户交互逻辑。

什么是用户交互逻辑?

场景1
  你是否思考过,当用户在浏览器中输入URL地址的时候,都发生了什么?


7天学会MVC——第1天

  浏览器向服务器发出请求,服务器响应请求。

7天学会MVC——第1天

  同坐这样的请求方式,客户端尝试着和服务器端进行交互。服务器之所以能够对请求做出响应,是因为服务器中存在着一些处理逻辑。

一些处理逻辑?到底是什么逻辑?
  处理用户请求和用户跟服务器交互的逻辑,也就是用户交互逻辑。

场景2
  服务器发出的响应内容也可能是单纯的HTML响应,HTML响应可以由一些input控件和一个submit button按钮组成。


7天学会MVC——第1天

  当点击“SaveCustomer”按钮的时候会发生什么?
  如果你的回答是:“一些事件处理句柄会处理点击事件”,那么,非常抱歉。
  “在网络应用程序里面,根本就没有‘事件’这个概念。由于微软的ASP.NET Webforms为我们写了一些代码,导致我们感觉像是在做‘事件驱动式’编程一样,其实这只是一种空想或者说是幻觉。”

  当按钮被点击的时候,只是发送了一个简单HTTP请求到服务器,随同请求一起发送还有“Customer Name”、“Address”、“Age”的值(术语叫做“values are posted to the server”)。总之,要想服务器对请求做出响应,服务器端必须有相应的处理逻辑,也就是用户交互逻辑必须在服务器端书写好。
  在ASP.NET MVC中,C字母代表Controller,也是处理用户交互逻辑的模块。

实验1-用Hello World来演示Controller

  
Step 1-创建 Asp.Net MVC5 工程
  Step1.1 打开Visual Studio2013(或者更高版本)。点击 文件>>新建>>工程


7天学会MVC——第1天

  
  Step1.2 选择Web Application,输入名字,选择路径,点击OK。

7天学会MVC——第1天

  Step1.3 选择MVC模块

7天学会MVC——第1天

  Step1.4 点击“Change Authentication”,选择“No Authentication”,点击ok。

  Step1.5 点击OK。
  
Step 2-创建Controller
  Step 2.1 在解决方案资源管理器中右击Controller文件夹,选择添加>>控制器


7天学会MVC——第1天

  Step 2.2 选择“空MVC5控制器”,点击添加


7天学会MVC——第1天

  
  Step 2.3 将控制器命名为“TestController”点击添加。
  在这一步中,非常重要的一点是不要将后面的“Controller”删掉,你可以将其看做一个保留关键字。
  
Step 3-创建Action 方法
  打开新创建的TestController类。你会发现里面有个Index方法。删掉它,新加一个“GetString”的public方法,如下:

public class TestController : Controller
{
public string GetString()
{
return "Hello World is old now. It&rsquo;s time for wassup bro;)";
}
}

  
Step 4 运行并测试
  按下F5,在浏览器地址栏输入“ControllerName/ActionName”,如下图所示。不要输入“Controller”单词,只要输入“Test”即可。


7天学会MVC——第1天

关于实验1的问答

TestController和Test之间有什么关系?

  TestController是类名而Test是控制器的名称,请记住,在输入URL的时候,输入控制器名称就好,不要加上Controller。
  
  Asp.Net MVC遵循基于约定的方法,严格地遵循我们使用的约定。

  在Asp.Net MVC中两个事情非常重要:
  1.如何命名?
  2.如何放置?
  

什么是Action方法?

  Action方法只是Controller内部的一个public方法,用来接收用户的请求然后返回一些响应。在上面的例子中,action方法“GetString”返回一个string类型的响应。

  提示:在Asp.Net Webforms中,默认的响应返回总是HTML。如果我们要返回其他的内容,我们新建HTTP handlers,重写content类型,调用 response.end()等等,这些都不是轻松地事情。在Asp.Net MVC中要做到这些很轻松,如果返回类型是string,你可以就返回string,你不需要发送完整的HTML。
  

当我们尝试用action方法返回object的时候,会发生什么?

  看看下面的代码段

namespace WebApplaction1.Controllers
{
public class Customer
{
public string CustomerName{get;set;}
public string Address{get;set;}
}
public class TestController : Controller
{
public Customer GetCustomer()
{
Customer c =new Customer();
c.CustomerName="Customer 1";
c.Address="Address1";
return c;
}
}
}

  上面action方法的输出如下:


7天学会MVC——第1天

  当返回类型为类似“Customer”的对象时,会返回该对象对‘ToString()’方法的实现。默认的‘ToString()’方法会返回完整的类名,也就是“NameSpace.ClassName”。
  

如果你想在上例中获得其属性值,该如何做?

  只需要重载“ToString”方法即可:

public override string ToString()
{
return this.CustomerName+"|"+this.Address;
}

  按下F5,输出如下:


7天学会MVC——第1天
  

是否必须在action方法前面加上public访问修饰符?

  是的,每一个public方法都会自动成为action方法。
  

非public方法有什么含义?

  它们只是类内部的非public的方法而已,简单地说,它们不能web调用。
  

如果我们想要一个非action方法的public方法,该怎么做?

  只需要加上NonAction特性即可,如下:

[NonAction]
public string SimpleMethod()
{
return "Hi, I am not a action method";
}

  当我们试着去访问上面的方法的时候,会得到如下的响应:


7天学会MVC——第1天
  
  

理解ASP.NET MVC中的Views

  从之前的讨论中,我们知道Controller会处理用户的请求和发送响应,最通常的响应是HTML,浏览器能够更好的理解这种格式。HTML会带有一些images,texts,input控件等等。一般而言的UI层,在Asp.Net MVC 中就是View层。
  
  

实验2-演示Views

  在第一个实验中,我们创建了一个简单的MVC应用,只有一个controller以及返回简单的string类型,让我们着手该MVC应用的View部分吧。

Step1-新建 action method

  在TestController中添加新的action方法,如下:

public ActionResult GetView()
{
return View("MyVeiw");
}

Step2-创建View

  Step2.1 右键点击上面的action方法,选择“添加视图”


7天学会MVC——第1天

  Step2.2 在“添加视图”对话框中,将视图名称改为MyView,取消“使用母板页”的选项,点击“添加”.

7天学会MVC——第1天

  之后,系统会在“View/Test”文件夹中添加该视图。

7天学会MVC——第1天

  
  

Step 3-向视图中添加内容

  打开MyView.cshtml文件,添加如下内容:

@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>MyView</title>
</head>
<body>
Welcome to MVC 5 Step by Step learning
</body> </html>

Step 4-运行测试

  按下F5运行程序,输出如下:


7天学会MVC——第1天

  

关于实验2的问答

为什么视图被放到了Test文件夹

  在ASP.NET MVC中,View和特定的Controller相关联,并且被放置在特定的文件夹里面。这个特定的文件夹将会以“ControllerName”来命名,并且放置在View文件夹下。对于每一个Controller,只有放在相对应的文件夹中的View才可以被访问。

  例如:所有跟Test Controller相关的Views都会被放置到“~/Views/Test”,Test Controller只能访问Test文件夹中的Views。

我们不能在多个Controllers中重用一个View吗?

  可以,将这些视图放在“Shared”文件夹中即可。


7天学会MVC——第1天

  Shared文件夹中的view可以被所有Controller访问。

一个action方法可以引用多个view吗?

  可以,如下:

public ActionResult GetView()
{
if(Some_Condition_Is_Matching)
{
return View("MyView");
}
else
{
return View("YourView");
}
}

View功能的目的是什么?

  创建ViewResult对象,渲染响应的HTML视图
  ●ViewResult内部创建ViewPageActivator对象
  ●ViewResult选择正确的ViewEngine,将ViewPageActivator作为参数传递给ViewEngine的构造函数。
  ●ViewEngine创建View类的对象
  ●ViewResult调用View的RenderView方法
  提示:我们有单独的讨论ASP.Net MVC的生命周期细节的话题。

ActionResult和ViewResult的关系是什么?

  ActionResult是抽象类,ViewResult是ActionResult的多层子类。多层是由于ViewResult是ViewResultBase的子类,ViewResultBase是ActionResult的子类。

如果我们想要返回ViewResult,为何ActionResult是ViewResult?

  为了实现多态性,如下:

public ActionResult GetView()
{
if(Some_Condition_Is_Matching)
{
return View("MyView");
}
else
{
return Content("Hi Welcome");
}
}

  在上面的例子中,当某些条件满足的时候,我们在返回的时候调用“View”函数,返回ViewResult,在其他的条件中,我们调用“Content”函数返回ContentResult。

什么是ContentResult?

  ViewResult呈现了完整的HTML响应,而ContentResult呈现了纯文本响应,就像返回string类型一样。不同之处在于,ContentResult是针对ActionResult的string类型结果的包装,ContentResult也是ActionResult的子类。

可以无参数调用View函数吗?

  可以,那样的话,View函数将会找到以当前“ActionName”命名的View。

第2天将会学习什么?

  第二天我们将会谈到Models,Validation,JQuery,Json。
  让我们一起学习,一起嗨!