MVC知识点
(一)通过MVC模板创建项目
MVC模式:ViewModel、View、Controller。
流程:由地址栏访问控制器(地址可以调用Controller和方法),通过Models过滤、校验,然后在Views显示出来。
在vs中创建项目的两种方法:
a.选择MVC模式创建;
b.使用Empty创建,勾选引用MVC核心创建项目
(1)a方法
项目内文件解析:
1.App_Start(配置文件夹)——
(1)BundleConfig:打包器(打包js和css文件)
bundles.Add(new ScriptBundle("~/bundles/jquery").Include("~/Scripts/jquery-{version}.js"));
// ScriptBundle:脚本打包器,作用是把include(XX)内的文件给重新打包命名,当出现之前的名字时,实际调用后续文件。
// StyleBundle:样式打包器,打包css文件,可同时打包多个,用“,”分隔。
// 打包器的作用:1.压缩文件;2.在更新js文件时只要命名符合规则,不需要改动代码名称;3.当Web.config中的设置把中的debug改为flase,即程序不调试直接发布后,会将打包中的代码压缩。
(2)FilterConfig:过滤器(写过滤规则)
(3)RouteConfig:路由配置,和WebAPIConfig一样
url: "{controller}/{action}/{id}",controller = "Home", action = "Index"
(规定controller和action的默认值)
2.Content文件夹
里面放置bootstrap的css样式和它当前页面site做了简单休整的css样式
3.Controller(控制器)
4.fonts——bootstrap的字体&图标文件
5.Models——ViewModel
6.Scripts
7.Views——控制器
- 每个controller在View中有一个对应的文件夹 (如HomeController.cs对应Home文件夹)
- controller中每一个action,都在View对应的文件夹下有一个文件(如Demo下的index,对应Demo下的Index.cshtml)
Home:对应Controller文件夹里的CS,一般Controller里的action方法名会在这里有与之对应的页面(.cshtml)调用不同的action方法就能出现不同的页面(即MVC模式)
Shard:共享文件夹,里面内容都可以用。其中Layout是母版页,未经过特殊设置的情况下所有页面都会套用它的格式(比如网站头尾的标识)。
设置其他母版页的方法:
a.在ViewStart中改变全局母版页
b.在页面中写Layout=“XXX”。
- 其中RenderBody()相当于一个占位符,起主题渲染的作用。后期会被替换,会被替换为Home中某一个特定页面;比如说About.cshtml,里面的内容最后会放在RenderBody()的位置。
所以当Layout中出现RenderBody(),其中就会被替换成内容页的部分。- ViewStart.cshtml里面设置套用哪个母版页。默认设置:Layout = “~/Views/Shared/_Layout.cshtml”;
△添加新项的步骤:Controller中添加项——选中action右键添加视图——
(2)b方法
实例及详细内容见MVCtest2
管道的概念:每个请求都会进入到一个固有的ASP.NET框架的管道中,管道会解析地址栏信息并作出相应操作
- 如地址为:localhost/54502/Demo/Index,先由ASP
ISS管道接管,根据中间键得到地址,解析出Demo→Controller名,Index→方法名,之后根据反射的方式实例化Controller并且调用INdex方法
———— 以上就是MVC框架的工作
调用时有几个非常重要的内置对象:
Request请求、Response响应、Session会话、Cookie客户端数据、Application当前项目(网站)对象、Server服务器对象
1.Request请求
客户端把数据给服务器(如浏览器写地址,请求54502服务器:localhost:54502
)
- Request.QueryString get请求
- Request.Form Post请求
- Reguest.File Post请求上传文件(比如自定义头像)
- Request.QueryString
①发送请求: QUeryString请求字符串对应get请求
localhost:49203?name=abcd
“?”是标志,后面可以加多个参数,中间使用"&"连接
(如:?name=abcd&age=12&id=3379……)
②接收请求:接收请求里name参数的数据
return Content(Request.QueryString["name"]);
//页面显示结果:abcd
return Content($"{Request.QueryString["name"]}-{Request.QueryString["age"]}-{Request.QueryString["id"]}");
//针对多个值,返回结果abcd-12-3379
- Request.Form
(结合HomePage1.html中代码一起看)
return Content(Request.Form["loginname"]);
<form action="Home/PostData" method="post">
<input type="text" name="loginname" />
<button>提交1</button>
</form>
- Request.Files
Files[ ]里的内容需要和html中的名字对应
Request.Files["file"].SaveAs(Request.MapPath("~/uploads/"+Request.Files["file"].FileName));
//SaveAs方法需要物理路径,用.Mapath()将虚拟路径转化为物理路径
<!--enctype="multipart/form-data"&&input type="file"是为了可以上传文件-->
<form action="Home/FileData" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button>提交2</button>
</form>
response响应
服务器给客户端做出的回应
- Response.Write:向客户端输出内容
Response.Write("Hello World!");
//地址栏使用时需要:49203/Home/responsedata
- Response.Redirect:重定向。重新请求另外一个路径
Response.Redirect("http://www.baidu.com");
//Response.StatusCode:状态网,比如网页404之类
- headers:加密的头文件
(消息分为分为两个部分:header、body)
Response.Headers["hello"] = "world";
//在header中添加一个名为hello,值为world的参数
return Content(Request.Headers["token"]);
//请求头
- Session:
一个键值对。数据保存在服务器,安全数据。存活时间20分钟,点击链接/按钮时重新计时。
- 进入(请求)网站开始就建立了一个Session,每个人的Session是独立的。
- 安全性高于cookie,但Session数据存储越多,占用内存就越多(因此session只用来存少量重要数据比如账号,不存其他——做身份识别)
Session["user"] = Request.Form["user"];
return Content("会话中的数据是:" + Session["user"]);
- Session成功建立后,当前所有页面(Action)都可以使用其中的数据(切换浏览器后get不到数据,因为数据不互通)
return Content("当前会话的数据是:" + Session["user"]);
- 安全退出页面——清除Session的两种方法
Session.Clear(); Session.Abandon();
- Cookie:
数据保存在客户端,不安全数据(想要防止篡改,需要用gwt防伪字符串)
- Cookie数据不需要用户操作,浏览器自动获取。
时效性:默认发过去的同时就过期了,因此需要额外设置有效时间Expires=DateTime.Now.AddDays()
//比如浏览器提示:七天免登录,就是在cookie上加入了时效性)
Response.Cookies.Add(new HttpCookie("token") { Value = "hijk1234",Expires=DateTime.Now.AddDays(7)});
- 清除cookie数据——使用过期的方式:
AddDays(-7)
Response.Cookies.Add(new HttpCookie("token") { Expires = DateTime.Now.AddDays(-7) });
- Application
数据在服务器端,整个网站共享(即换了浏览器也能取到)
HttpContext.Application["Appuser"] = "yessir";
- Server
Server.MapPath(); //绝对路径转相对路径
Server.MachineName(); //获取服务器名
Server.HtmlDecode/HtmlEncode //html转译
Server.UrlDecode //url转译
(二)控制器&页面数据互传
(1)怎样从控制器把数据传递给界面
controller从数据库取数,给到View显示
把Control中数据推送到视图的几种方法如下:
(实例参考MVCtest3-HomeController)
- ViewBag
不可跨页面,是dynamic类型(动态类型),因此可以随意放入任意的属性&方法 - ViewData
不可跨页面,与ViewBag存放方式相同,因此Data中定义的属性也可以由Bag来调用。一般存放一些不是主要的数据 - TempData
可以跨页面,相当于一次读取的Session(存储后读取一次就失效)
// 控制器中定义:
ViewBag.name = "张三";/ViewData["Habit"] = "抽烟";/TempData["hello"] = "world";
//cshtml中使用:
@ViewBag.Content /@ViewData["Habit"] /@TempData["hello"]
- View(model)方法
- 重载1.无参(页面、母版页、数据都无),使用当前方法同名页面,使用viewstart中指定的默认母版
- 重载2.传数据对象———使用action的同名视图。(只能传一个数据对象,用来传递主要数据。如model中建立student类,new一个赋值作为参数)
- 重载3.传viewname&数据对象——使用指定视图(访问路径不变),使用默认母版页,
- 重载4.传viewname&母版页&数据对象——到控制器同名文件夹→shared文件夹中查找视图对象;使用指定母版页,也可在view中用“layout=”设置。数据对象(需要在视图中声明数据对象)
(2)怎样从界面把数据放入控制器
view有数据后方向传递给控制器
(实例参考MVCtest3-DemoController)
- Get请求
- Post请求
✳一般表单页面都是一个Get+一个Post(Get用来显示,Post用来处理提交的请求,比如存入数据库。
(实例参考DemoController-Login)
如何快速创建页面(强类型视图&视图模型结合)
建立ViewModel,添加属性特性 →
建立无参Action Login(return View)→
创建对应视图Login.cshtml(选用模板Creat,模型类LoginViewModel,勾选“引用脚本库”)
在Login.cshtml中 ————
@using (Html.BeginForm())
//对应自建Form中的<Form>
标签的部分。BeginForm()中无参则默认提交当前Action,若加参,可提交指定Action
@Html.AntiForgeryToken()
//页面防伪标识(防止他人改造生成)
需在controller对应Action前加上[ValidateAntiForgeryToken],表示无防伪码不处理请求
@Html.ValidationSummary()
//错误校验汇总,对应结合Action中模型错误ModelState,
用AddModelError()添加summary会进行累计,将错误提示实时显示在当前页面
@Html.LabelFor()
//对应Model中[Display]特性的name值
@Html.EditorFor()
//文本框,对应Model中[DataType]特性
@Html.ValidationMessageFor()
//错误信息显示
(三)ActionResult的种类
ActionResult是一个父类型,有多种子类。常用的如下:
*ViewResult 返回相应视图
*ContentResult 返回字符串
*RedirectResult 重定向
*RedirectToRouteResult 根据路由进行重定向(内部跳转)
*FileResult 向客户端输出文件(file上传&显示)
*JsonResult 向客户端返回对象的Json序列化后的结果(将对象转成Json,输出结果)
*HttpStatusCodeResult 返回http页面状态码信息如404
*PartialViewResult 返回部分页面,相当于共享组件,针对重复利用的页面
(四)其他细节
1.razor剃须刀模板的使用
在.cshtml文件中:
最顶端的@ ——声明;
@{ ——编写代码片段。后续可以使用之前声明的变量等
@变量 ——输出这个变量的内容
@对象 ——输出该对象的属性内容
@表达式————输出表达式,
如“@a+22”,若想输出运算后的结果,需加括号如“@(a+22)”
要连续输出,写在一起即可:“@a@name”
要变量字符一起输出,变量外加括号:“@(a)a@(name)””
想要输出字符‘@’,需要用@转译:@@
想要输出样式的数据,需要用@Html.Raw()转换:@Html.Raw(sample)
※在cshtml中,加上标记识别为html部分。
※变量声明&数据处理一般在controller中写好。html中直接使用传过来的对象数据
※在cshtml文件中,代码是混编的,灰底为C#黑底为html。
在html标签内,代码默认为html,如果需要输出则在变量前加@;C#标签(@{)内同理,默认C#想写html需外套标签。
2.区域
(项目里右键——新建——区域)
大型项目有众多模块,放在一个MVC里不便于查找。使用区域分隔开,各模块分别占用区域,可视为独立的MVC。
建立区域如Sport后,项目中出现一个Area
文件夹,文件夹下区域并列(各区域拥有独立MVC结构、独立路由-路由前缀为创建时的区域名)
访问地址变为:localhost:50390/Sport/Home/Index
(再使用之前的localhost:50390/Home/Index会报错提示有多个Home)
此时要解决该报错问题,需要到Appstart——RouteConfig中添加命名空间声明:`namespaces: new string[] { “MVCtest5.Controllers” }/
3.页面跳转的三种方法
————参考MVCtest5/Home/Index
-
最基本的方法
弊端:一旦更改路由地址,所有相关引用都要一起更改(更改路由地址——SportAreaRegistration.cs文件)
<a href="/Sport/Home/Index">
点击跳转——体育板块 -
系统自动生成,不手动写
会生成<a>
标记,更改路由无影响。
- a.跨路由跳转——
参数(linktext,路由名称,controller&action定义)
@Html.RouteLink("方法2-体育板块", "Sport_default", new { Controller = "Home", Action = "Index" });
- b.当前路由跳转——
参数(linktext,Action名称,Action参数列表)
@Html.ActionLink("方法2-显示图片","GetFile",new {name= "637375892912542235logo.png" });
- c.当需要给标记添加样式时,把class-htmlAttributes写在参数列表的末尾
@Html.ActionLink("方法2-显示图片2", "GetFile", new { name = "logo.png" }, new { style = "color:red" });
- 手动。
使用Url下的方法——获取某Action的路由路径
- a.当前路由
<a href="@Url.Action("GetFile",new { name= "637375892912542235logo.png" })">方法3-显示图片3</a>
- b.跨路由
<a href="@Url.RouteUrl("Admin_default",new { Controller="Home",Action="Index",userid="123456",})">方法3-管理模块</a>
4.ViewModel细节
一般增删改查都要有对应的Model。参考MVCtest5/LoginViewModel
[Required(ErrorMessage =“邮箱地址必须填写”)]
[EmailAddress]//自动校验邮箱格式
[RegularExpression("",ErrorMessage =“邮箱格式有误”)]//自定义正则表达式,进行判断
[Required(ErrorMessage = “密码设置不能为空”)]
[DataType(DataType.Password)]//修改文本框显示类型,做pwd显示
[Compare(nameof(Pwd))]//保证ConfirmPwd和Pwd一致,用nameof防止写错
public DateTime? BornDate { get; set; }//值类型默认必填,因此后面加“?”变成可控类型-选填;引用类型默认选填
[Range(10,150,ErrorMessage =“年龄必须在10~150之间”)]//设置属性值范围
5.Action细节
1.Action拒绝访问:
a.使用private修饰符,不能调用(报错404)
b.不使用private修饰符情况下拒绝访问 ———— Action前方加[NonAction]
2.Action定义别名:
[ActionName(“111”)],当方法多次重载的时候,可以用它来区分访问路径如:Home/Demo;Home/111