重温MVC基础入门
重温MVC基础入门
简介
本文主要是作者回顾MVC基础的文章,整合个人认为基础且重点的信息,通过简单实践进行复习。
相关代码地址:https://github.com/OtherRuan/Review-Serials
WebForm
开始说MVC的时候不得不提下WebForm,熟悉两者的区别和优劣,能够更好的理解MVC。早些时候,开始做asp.net开发的时候离不开webform的控件拖拽的方式开发,只需要拖拽系统的控件就能完成web页面,效率之快毋庸置疑。但是随之而来的是臃肿的应用程序,耦合度极高的前后端,ViewState大量占用带宽等问题,在当今越来越追求性能的背景下。WebForm也面临退伍的命运,就像Asp.Net5已经完全摒弃了WebForm的开发方式。
性能问题是WebForm最主要的问题,通过MVC与WebForm两者性能的对比,可以明显的看出WebForm性能上存在的问题。
1. 响应时间
(图片来源自:http://www.codeproject.com/Articles/866143/Learn-MVC-step-by-step-in-days-Day)
可以看出响应时间上WebForm是MVC的两倍,因为WebForm需要将控件进一步转换成html文本响应。如下流程
用户请求-->服务器控件-->转换成Html-->返回响应
2. 带宽消耗

由于服务器控件的状态变换控制是通过事件回发来完成的,而回发状态信息则保存在ViewState中,以达到减少开发时间。但是ViewState却大幅增加了页面的大小,从上图可以看到WebForm的页面大小比MVC要大2倍上下。
其他问题,如重写问题、单元测试问题等等
MVC
解决WebForm性能问题,从几个问题来看。首先,由于WebForm是由aspx和aspx.cs两者通过CodeBehind高度耦合,导致无法单元测试, 因此我们将二者独立开,即Controller。其次ViewState导致页面大,服务器控件多的情况下,加之难以重写的问题,因此前端采用纯Html方式,也就是View。以下是MVC的流程图

简要介绍几个内容:
1. Controller:也就是后端逻辑处理
2. View
MVC通过创建ViewResult对象渲染View到响应包中。过程如下:
a. ViewResult内部创新ViewPageActivator对象
b. ViewResult选择正确的ViewEngine,将ViewPageActivator作为ViewEngine构造函数的参数
c. ViewEngine创建View 对象
d. ViewResult 触发 View对象的方法RenderView
ViewResult和ActionResult的关系
ActionResult是抽象类,ViewResult-->ViewResultBase-->ActionResult。 -->为继承关系
ViewResult描述了完整的HTML响应,而ContentResult响应文本请求。
3. 数据对象Model在Controller与View之间的传递
a. ViewState的使用
ViewState是一个dictionary,Controller将数据Model对象添加到这个Dictionary中,View从中读取数据。
ex. ViewState["Employee"] = new Employee();
b. ViewBag的使用
ViewBag.Employee = new Employee();
c. ViewState和ViewBag的问题
1) 性能问题
ViewData的数据是Object,我们需要强制转换它。
2) Type安全问题与Runtime编译时错误问题
当发生强转出错时,我们会获取运行时错误信息。但是好的程序,应该要获取编译时错误
3) 数据发送端与接收端没有必要联系
由于controller和view是相互解耦的,这时如果view和controller是两个不同的程序员时,使用viewState就容易造成运行时错误,强转错误
4. 理解强类型视图
针对3.c指出的类型问题,我们可以采用强类型视图,预先定义好model对象的类型,避免发生转换错误。

@model MVCReview.Models.Employee @if(Model.Salary>15000)
{
<span style=" padding: 0px; color: rgb(0, 0, 255); font-size: 12px !important; line-height: 1.5 !important;">>
Employee Salary: @Model.Salary.ToString("C")
</span>
}
else
{
<span style=" padding: 0px; color: rgb(0, 0, 255); font-size: 12px !important; line-height: 1.5 !important;">> Employee Salary: @Model.Salary.ToString("C")
</span>
}

@model MVCReview.Models.Employee 指定了类型
5. 理解ViewModel
ViewModel作为Model和View之前的交互的数据容器。Model一般为具体业务数据,是基于业务和数据库结构创建的。而ViewModel是具体的View数据,基于View页面对象
之前提到,当我们用model作为view的对象时,如果我们想新增其他信息时,这就违背了SRP和SOLID原则。
Controller集合多个Model,合并成一个view的viewmodel
6. ViewModel的实例

