7 天学习 MVC 项目 – 第 1 天






4.86/5 (499投票s)
在本篇文章中,我们将学习 MVC 5,循序渐进,共 7 天 - 第1天
目录
- 引言
- 进行 ASP.NET MVC 需要准备什么?
- ASP.NET vs MVC vs WebForms
- 为什么选择 ASP.NET Web Forms?
- ASP.NET WebForms 的问题
- 解决方案是什么?
- Microsoft ASP.NET MVC 如何解决 WebForms 中的问题?
- 理解 ASP.NET MVC 中的 Controller?
- 理解 ASP.NET MVC 中的 Views
- 实验1 - 通过一个简单的 hello world 演示 Controller
- 关于实验1 的问答环节
- 实验2 - 演示 Views
- 关于实验2 的问答环节
- 第2天有什么内容?
- 2天学会 MVC(16小时)
完整系列
引言
正如标题所承诺的,“7 天学会 MVC,循序渐进”,所以本文将包含 7 篇文章,即每天一篇。所以,从一个愉快的星期一开始阅读这个教程系列,并在周末成为一名 MVC 专家。
第1天可以算作热身。在第一天,我们将理解为什么选择 ASP.NET MVC 而不是 Webforms?Webforms 的问题,我们将进行两个实验,一个围绕 Controller,另一个围绕 Views。
在每个实验之后,我们将进行一个简短的问答环节,讨论实验中的概念。所以本文的结构是实验,然后是问答。
如果您对任何未在问答环节中解答的实验有疑问,请随时在下面的评论框中提出。我们一定会回答,并且如果发现这些问题反复出现,我们也会将其包含在文章中,以便其他社区成员从中受益。
所以我们只需要您 7 天的时间,剩余的本文将确保您成为一名 ASP.NET MVC 开发者。
进行 ASP.NET MVC 需要准备什么?
我们只需要 Visual Studio,好消息是 Visual Studio 是完全免费的。您可以从 http://www.visualstudio.com/ 下载 Visual Studio 社区版,没有过期,没有许可问题,也不需要花费巨资。
ASP.NET vs MVC vs WebForms
“您阅读本文是因为您了解 ASP.NET 并想升级到 MVC。”
抱歉打扰,请您重新阅读以上陈述,如果您认为它是正确的,那么这一部分是您必读的。
许多 ASP.NET 开发者第一次接触 MVC 时,认为 MVC 与 ASP.NET 不同、新颖、全新。但事实是,ASP.NET 是一个创建 Web 应用程序的框架,而 MVC 是一种组织和安排代码的优秀架构。所以,与其说是 MVC,不如说是 ASP.NET MVC。
好的,如果新事物是 ASP.NET MVC,那么旧事物叫什么呢?它叫做“ASP.NET Webforms”。
让我纠正一下您的词汇
“您阅读本文是因为您了解 ASP.NET Webforms 并想升级到 ASP.NET MVC。”
现在您的词汇已经纠正,欢迎来到 ASP.NET MVC 的世界,让我们开始这个教程。
为什么选择 ASP.NET Web Forms?
ASP.NET Webforms 在过去 12 年中一直成功地交付 Web 应用程序。让我们尝试理解 Webforms 如此受欢迎和成功的原因。
如果您看看从 VB(Visual Basic)时代开始,微软编程语言的成功,那是因为 RAD(快速应用程序开发)和可视化编程方法。可视化编程在微软得到了广泛的推广和成功,因此他们将 IDE 命名为“Visual Studio”。
通过使用 Visual Studio,开发人员可以在设计器区域中拖放 UI 元素,后端,Visual Studio 会为这些元素生成 C# 或 VB.NET 代码。这些代码被称为“后台代码”或“Code Behind”。在后台代码中,开发人员可以编写逻辑来操作 UI 元素。
因此,微软的可视化 RAD 架构包含两部分:一部分是 UI,另一部分是后台代码。对于 ASP.NET WebForms,您有 ASPX 和 ASPX.CS;对于 WPF,您有 XAML / XAML.CS 等等。
ASP.NET Web Forms 的问题
既然 ASP.NET Webform 如此成功,为什么微软还要考虑创建 ASP.NET MVC?ASP.NET Webform 的主要问题是性能,性能,还是性能。在 Web 应用程序中,有两个方面定义了性能
- 响应时间:服务器响应请求的速度有多快?
- 带宽消耗:发送了多少数据?
响应时间问题
让我们尝试理解为什么 ASP.NET Webforms 的响应时间会变慢。我们进行了 Webform 与 ASP.NET MVC 的小型负载测试实验,发现 ASP.NET MVC 的速度快了两倍。
请在此处 阅读更多关于如何进行此测试。
让我们尝试理解为什么 ASP.NET MVC 在上述负载测试中性能更好。考虑下面的简单 UI 代码以及该 UI 的后台代码。
假设 ASPX 代码包含以下简单的 textbox
。
<asp:TextBox ID="TextBox1" runat="server">
在后台代码中,您编写了一些逻辑来操作 textbox
的值和 background
颜色。
protected void Page_Load(object sender, EventArgs e)
{
TextBox1.Text = "Make it simple";
TextBox1.BackColor = Color.Aqua;
}
运行上述程序后,下面的 HTML 输出是这样的。
通过查看源代码,您会发现 HTML 输出如下所示。
<input name="TextBox1" type="text"
value="Make it simple" id="TextBox1"
style="background-color:Aqua;" />
现在暂停阅读片刻,闭上眼睛思考。尝试回答以下问题:
- 这是生成 HTML 的有效方式吗?我们真的需要进行那些漫长的服务器往返才能在浏览器上获得简单的 HTML 吗?
- 开发人员不能直接编写 HTML 吗?有那么难吗?
对于每次请求,都有一个转换逻辑在运行,将服务器控件转换为 HTML 输出。当有网格、树视图控件等复杂 HTML 表格时,这种转换会变得越来越糟和沉重。由于这种不必要的转换,响应时间会受到影响。
此问题的解决方案:“摆脱后台代码”,卷起袖子,用纯 HTML 工作。
带宽消耗
在过去的 10 年里,Viewstate
一直是 ASP.NET 开发者的好朋友,因为它可以在回发之间自动保存状态并减少我们的开发时间。但这种开发时间的减少是以巨大的代价换来的,viewstate
显著增加了页面大小。在这个 负载测试 中,我们发现 viewstate
使页面大小增加了两倍,与 ASP.NET MVC 相比。
下面是 Webform 和 ASP.NET MVC 发出的内容长度的图表。
大小增加是因为 viewstate
生成了额外的字节,下面是 viewstate
的快照。很多人会争辩说 viewstate
可以被禁用,但我们都知道开发人员是什么样的,如果提供了选项,他们肯定会尝试使用。
此问题的解决方案:“摆脱服务器控件”。
注意:下面的其余三点是由后台代码和服务器控件引起的次要问题。但主要问题始终是性能。
HTML 自定义
现在,由于我们是后台代码和 ASP.NET Web 服务器控件的奴隶,我们“完全不知道”会生成什么样的 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
标签?如果您运行上面的代码,下面的分别是生成的 HTML。Label
生成 SPAN
,Literal
生成纯文本,Panel
生成 DIV
标签,以此类推。
<span id="Label1">I am label</span>
I am a literal
I am a panel
所以,与其通过服务器控件生成 HTML,不如直接编写 HTML 并完全控制 HTML。
因此,此问题的解决方案是“不要使用服务器控件”,直接使用 HTML 工作。
直接使用 HTML 的另一个巨大好处是,您的 Web 设计师可以与开发团队紧密合作。他们可以获取 HTML 代码,在他们喜欢的 Dream Weaver、Front Page 等设计工具中进行操作,并独立设计。如果我们有服务器控件,这些设计工具就无法轻松识别它们。
后台代码类的可重用性
如果您观看任何专业的 ASP.NET Webform 项目,您会注意到后台代码类包含了大量的代码,并且代码非常复杂。现在这个后台代码页面类继承自“System.Web.UI.Page
”类。这个类不是一个可以被重用和实例化的普通类。换句话说,对于 Webform
类,您永远无法做到如下所示
WebForm1 obj = new WebForm1();
obj.Button1_Click();
因为“WebForm
”类在没有“request
”和“response
”对象的情况下无法实例化。如果您曾经见过“WebForm
”的“ButtonClick
”事件,它们如以下代码所示。从代码中,您可以知道实例化它的难度。
protected void Button1_Click(object sender, EventArgs e)
{
// The logic which you want to reuse and invoke
}
此问题的解决方案:“摆脱服务器控件和后台代码”。
单元测试
如上一节所述,您无法直接实例化后台代码,很难对后台代码进行单元测试或自动化测试。必须手动运行应用程序并进行测试。
解决方案是什么?
如果我们阅读上一节提到的 ASP.NET Webforms 的四个问题,主要罪魁祸首是两样东西:“后台代码”和“服务器控件”。下面是我绘制的根本原因图。在此图中,我从问题开始,然后是原因,最后是解决方案。整个图谱聚焦于两件事:“后台代码”和“服务器控件”。
解决方案是将后台代码移到一个单独的简单类库,摆脱 ASP.NET 服务器控件,编写简单的 HTML。
简而言之,解决方案应该如下图所示
Microsoft ASP.NET MVC 如何解决 Web Forms 中的问题?
如前所述,后台代码和服务器控件是问题的根本原因。因此,如果您查看开发人员目前使用的 WebForm 体系结构,它主要是三层架构。这个三层架构包括 UI,它有 ASPX 和 CS 后台代码。
这个 UI 与 .NET 类通信,您可以称之为中间层、业务逻辑等,中间层与数据访问层通信。
因此,ASP.NET MVC 包含三个部分 - Model、View 和 Controller。后台代码逻辑被放入 Controller。View 是您的 ASPX,即纯 HTML,而 Model 是您的中间层。您可以在上图中看到这些层是如何契合的。
所以,如果您看,有两个主要的改变:View 变成简单的 HTML,后台代码转移到简单的 .NET 类,称为 Controller。
在 ASP.NET MVC 中,请求流通常如下所示:
步骤 1:第一次点击到达 Controller。
步骤 2:根据操作,Controller 会创建 Model 对象。Model 再调用数据访问层,数据访问层将数据获取到 Model 中。
步骤 3:然后将填充了数据的 Model 传递给 View 进行显示。
现在我们已经理解了 ASP.NET MVC 的不同组件,让我们深入了解每个组件,让我们开始做一些实验。让我们先从 Controller 开始,因为它们是 MVC 架构中最重要的中心部分。
理解 ASP.NET MVC 中的 Controller?
为了理解 Controller,我们首先需要理解“用户交互逻辑”这个术语。
什么是用户交互逻辑??
场景 1
您是否曾经考虑过当最终用户在浏览器中输入 URL 时会发生什么?
浏览器发送请求到服务器,服务器发送响应。
通过这种请求,客户端试图与服务器交互。服务器能够响应是因为服务器端编写了一些逻辑来满足这个请求。
一些逻辑??那么这个逻辑究竟是什么?
处理用户请求和用户与服务器交互的逻辑。简而言之,用户交互逻辑。
场景 2
服务器发送的响应也可能是一个 HTML 响应。HTML 响应可能包含几个输入控件和一个提交按钮。
当单击“保存客户”按钮时会发生什么?
如果您的答案是“某个事件处理程序将处理按钮单击”,那么很抱歉 :-(。
“在 Web 编程的现实世界中,不存在事件的概念。在 ASP.NET Web Forms 的情况下,微软替我们编写了一些代码,让我们体会到了事件驱动编程的感觉。这只是一种抽象,或者更准确的说法是幻觉。”
单击按钮时,会向服务器发送一个简单的 HTTP 请求。这次的区别是,“客户姓名”、“地址”和“年龄”中的值将随请求一起发送。(技术上讲,“值被发布到服务器”)。最终,如果这是一个请求,那么服务器端必须编写一些逻辑,以便服务器能够发送响应。简而言之,服务器端必须有一些用户交互逻辑。
在 ASP.NET MVC 中,最后一个字母 C,即 Controller,就是处理用户交互逻辑的。
实验 1 - 通过一个简单的 MVC Hello World 演示 Controller
步骤 1 - 创建 ASP.NET MVC 5 项目
步骤 1.1 - 打开 Visual Studio 2013(或更高版本)。点击 文件 >> 新建 >> 项目。
步骤 1.2 - 选择 Web 应用程序。输入 名称。输入 位置,然后点击 确定。
步骤 1.3 - 选择 MVC 模板。
步骤 1.4 - 点击 更改身份验证。在“更改身份验证”对话框中选择“无身份验证”并点击 确定。
步骤 1.5 - 点击 确定。
步骤 2 - 创建 Controller
步骤 2.1 - 在解决方案资源管理器中,右键单击 controller 文件夹,然后选择 添加 >> Controller。
步骤 2.2 - 选择“MVC 5 Controller - Empty”并点击 添加。
步骤 2.3 - 将 Controller 名称设置为“TestController
”并点击 添加。
在这个步骤中有一个非常重要的点需要注意,不要删除“controller”这个词。目前,您可以认为它是一个保留关键字。
步骤 3 - 创建 Action Method
打开新创建的 TestController
类。您会在其中找到一个名为“Index
”的方法。删除该方法,然后添加一个名为“GetString
”的新的 public
方法,如下所示:
public class TestController : Controller
{
public string GetString()
{
return "Hello World is old now. It’s time for wassup bro ;)";
}
}
步骤 4 - 执行和测试
按 F5。在地址栏中,输入“ControllerName/ActionName”,如下所示。请注意,不要输入“Controller”这个词,只需输入“Test”。
关于实验1 的问答环节
TestController 和 Test 之间是什么关系?
TestController
是类名,而 Test
是 Controller 名称。请注意,当您在 URL 中输入 Controller 名称时,不应包含“controller”一词。
ASP.NET MVC 遵循约定驱动的方法。它严格遵守我们使用的约定。
在 ASP.NET MVC 中,两件事非常重要:
- 我们如何命名?
- 我们把东西放在哪里?
什么是 Action Method?
Action
方法只是 Controller 中的一个 public
方法,它接受用户的请求并返回一些响应。在上面的例子中,action
方法“GetString
”返回一个 string
响应类型。
注意:在 ASP.NET Web Forms 中,默认返回响应始终是 HTML。如果我们想返回 HTML 以外的内容(在 ASP.NET Web Forms 中),我们需要创建 HTTP handlers,覆盖 Content Type,执行 response.end
等等。这并非易事。在 ASP.NET MVC 中,这非常简单。如果返回类型是 'string
',您可以直接返回 string
:-) ,您不需要发送完整的 HTML。
如果我们尝试从 Action Method 返回一个对象会发生什么?
看下面的代码块:
namespace WebApplication1.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 method 的输出将如下所示:
当返回类型是像‘customer
’这样的对象时,它将返回该对象的‘ToString()
’实现。默认情况下,‘ToString()
’方法返回类的完全限定名,即“NameSpace.ClassName
”。
如果您想获取上面示例中属性的值怎么办?
只需像这样覆盖类的“ToString
”方法:
public override string ToString()
{
return this.CustomerName+"|"+this.Address;
}
按 F5。输出将如下所示:
Action Methods 必须用 Public 访问修饰符来装饰吗?
是的,每个 public
方法都会自动成为 action methods。
非公共方法呢?
它们只是类的方法,不对外公开。简单来说,这些方法无法从 Web 调用。
如果我们希望一个方法是公共的但不是 Action Method 怎么办?
只需用 NonAction
属性来装饰它,如下所示:
[NonAction]
public string SimpleMethod()
{
return "Hi, I am not action method";
}
当我们尝试请求上述 action method 时,我们将收到以下响应:
理解 ASP.NET MVC 中的 Views
正如我们之前讨论过的,Controller 将处理用户的请求并发送响应。最常见的是,响应是 HTML,因为浏览器更能理解这种格式。HTML 包含一些图像、文本、输入控件等。通常在技术领域,定义用户界面设计被称为 UI 层,而在 ASP.NET MVC 中,它被称为 View。
实验2 - 演示 Views
在第一个实验中,我们创建了一个只有 Controller 和简单 string
返回类型的简单 MVC 应用程序。让我们去给 MVC 应用程序添加 View 部分。
步骤 1 - 创建新的 Action Method
在 TestController
中添加一个新的 action method,如下所示:
public ActionResult GetView()
{
return View("MyView");
}
步骤 2 - 创建 View
步骤 2.1. 右键单击上面的 action method,然后选择“添加视图”。
步骤 2.2. 在“添加视图
”对话框中,将视图名称设置为“MyView
”,取消选中“使用布局”复选框,然后点击“添加”。
这将在解决方案资源管理器中的“Views/Test”文件夹内添加一个新的视图。
步骤 3 - 向 View 添加内容
打开 MyView.cshtml 文件并添加以下内容:
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>MyView</title>
</head>
<body>
<div>Welcome to MVC 5 Step by Step learning.</div>
</body>
</html>
步骤 4 - 测试和执行
按 F5 并执行应用程序。
关于实验2 的问答环节
为什么 View 放在 Test 文件夹内?
在 ASP.NET MVC 中,与特定 Controller 相关的 Views 放在一个特殊文件夹中。这个特殊文件夹的名称将是“ControllerName
”,并放置在Views文件夹(位于根文件夹)中。对于每个 Controller,只有位于其自己文件夹内的 Views 才可用。
例如:所有与 Test controller 相关的 Views 都将放置在“~/Views/Test”中,并且 Test controller 只能访问 Test 文件夹内的 Views。
不能跨多个 Controller 重用一些 Views 吗?
可以。为此,我们将把这些文件放在一个名为“Shared”的特殊文件夹中。
位于此 Shared 文件夹内的 Views 将可供所有 Controller 使用。
一个 Action Method 是否可以引用多个 View?
是的。看下面的代码:
public ActionResult GetView()
{
if(Some_Condition_Is_Matching)
{
return View("MyView");
}
else
{
return View("YourView");
}
}
注意:在 ASP.NET 中,MVC Views 和 Controllers 之间没有紧密耦合。一个 action method 可以引用多个 view,一个 view 也可以被多个 action method 引用(通过将它们放在 Shared 文件夹中)。这提供了更好的可重用性。
View 函数的目的是什么?
创建 ViewResult
对象,该对象将 View
渲染到响应中。
ViewResult
内部创建ViewPageActivator
对象。ViewResult
选择正确的ViewEngine
并将ViewPageActivator
对象作为参数传递给ViewEngine
的构造函数。ViewEngine
创建View
类的对象。ViewResult
调用View
的RenderView
方法。
注意:在本系列中,我们有一个单独的主题详细讨论 ASP.NET MVC 的生命周期。
ActionResult 和 ViewResult 之间有什么关系?
ActionResult
是 abstract
类,而 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
”函数,它将返回 Content Result。
什么是 ContentResult?
ViewResult
代表一个完整的 HTML 响应,而 ContentResult
代表一个标量文本响应。它就像返回纯 string
。区别在于 ContentResult
是 string
结果的 ActionResult
包装器。ContentResult
也是 ActionResult
的子类。
是否可以不带参数调用 View 函数?
是的,然后它会查找名为“CurrentActionName
”的视图。
第2天有什么内容?
第二天,我们将讨论 Models、Validation、Jquery 和 Json。所以继续加油,继续学习。
2天学会 MVC(16小时)
我们两位作者发起了一个倡议,2天学会 MVC,即满打满算 16 小时。以下是该视频:
如需进一步阅读,请观看下面的面试准备视频和逐步视频系列。
- ASP.NET MVC 面试题及答案
- C# 面试题及答案
- Angular 面试题及答案
- 一步步学习 Azure
- 逐步学习MVC 5
- MVC Core 分步教程
- 一步步学习 SQL Server
- ASP.NET 中的 Session 和 Viewstate
历史
- 2015年1月17日:初始版本