在深刻了解ASP.NET Core MVC的细节以前,我想确保您熟悉MVC设计模式背后的思路以及将其转换为ASP.NET Core MVC项目的方式。 您可能已经了解本章中讨论的一些想法和约定,特别是若是您已经完成了高级ASP.NET或C#开发。 若是没有,我鼓励你仔细阅读 - 深刻地理解隐藏在MVC背后的东西能够帮助你在通读本书时更好地与MVC框架的功能联系起来。html
模型视图控制器模式起源于20世纪70年代后期,来自施乐PARC的Smalltalk项目,它被设想为组织一些早期的GUI应用程序。 原始MVC模式的一些细节与Smalltalk特定的概念(如屏幕和工具)有关,但更普遍的概念仍然适用于应用程序,而且它们特别适合于Web应用程序。程序员
在高层次上,MVC模式意味着MVC应用程序将被分红至少三个。数据库
模型 - MVC中的M - 包含用户使用的数据。有两种普遍的模型:视图模型,它们表明从控制器传递到视图的数据。领域模型:业务领域中的数据以及操做,转换和规则,用于建立、存储并操纵该数据,统称为模型逻辑。 模型是您的应用程序工做的环境的定义。例如,在银行应用程序中,该模型表示应用程序支持的银行中的全部内容,如账户、总账和客户的信用限额以及可用于存入资金并从帐户中提款等相似模型中数据的操做。该模型还负责保存数据的总体状态和一致性 - 确保全部事务被添加到客户不会比银行有权得到更多的钱或者比银行更多的钱提取更多的钱。 对于MVC模式中的每一个组件,我将描述它应该包括哪些东西和不该该包括哪些东西。json
使用MVC模式构建的应用程序中的模型应该:设计模式
模型不该该:浏览器
提示:许多刚接触MVC的开发人员对在数据模型中包含逻辑感到困惑,认为MVC模式的目标是将数据与逻辑分离。 这是一个误会:MVC模式的目标是将应用程序分红三个功能区域,每一个功能区域能够包含逻辑和数据。 目标不是消除模型中的逻辑。 而是确保模型只包含用于建立和管理模型数据的逻辑。架构
控制器是MVC模式中的结缔组织,用做数据模型和视图之间的通道。 控制器定义提供在数据模型上运行的业务逻辑的动做,并向用户提供查看显示的数据。框架
使用MVC模式构建的控制器应该是:工具
控制器不该该:布局
视图包含向用户显示数据或从用户捕获数据所需的逻辑,以即可以经过控制器操做进行处理。
视图应该:
视图不该该:
顾名思义,ASP.NET Core MVC将抽象MVC模式应用于ASP.NET和C#开发的世界。 在ASP.NET Core MVC中,控制器是C#类,一般派生自Microsoft AspNetCore.Mvc.Controller类。 从Controller派生的类中的每一个公共方法都是与URL相关联的行动方法。 当请求发送到与行动方法相关联的URL时,执行该行动方法中的语句,以便对域模型执行某些操做,而后选择要向客户端显示的视图。 图3-1显示了控制器,模型和视图之间的交互。
图3-1 控制器,模型和视图之间的交互。
ASP.NET Core MVC使用一种称为Razor的视图引擎,它是负责处理视图的组件,以便为浏览器生成响应。 Razor视图是包含C#逻辑的HTML模板,用于处理模型数据以生成响应模型更改的动态内容。 我将在第5章中解释Razor的做用。 ASP.NET Core MVC不会对领域模型的实现施加任何限制。 您可使用常规C#对象建立模型,并使用任何数据库,对象关联映射框架或.NET支持的其余数据工具来实现持久性。
固然,MVC不是惟一的软件架构模式。 还有不少其余的,其中有些是或至少已经很是受欢迎。 您能够经过查看替代方案了解有关MVC的许多内容。 在如下部分中,我简要介绍了构建应用程序的不一样方法,并将其与MVC进行对比。 一些模式与MVC有些许的差别,而另外一些则彻底不同。
我不是说MVC是最完美的模式。 我支持采起最佳方法解决手头问题。 有些状况下,某些模式与MVC同样好或可能更好。 我鼓励您在选择模式时作出明智的选择。 您正在阅读本书的事实代表,您已经决定使用MVC模式了,可是保持开阔的视野对你老是有好处的。
最多见的设计模式之一就是智能用户界面(smart UI)。大多数程序员在职业生涯中的某个时候建立了一个智能UI应用程序 - 我固然有。若是您已经使用Windows窗体或ASP.NET Web窗体,那么您也这样作了。 要构建一个智能UI应用程序,开发人员一般将一组组件或控件拖到设计表面或画布上构建用户界面。控件经过发出按钮按压,击键,鼠标移动等事件来报告与用户的交互。开发人员添加了一系列事件处理程序来响应这些事件的代码;这些是在发出特定组件上的特定事件时调用的小块代码。这将建立一个单片应用程序,如图3-2所示。处理用户界面和业务的代码都是混合在一块儿的,没有任何分离的问题。定义数据输入的可接受值而且查询数据或修改用户账户的代码最终以小部分结束,并按预期的顺序耦合在一块儿。
图3-2 Smart UI 模式
智能UI是简单项目的理想选择,由于您能够快速得到一些好的结果(相比之下,在MVC开发中,正如你将在第8章中看到的那样,须要在交付结果前进行大量的初始投资)。智能UI也适用于用户界面原型。这些设计UI工具能够真的很好,若是你和客户坐在一块儿,想要捕捉到外观和流程的要求,一个智能的UI工具能够快速有效地生成和验证不一样的想法。Smart UI最大的缺点是难以维护和扩展。混合领域模型和业务逻辑代码与用户界面代码致使代码冗余,其中相同的业务逻辑被复制和粘贴以支持新添加的组件。找到全部重复的部分并修复可能很困难。添加新功能而不会破坏现有的功能几乎是不可能的。测试智能UI应用程序也可能很困难,惟一的方法是模拟用户交互,那很是不理想,提供全面测试覆盖更是不太可能。 在MVC的世界中,Smart UI一般被称为反模式:应该不惜一切代价避免。这种反感来自,人们花了一半的职业生涯尝试开发和维护智能UI应用程序,后来结果却一团糟,后来人们才发现MVC是一个更好的方案。 个人意思是说,拒绝智能UI模式是错误的。Smart UI模式并不是都那么糟糕,它有好的方面。Smart UI应用程序快速且容易开发。组件和设计工具生产者已经为开发作出了很大的努力。开发体验是愉快的,甚至最无经验的程序员能够在短短几个小时内产生一些专业而又合理的东西。
Smart UI应用程序的最大弱点 - 可维护性 - 在小型开发工做中不会出现。 若是您正在为小客户制做一个简单的工具,Smart UI应用程序能够是一个很好的解决方案。 MVC应用程序太复杂太烦人。
在Smart UI应用程序中容易出现维护问题的部分是业务逻辑,它分散在整个应用程序中,使得修改或添加功能十分麻烦。 模型-视图架构改进了好多,它将业务逻辑转化为单独的域模型。 这样数据、进程和规则都集中在应用程序的一部分中,如图3-3所示。
模型视图架构能够是单片智能UI模式的改进 - 例如,更容易维护,可是会出现两个问题。 首先是由于UI和领域模型是紧密结合的,因此在这二者之间进行单元测试是很困难的。 第二个问题来自实践,而不是模式的定义。 该模型一般包含大量的数据访问代码 -虽然不老是这样,但一般是- 这意味着数据模型不只包含业务数据,操做和规则。
为了解决模型视图架构的问题,三层模式将持久性代码与域模型分离,并将其放置在称为数据访问层(DAL)的新组件中。 如图3-4所示。
三层架构是业务应用程序中使用最普遍的模式。 它对UI的实现没有任何限制,而且提供了很好的分离关注点,而不会太复杂。 并且能够建立DAL,使单元测试相对容易。 您能够看到经典三层应用程序和MVC模式之间的明显类似之处。 不一样的是,当UI层直接耦合到点击事件GUI框架(如Windows窗体或ASP.NET Web窗体)时,几乎不可能执行自动化单元测试。 并且由于三层应用程序的UI部分可能很复杂,因此有不少代码不能被严格的测试。
在最糟糕的状况下,三层架构在UI层面缺少执行规则意味着许多这样的应用程序最终都是虚拟假装的Smart UI应用程序,并无真正的关注分离。 这给了最糟糕的可能结果:一个很是复杂的,不可测试的,不可维护的应用程序。
我已经描述了MVC应用程序的核心设计原则,特别是适用于ASP。 NET Core MVC。 其余人以不一样的方式来解释模式的各个方面,并添加到MVC中,以适应其项目的范围和主题。 在如下部分中,我简要介绍一下关于MVC主题的两个最流行的变体的概述。 了解这些变体对于使用ASP.NET Core MVC并非必不可少的,可是为了知识的完整,我将它包含进来,由于这涉及到大多数软件模式讨论中使用的术语。
模型视图呈现器(MVP)是MVC的一个变体,旨在更容易地与诸如Windows窗体或ASP.NET Web窗体之类的状态GUI平台相配合。这是值得尝试的,可以得到最好的Smart UI模式的优势并且不会带来问题。 在这种模式中,演示者(Presenter)与MVC中的控制器具备相同的职责,但与有状态视图的关系也更为直接,对用户的输入的值和操做可直接在UI组件中显示。 这种模式有两种实现方式:
模型视图模型(MVVM)模式是MVC最近的一个变化。 它源于Microsoft,并在Windows Presentation Foundation(WPF)中使用。 在MVVM模式中,模型和视图与MVC中具备相同的角色。 不一样之处在于MVVM中视图模型的概念,它是用户界面的抽象表示,一般是一个C#类,用于显示要在UI中显示的数据的属性,以及能够从UI调用的数据的操做 。 与MVC控制器不一样,MVVM视图模型不存在视图(或任何特定UI技术)的概念。 MVVM视图使用WPF绑定功能将视图中的控件(下拉菜单中的项目或按下按钮的效果)暴露的属性与视图模型公开的属性进行双向关联。
提示:MVC模式还使用术语view模型,可是指的是一个简单的模型类,仅用于将数据从控制器传递到视图,而不是域模型,这些模型是数据,操做和规则的复杂表示。
当您建立一个新的ASP.NET Core MVC项目时,Visual Studio会为您提供项目中所需的初始内容的一些选择。这个想法是为了减轻新开发人员的学习过程,并为常见的功能和任务应用一些节省时间的最佳实践。我不是这种代码模具方式的粉丝。意图是好的,但执行老是很让人崩溃。我最喜欢ASP.NET和MVC的特色之一就是我在裁剪平台时有多大的灵活性来适应个人开发风格。 Visual Studio建立和填充的项目,类和视图使我感到是在别人的风格下工做。我也发现内容和配置太通用,太平淡,没法使用。微软不可能知道须要什么样的应用程序,因此它涵盖了全部的基础,可是以这样的通常化方式,我最终只是删除默认内容。 个人建议(给任何提出错误的人)是从一个空项目开始,并添加所需的文件夹,文件和包。不只您将更多地了解MVC的工做原理,并且您能够彻底控制您的应用程序所包含的内容。可是,个人想法可能不适合你。您可能会发现模板比我更加有用,特别若是您是ASP.NET的新手,而且还没有开发出适合您的开发样式。您可能还会发现项目模板是一个有用的资源和创意来源,尽管在彻底了解应用程序的工做原理以前,您应该谨慎地向应用程序添加任何功能。
当您首次建立新的ASP.NET Core项目时,您能够选择如下三个基本的起点:空模板,Web API模板和Web应用程序模板,如图3-5所示。
图3-5 ASP.NET 工程模板
空项目模板包含ASP.NET Core的管道,但不包括MVC应用程序所需的库或配置。 Web API项目模板包括ASP.NET Core和MVC,其中包含示例应用程序,演示如何从客户端接收和处理Ajax请求。 Web应用程序项目模板包括ASP.NET Core和MVC,其中包含演示如何生成HTML内容的示例应用程序。 Web API和Web应用程序模板能够配置不一样的方案来验证用户并受权他们访问应用程序。 项目模板能够给人须要遵循特定的路径来建立某种ASP.NET应用程序的印象,但事实并不是如此。模板仅仅是相同功能的不一样起点,您可使用任何模板添加所需的任何功能。例如,第20章中,我解释了如何处理的Ajax请求以及第28-30页的身份验证和受权,全部这些都是从空项目模板开始的。
所以,项目模板之间的真正区别是Visual Studio在建立项目时添加的库,配置文件,代码和内容的初始集合。最简单的模板(空)和最复杂(Web应用程序)之间存在不少差别,如图3-6所示,它显示了在建立项目以后的解决方案资源管理器。对于Web应用程序模板,我不得不将解决方案资源管理器集中在不一样的文件夹上,由于单个列表对于打印页面来讲太长。
图3-6 空项目模板和Web应用模板中的默认内容
Web应用程序模板添加到项目中的额外文件看起来使人望而生畏,但其中一些只是占位符或经常使用功能的示例实现。 一些其余文件设置MVC或配置ASP.NET。 还有一些是客户端库,它们将被并入应用程序生成的HTML中。 文件列表如今可能看起来很崩溃,可是在完成这本书时你会明白所作的一切。
不管您用于建立工程的模板如何,都会显示一些常见的文件夹和文件。 工程中的某些项具备特殊角色,他们是硬编码到ASP.NET中或MVC中或Visual Studio提供支持的工具中。 其余的则受到大多数ASP.NET项目或MVC项目中使用的命名约定的约束。 在表3-1中,我描述了您将在ASP.NET Core MVC项目中遇到的重要文件和文件夹,其中有些文件和文件夹默认不存在于项目中,但在后面的章节中我将介绍。
Table 3-1 MVC 工程中的文件项汇总
文件夹或文件
描述
/Areas
区域是将大型应用程序分割成较小的部分的一种方式。 我在第16章描述区域。
/Dependencies
“依赖关系”项目提供项目依赖的全部包的详细信息。我在第6章中描述Visual Studio使用的包管理器。
/Components
这是定义用于显示自包含功能(如购物车)的视图组件类。 我在第22章中描述视图组件。
/controllers
这是控制器类所在的地方。 这是一个约定,您能够将控制器类放在您喜欢的任何地方,由于它们都被编译成同一个程序集。 我在第17章详细描述了控制器。
Data
这是定义数据库上下文类的地方,尽管我更倾向于忽略此约定,并在Models文件夹中定义它们,如第8章所示。
/Migrations
这是存储数据库模式的详细信息,以即可以更新部署数据库。 我在第12章中演示了部署的过程。
/Models
这里放置视图模型和域模型。 这是一个约定 您能够在项目中的任何位置或单独的项目中定义模型类。
/Views
该目录包含视图和部分视图,一般在与它们相关联的控制器上命名的文件夹中组合在一块儿。 我在第21章详细描述了视图。
/Views/Shared
此目录包含共享的布局和视图。 我在第21章详细描述视图。
/Views/_ViewImports.cshtml
该文件用于指定将包含在Razor视图文件中的命名空间,如第5章所述。 它也用于设置标签助手,如第23章所述。
/Views/_ViewStart.cshtml
该文件用于指定Razor视图引擎的默认布局,如第5章所述。
/bower.json
此文件默认隐藏。 它包含由Bower软件包管理器管理的软件包列表,如第6章所述。
/project.json
该文件指定了项目的一些基本配置选项,包括其使用的NuGet软件包,如第6章所述。
/Program.cs
这个类配置了应用程序的托管平台,如第14章所述。
/Startup.cs
该类配置应用程序,如第14章所述。
/wwwroot
这是静态内容,如CSS文件和图像所在的地方。 Bower包管理器、JavaScript和CSS包也在这里,如第6章所述。
在MVC项目中有两种约定。第一类只是建议您如何组织您的项目。例如,一般将您所依赖的第三方JavaScript和CSS包放在wwwroot/lib文件夹中。这是其余MVC开发人员但愿找到它们以及软件包管理器安装的地方。可是你能够自由地重命名lib文件夹,或者彻底删除它,并将你的包放在别的地方。只要您的视图中的脚本和连接元素指向您所在的位置,MVC就会运行您的应用程序。 另外一种惯例来自于约定大于配置的原则,这是Ruby on Rails受欢迎的主要卖点之一。例如,约定大于配置意味着您不须要显式地配置控制器及其视图之间的关联。您只需遵循一个特定的命名约定为您的文件,一切都正常。在处理这种惯例时,改变项目结构的灵活性较小。如下部分将说明用于替代配置的约定。
提示:全部的约定都是能够更改的,经过用你本身的MVC组件替换默认组件来实现。 我在本书中描述了不一样的方法来解释MVC应用程序的工做原理,但这些是大多数项目中将要处理的约定。
Controller类的名称以Controller结束,如ProductController,AdminController,和HomeController。 当从项目其余地方引用控制器时,例如使用HTML帮助器方法时,您能够指定名称的第一部分(例如Product),MVC会自动将Controller添加到名称中,并开始查找控制器类。
提示:您能够经过建立一个模型约定来改变这一点,我在第31章中描述。
视图放在文件夹/Views/Controllername。 例如,与ProductController类相关联的视图放在/Views/ Product文件夹。
提示:请注意,Views文件夹中省略了"Controller"单词:/Views/Product,not/Views/ ProductController。 起初看起来彷佛是违反直觉的,但它很快就变得天然了。 MVC但愿以该方法命名操做方法的默认视图。 例如,与名为List的动做方法关联的默认视图应该称为List.cshtml。 所以,对于ProductController类中的List操做方法,默认视图预期为/Views/Product/List.cshtml。 在动做方法中返回调用View方法的结果时使用默认视图,以下所示:
return View();
你能够用名字指定不一样的视图,像这样:
return View("MyOtherView");
请注意,我不包括文件扩展名或视图的路径。 当寻找一个视图时,MVC在控制器后面命名的文件夹中,而后在/Views/Shared文件夹中。 这意味着我能够在/Views/Shared文件夹中放置多个控制器使用的视图,而MVC会发现它们。
布局的命名约定是使用文件前面加下划线(_
)字符,而且布局文件放在/Views/Shared文件夹中。 默认状况下,此布局将应用于全部视图/Views/_ViewStart.cshtml文件。 若是您不但愿将默认布局应用于视图,则能够更改ViewStart.cshtml中的设置(或彻底删除该文件)以在视图中指定其余布局,以下所示:
@{ Layout = "~/_MyLayout.cshtml"; }
或者你能够不使用任何布局,像下面这样:
@{ Layout = null; }
在本章中,我向您介绍了MVC架构模式,并将其与您以前看到或听到的其余模式进行了比较。 我讨论了领域模型的重要性并引入了依赖注入,它容许您去分离组件以强制应用程序的各个部分之间的严格分隔。 在下一章中,我将解释Visual Studio MVC项目的结构,并描述MVC Web应用程序开发中使用的基本C#语言特性。