using MVCReview.Models;
using MVCReview.ViewModels;
public class EmployeeViewModel
{
public string EmployeeName { get; set; }
public string Salary { get; set; }
public string SalaryColor { get; set; }
public string UserName { get; set; }
}

其中EmployeeViewModel中含有两个对象的集合,Employee对象的数据和User的数据UserName。
DAL层
- 什么是EF
ORM: 与数据库通信,mapping数据库的表对象
2. 什么是Code First
EF有三种创建模式
a) Database First Approach:先创建数据库表,然后EF生成关联的Model类和DAL代码
b) Model First Approach: Model类以及Model之间的关系,使用Model designer先定义好,EF会生成DAL代码和在数据库中生成表
c) Code First Approach: 手动创建POCO类。表间的关系通过POCO定义。当程序第一次运行时会生成DAL代码和数据库表
Authentication权限
ASP.NET Form Authentication所做的工作:
- 用户请求Form权限允许访问程序
- 浏览器把相关的Cookies保存到请求中
- 请求到达服务端后,服务器检查请求的cookie信息:Authentication Cookie
- 解析Cookie信息得到用户信息,如果没有cookie则认定用户为匿名用户anoymous
FormsAuthentication.SetAuthCookie(account.Name, false);
ModelState.AddModelError("AddError", "Invalid Username or password!");
@Html.ValidationMessage("AddError", new {style="color:red;" })
Global添加权限属性过滤—共用权限验证
如何添加页眉页脚
- ViewModel添加FootViewModel
- @{Html.RenderPartial(“Footer”,Model.FootData)}
Html.RenderPartial与html.partial区别:
renderPartial直接将View转成Http响应stream,而partial则返回结果MvcHtmlString对象。MvcHtmlString代表html编码后的字符串,razor会对string一直编码,但MvcHtmlString例外。使用场景:当我们不需要使用razor进行编码的时候。partial之所以返回MvcHtmlString而非String,原因就是Partial 的使用通常是作为HTML文本而非string. Html.renderPartial比partial快,所以推荐。
实现角色安全
- 创建用户角色枚举
- 服务调用,记录到Session中
- 创建PartialView权限范围内的功能,如添加新用户
- 添加Action,render这个PartialView
- Html.RenderAction
这样还不够,因为登录的用户可以通过输入url地址,来使用添加用户的功能。使用MVC ActionFilter来执行Action处理前和处理后的逻辑
MVC filter有四种,Action、Authorization、Result、Exception
使用ActionFilter过滤结果对象
ActionExcutedContext
- ActionDescriptor包含Action、Controller等等的描述,如name、Type等
- Canceled:返回当前Action是否取消执行的状态
- Exception:执行Action中的Exception对象
- ExceptionHandled:返回执行Action时Exception对象是否被处理。
- Result:ActionResult对象,即Action返回的结果对象。可以操作结果视图对象里的Model和View。
完善项目
- 创建ViewModel基类ReactViewModel,包含基础信息,如Footer、Username
- 创建layout view. ReactView.cshtml
- 强类型视图,引用ReactViewModel对象
- 定义@RenderSection(“ContentBody”)
- Index页面引用layout
- Index 页面实例section,@section ContentBody{ //html元素 }
@html.RenderBody()做了什么?
Razor允许我们利用RenderBody来定义section外的content内容。非包含在section内的内容将自动包含在renderBody中。
MVC响应请求的过程
MVC是如何响应你发送的请求?
当一个请求发生时,就会创建一个线程来执行相应的程序。Web服务器上的Asp.net中,.net framework维护线程池。每一次请求发送到web服务器,线程池就分配一个线程(工作线程)响应这个请求。工作线程将会锁定单独处理这个请求,因此很有可能一个应用程序接受N多个线程且长期占用资源的情况。当线程池请求占满,没有可用的线程响应请求,这叫线程饥饿。
解决方案:
异步请求
- 线程池为异步请求分配工作线程
- 工作线程初始化异步操作的信息后就返回线程池,异步操作将继续在CLR线程中执行。
- 当CLR线程执行完后将通知ASP.NET
- Web服务器将获取工作线程处理剩余的请求并发送响应
Request-->work thread-->CLR thread-->work thread-->response
解决线程饥饿的问题
- 请求发送到web服务器
- Web服务器从线程池中分配工作线程响应请求
- 工作线程触发Action方法执行
- Action通过Task.Factory.StartNew方法开始异步处理
- Async关键字确保工作线程在异步处理开始后的释放。逻辑处理将在单独的CLR线程后台执行
- Await关键,确保下一行的执行等待异步操作完成后
- 异步操作完成后,则需要分配新的工作线程处理剩余的请求和发送响应
错误处理-显示自定义错误页面
Exception Filter
使用步骤:
- 开启ExceptionFilter
<customErrors mode="On"></customErrors>
2. 添加属性到Action、Controller、Global级别
Action方法发生错误时,Exception Filter获取Control的错误,并处理filter的内容。当Action发生错误时,filter会从~/Views/[Controller]或者~/Views/Shared文件夹中找以Error为命名的文件,创建ViewResult响应结果
错误处理-日志错误
ExceptionFilter:HandleErrorAttribute
Override OnException method
改变原有的Exception Filter
//filters.Add(new HandleErrorAttribute());//ExceptionFilter
filters.Add(new EmployeeExceptionFilter());
base.OnException(filterContext);
错误处理后,OnException将返回ViewResult也就是Error View。 重定义filterContext的Result就可以重定义ViewResult
路由
理解RouteTable
包含所有应用程序的所有URL路由的定义,静态属性RouteCollection
RouteConfig.RegisterRoutes(RouteTable.Routes);
RouteConfig.cs里RegisterRoutes将会在Asp.Net MVC请求环中决定Url路由对应的Controller和Action
MVC请求周期:
1. UrlRoutingModule
终端用户第一次请求经过UrlRoutingModule对象,UrlRoutingModule是HttpModule
2. Routing路由
UrlRoutingModule从RouteTable里的RouteCollection中,获取匹配的Route对象。该匹配过程就是对比RouteConfig里定义的Url的路由模式
3. 创建MVC Route Handler
匹配对应的Route对象后,UrlRoutingModule会从Route对象中获取MvcRouteHandler对象
4. 创建RouteData和RequestContext
UrlRoutingModule对象会通过Route对象创建RouteData(包含Routes的相关信息,如action、controller、parameters信息),继而通过RouteData创建RequsetContext对象。
5. 创建MVCHandler
MvcRouteHandler创建MVCHandler实例传递RequestContexst对象。
6. 创建Controller实例
MVCHandler借助ControllerFactory,创建Controller实例。
7. 执行方法
MVCHandler会触发Controller的执行。执行方法定义在Controller的基类中。
8. 触发Action方法
所有Controller关联一个ControllerActionInvoker对象。内置的执行方法利用ControllerActionInvoker触发action方法的执行
9. 执行结果
返回ViewResult结果
Request-->UrlRoutingModule (RouteTable) -->Route -->MVCRouteHandler、RouteData-->RequestContext
MvcRouteHandler-->MvcHandler (ControllerFactory)-->Controller (ControllerActionInvoker)-->ActionàViewResult
如何实现友好的URL
配置RouteConfig里的RegisterRoute
或者在Controller上添加Route()属性
参考文献
重温MVC基础入门的更多相关文章
- Spring MVC基础入门
Spring MVC简介 Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱 ...
- ASP.NET MVC基础入门.
一:ASP.NET MVC 简介 1:asp.net mvc 是一种构建web应用程序的框架,他将一般的MVC(Model--View--Controller)模式应用于asp.net框架. 2:as ...
- Taurus.MVC WebAPI 入门开发教程4:控制器方法及参数定义、获取及基础校验属性【Require】。
系列目录 1.Taurus.MVC WebAPI 入门开发教程1:框架下载环境配置与运行. 2.Taurus.MVC WebAPI 入门开发教程2:添加控制器输出Hello World. 3.Tau ...
- 【番外篇】ASP.NET MVC快速入门之免费jQuery控件库(MVC5+EF6)
目录 [第一篇]ASP.NET MVC快速入门之数据库操作(MVC5+EF6) [第二篇]ASP.NET MVC快速入门之数据注解(MVC5+EF6) [第三篇]ASP.NET MVC快速入门之安全策 ...
- SpringMVC基础入门
一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要的jar包. 2.添加Web.xml配置文件中关于SpringMVC的配置 1 2 3 4 5 6 ...
- T4教程1 T4模版引擎之基础入门
T4模版引擎之基础入门 额,T4好陌生的名字,和NuGet一样很悲催,不为世人所熟知,却又在背后默默无闻的奉献着,直到现在我们项目组的人除了我之外,其它人还是对其豪无兴趣,基本上是连看一眼都懒得看 ...
- SpringMVC基础入门,创建一个HelloWorld程序
ref:http://www.admin10000.com/document/6436.html 一.SpringMVC基础入门,创建一个HelloWorld程序 1.首先,导入SpringMVC需要 ...
- .net core +codefirst(.net core 基础入门,适合这方面的小白阅读) 【我们一起写框架】领域驱动设计的CodeFirst框架(一)—序篇
.net core +codefirst(.net core 基础入门,适合这方面的小白阅读) 前言 .net core mvc和 .net mvc开发很相似,比如 视图-模型-控制器结构.所以. ...
- SpringBoot之基础入门-专题一
SpringBoot之基础入门-专题一 一.Spring介绍 1.1.SpringBoot简介 在初次学习Spring整合各个第三方框架构建项目的时候,往往会有一大堆的XML文件的配置,众多的dtd或 ...
随机推荐
- 开源一款android 偷拍 app【静拍】豌豆荚、flyme商店已经上线
首先先花3秒时间,预览下下app的大概是做啥的,解决啥痛点的:) app: 本地下载地址 需求点: 1:音量键可以拍照 2:没有快门声.闪光灯 3:锁屏下.或者是在其他程序界面都可以拍照 思路: 1: ...
- 实战DVWA!
DVWA漏洞训练系统,来个大图^-^ 1.首先试了下DVWA的命令执行漏洞command execution 这是我在Low级别上测试的,另外附上low级别代码: <?php if( i ...
- python单元测试框架——pytest
官网:https://docs.pytest.org/en/latest/ pytest帮你写出更好的程序 1.An example of a simple test:(一个简单的例子),命名为tes ...
- MyEclipse 2014优化设置(禁用myeclipse updating indexes)
1.指定本机java环境 Windows-->preferences-->java-->Insetallel JREs 右侧 单击ADD standard VM-->Next ...
- mysql中sql语句中常见的group_concat()函数意思以及用法,oracle中与其一样的功能函数是wmsys.wm_concat()
1.group_concat(),手册上说明:该函数返回带有来自一个组的连接的非NULL值的字符串结果.比较抽象,难以理解. 通俗点理解,其实是这样的:group_concat()会计算哪些行属于同一 ...
- 为什么gitHub提交记录显示作者名称是unknow?
unknow,为什么? gitHub上提交记录显示作者名称是unknow,刚开始没怎么管,后面遇到问题看提交记录时发现有两个unknow(一定有一个人遇到和我一样的问题了,哈哈..),于是解决一下吧. ...
- 【Head First Servlets and JSP】笔记 27: web 应用安全
典型的安全问题:假冒者.窃听者.非法升级者 认证方式: Base64 .摘要认证 .客户端证书.表单认证,重点熟悉摘要算法( HASH . MD5 等) 安全机制:授权.认证.数据完整性.机密性 80 ...
- Web开发相关笔记 #02#
[1] HTML 插入第三方. [2] [3] JavaScript 回调函数 & 模块化 --> 用变量封装数据.方法 --> 类比 Java 中的 package var fe ...
- linux下如何制作ext4文件系统镜像
1.生成一个空的2MiB文件 dd if=/dev/zero of=rootfs.ext4 bs=1024 count=2048 (指定每一块大小为1024字节,一共又2048块,那么就是2048 * ...
- MySQL MERGE存储引擎 简介及用法
MERGE存储引擎把一组MyISAM数据表当做一个逻辑单元来对待,让我们可以同时对他们进行查询.构成一个MERGE数据表结构的各成员MyISAM数据表必须具有完全一样的结构.每一个成员数据表的数据列必 ...