软件开发
MVC是WEB开发的主流技术/模式,应用非常广泛。但是很多同学受原有MVC概念的影响,并没有真正理解MVC的确切含义;或者应用原有的MVC概念无法对应实际编程;或者可以参考例子写代码,但是遇到复杂问题不知道从何下手。那么MVC在ASP.NET的含义是什么,M、V、C之间的关系是什么,如何基于最新的MVC原则分析复杂的交互问题?
1.m、v和c的含义
顾名思义:m:模型,模型;v:观,观;c:控制器,控制器。
男:模特,模特。这个M是理解MVC机制的关键。但是m的概念很模糊,含义不清。它是一个领域模型,代表业务实体和逻辑吗?是实体模型,代表一个ORM实体对象吗?还是视图模型(VM)?答案是视图模型!是视图内容的抽象或映射。
v:观,观。很好理解,就是UI界面,用户的交互界面,对应的代码就是一系列HTML元素。视图的功能是:(1)接收用户动作;(2)呈现处理结果。呈现的数据从何而来?查看模型对象!
c:控制器,控制器。控制器是一个“盒子”。每个控制器包含一系列动作函数,每个动作代表一个HTTP请求(动作)和响应。每个动作函数的作用是:(1)接收HTTP请求;(2)返回请求处理结果。其执行业务处理或者调用独立的业务层来执行业务处理。返回什么结果?“视图+视图模型”的组合!通过这种方式,View可以呈现用户在浏览器中看到的内容。那么控制器控制什么呢?控制“请求和响应”与“视图和视图模型”之间的关联。当然,这些关联都是MVC框架支持的,控制器只是这些关联的呈现者。
M-V-C应该叫ViewModel-View-Controller或者ViewModel-View-Action。
MVC发展到现在,已经不是原来的样子了。现在的Web应用环境和1979年MVC提出时的软件环境已经有了很大的不同,M、V、C的概念和关系都有了很大的演变。因此,我们不能再套用原来的MVC概念来理解现在的MVC模式。ASP.NET MVC采用MVC的新变种Model2模式,这也是Spring MVC采用的模式。接下来,我们将从典型的ASP.NET MVC代码中分析M、V和C的含义和关系。
2.从典型代码分析M、V和C之间的关系。
一个超级简单的用户信息编辑演示,界面如下:
(1)模型文件User.cs具体代码如下:
命名空间MvcDemo。模型
{
公共类用户
{
public int ID { setget}
公共字符串名称{ setget}
公共字符串地址{ setget}
}
}
这只是一个简单的POCO(Plain Old C# Object)类,它定义了用户模型。为什么要定义这个模型?因为视图需要它。现在看看视图文件。
(2)视图文件UserEdit.cshtml它存储在Views/User/UserEdit.cshtml中,具体代码如下:
@model MvcDemo。模型.用户
& lth2 & gt用户信息编辑
@使用(Html。BeginForm())
{
& ltp & gt
ID:@Html。显示for(m = & gt;医学博士)
@Html。hidden for(m = & gt;医学博士)
& lt/p & gt;
& ltp & gt名字:@Html。textbox for(m = & gt;m . Name)& lt;/p & gt;
& ltp & gt地址:@Html。textbox for(m = & gt;m .地址)& lt/p & gt;
& ltinput type = ” submit ” value = ” se “/& gt;
}
这个文件定义了浏览器要呈现的界面元素,通过“保存”按钮可以实现与用户的交互。
浏览器需要数据来呈现界面内容,数据来自模型对象。@model标签指定了当前视图对应的数据(数据定义),也就是视图对应的模型用户。这样,我们假设有了一个用户对象M,就可以在界面上呈现M的数据。
模型用户(类)是基于视图UserEdit.cshtml的,视图显示的需求决定了用户是什么样子,需要定义什么内容。视图/界面代表应用需求,我们所做的是基于应用需求。
总结:视图决定模型,模型是基于视图的模型,所以应该叫ViewModel。
(3)控制器文件UserController.cs具体代码如下:
使用系统。Web . Mvc
使用MvcDemo。模特;
命名空间MvcDemo。控制器
{
公共类UserController:控制器
{
[HttpGet]
public action result UserEdit(int id)
{
var user = getuser byid(id);
返回视图(用户);
}
[HttpPost]
公共操作结果用户编辑(用户用户)
{
updateUser(用户);
返回视图(用户);
}
}
文件中的UserController类包含两个操作函数:
第一个动作函数UserEdit(int id)处理HttpGet请求,请求的URL类似于http://www.xxx.com/User/UserEdit?. id = 2,问号后面的参数Id自动映射到动作函数的参数Id。为了响应这个请求,Action函数获取用户id=2的用户对象,并将其呈现给接口。
第二个操作函数UserEdit(用户User)处理HttpPost请求。当用户点击“保存”按钮时,表单内容被提交,触发一个与上面URL相同的HttpPost请求,类似于http://www.xxx.com/User/UserEdit?. Id = 2,请求提交的表单内容自动映射到Action函数的参数user,即参数user的属性值由提交的表单内容根据属性名自动填写。作为对该请求的响应,Action函数保存提交的用户信息,并仍然将该信息呈现给界面。
(1)先说HTTP请求。HTTP请求一般包括三个元素:请求模式(Get/Post)、请求URL、请求参数(在URL中显式传输或在表单中隐式传输)、Cookie等。在上面的代码中,标记“[HttpGet],[HttpPost]”区分不同的HTTP请求类型。根据ASP.NET MVC惯例优于配置的原则,网址“http://www . XXX . com/User/UserEdit?”id=2中的“/User/”表示MVC框架正在寻找“UserController”,/UserEdit表示MVC框架正在寻找“UserEdit”函数来处理相应的请求。也就是说,URL决定了要调用的控制器类和其中的操作函数的名称。所请求的参数被自动映射到动作函数的参数,尤其是在第二个动作函数UserEdit(用户User)中。事实上,第一个动作函数UserEdit(int id)也可以写成:
[HttpGet]
公共操作结果用户编辑(用户用户)
{
var userObj = getUserById(user。ID);
返回视图(user obj);
}
也就是说,我们都可以将请求参数映射到一个视图模型对象,但是这个对象的属性值是否完全填充取决于请求参数的内容。当然,我们也不必为了满足程序处理的需要而完全填充。
那么,ASP.NET MVC的HTTP请求流程可以抽象表示为下图。请求由View发送给相应的Action,发送的内容是ViewModel对象。ViewModel对象成为动作函数的输入参数。
(2)先说HTTP响应。HTTP响应的内容通常是HTML文档,由浏览器解析并显示为页面。我们看到,视图文件UserEdit.cshtml本质上是一个html模板文件,在获取相应的视图模型对象user后,它会被填充到一个正式的HTML文档中。再看动作函数,它定义了请求对应的响应视图:动作函数UserEdit的名称与视图UserEdit.cshtml的后缀名称一致,控制器UserController的后缀名称与Views下的用户目录名称一致。它的作用是在控制器中的Action函数处理完用户的请求后,使用同名的视图来呈现响应结果。此外,Action函数还定义了视图要呈现的数据内容(视图模型对象)。代码的最后一行“返回视图(用户)”表示当前视图中要呈现的数据对象是用户。
那么,ASP.NET MVC的HTTP响应过程可以抽象表示为下图。响应由Action发送到相应的视图,发送的内容是ViewModel对象。MVC框架的底层实现将视图文件和视图模型对象组合成一个正式的HTML文档,并发送给用户的浏览器。
总结:控制器的作用其实就是把“请求-响应”和“视图(文件)-视图模型(对象)”关联起来!
把上面两个图结合起来,如下图,抽象表达视图、视图模型、动作、控制器之间的关系。即视图和动作之间,通过交换ViewModel对象实现交互——实现请求接收和结果响应。
可见,M、V、C三者交互的核心是处理视图交互的问题。所以Dino在《Microsoft.NET企业应用架构设计》中把MVC归为Web表示层的模式,在《企业应用架构模式》中把Martin Fowler归为。
3.理解MVC-M的关键。
前面我们说过,M是理解MVC机制的关键。这个M是一个视图模型,它基于视图和视图内容的抽象。
这个M不是一个领域模型,它不处理业务逻辑,并且应该尽可能保持简单,一般它是一个POCO类。业务逻辑由控制器处理,或者它调用一个独立的业务层来处理。认为M是处理业务逻辑的一个误区,通常把对原有MVC概念的理解机械地套用到MVC的新变种Model2模式上。
这个M也不是来自数据库ORM的实体模型,因为没有数据库和ORM实体模型,MVC就已经有效工作了,MVC和数据库没有直接关系。但是很多时候,我们直接用实体模型作为视图模型,是因为它往往正好满足视图的需求,但是概念上我们还是要明确:此时用实体模型作为视图模型。
数据库对于企业应用软件来说是一个高度抽象的需求,因为它通常是由经验丰富的高级程序员或架构师在编程前一次性设计出来的,这导致很多程序员认为一切(包括视图模型)都是从数据库中派生出来的。而且在使用Visual Studio创建一个MVC项目时,会在Models文件下自动创建基于EF的ORM实体模型,这让很多人产生了混淆和误解,以为基于数据库的实体模型就是MVC中的M。其实我们在编程的时候就应该从软件需求入手,软件需求导出界面原型,界面原型导出视图,视图导出视图模型(对象),视图模型导出业务逻辑,业务逻辑导出数据库设计。其实代码优先就是这样一种“向后结果过程”——“向后需求数据库设计”的思维模式。DB First模式只是资深程序员用丰富的经验高度压缩“基于需求的数据库设计”的一个思维过程。合理的思维应该是“结果的逆向思维”。需求是软件的结果,需求驱动软件开发的一系列过程。按照“后向结果”的思路,视图呈现的需求导致了视图模型的定义。所以ASP.NET MVC中的M是基于视图的需要,应该是视图模型。
4.解决复杂的交互问题
那么,在ASP.NET MVC编程与开发中要根据视图来设计视图模型,尤其是在处理各种交互的复杂视图时,要仔细思考如何抽象视图接口,然后设计合理的视图模型。
我总结为“通过查看视图来设计视图模型”,盯着视图界面,在脑海中把视图想象成一个对象,把页面上的元素/数据当作对象的成员。本质是将视图中的元素抽象成POCO类的属性,可以是简单的变量,也可以是小对象。视图上的每个交互请求都将ViewModel对象作为参数传递给相应的Action函数。如果你把一个视图接口当成一个对象,你就不怕复杂。
心中有了目标,世界就简单了。
采矿软件:http://www.cyjysoft.com
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。