ASP.NET MVC
原长期更新,但是不喜欢c#,所以结课了,就结束了
第一章 引子
略
第二章 遇见ASP.NET MVC
略
第三章 asp.net mvc技术入门
3.1 c# 知识
可选参数和命名参数:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace _3._1 // 命名空间
{
class Program // 类
{
// 主函数外写自定义函数
static void myTest(int x,string y="y",int z = 10,int m =5)
{// 默认参数必须放后面,赋值参数必须在前,如果把x放后面就会报错
Console.WriteLine("x={0},y={1},z={2},m={3}", x, y, z,m);
}
static void Main(string[] args) // 启动主函数入口
{
myTest(1);
// 输出为x:1 y:y z:10 m:5 也就是第一个参数修改了,其他参数使用默认值
myTest(1,"z",1);
// 输出为x:1 y:z z:1 m:5 顺序修改参数内容
myTest(3,m:6,y:"mvc");
// 输出为x:3 y:mvc z:10 m:6 不用顺序修改时,把参数写上加上':'号和值,便可以给指定的参数赋值,其他参数默认 这叫命名参数,上面的都是可选参数
Console.Read();
}
}
}
接口关键字:
interface [自定义名字]{
void [方法名]();
}
类继承接口用':'
class [类名]:[接口名],[接口名]{
public [方法名]{
}
}
多态:
[接口名] [自定义] = new [继承接口的类]();
[自定义].[方法名]
匿名类型
static void Main(string[] args) // 启动主函数入口
{
var x = 18;
// 隐式类型就是var 不知道这个参数式什么类型,int还是str
var stu = new { Sname = "zyx", Age = x };
// 匿名类型变量
// stu.Age = 19;
// 不能赋值,这是只读的
}
动态类型 dynamic
var stu = new { Sname = "zyx", Age = x };
// 匿名类型变量 不需要class
// 错误: stu.Age = 19;
// 不能赋值,这是只读的
dynamic myd = 8;
// 只在运行的时候检查 ,可用于泛型类型参数等,可以赋值或者被赋值任何类型,并且不需要强制类型转换
myd = stu;
// myd=myd + 1;
// 编码不报错,运行报错 因为赋值的类型不能运算
// stu.getAge();
// 报错是因为匿名变量不能在外面新建属性
// myd.getAge();
// 同理,因为是匿名变量,但是编码的时候不会报错,使用的时候要小心
// int dint = myd;
// 不能强转
// string dsrt = myd;
// 不能强转
3.2 路由知识
基本概念
注册和定义路由:
// 解决方案/App_Start/RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default", // 随便定义,但不可重名
url: "{controller}/{action}/{id}",
// url获取数据的规则,占位符 第一个控制器,第二个是action 第三个可以自定义 中间的/时分隔符,可以自定义
defaults: new { controller = "Home", action = "Index", id=UrlParameter.Optional}
// urlParameter.Optional意思:url参数.可选
// 这就是匿名类型
// 默认情况下进入的路径
// constraints: new { id = @"\d{1,3}" }
// 这个意思是id必须是1-3位数 如果加约束上面的语句需要加','
// 带约束的路由
//*捕获所有路由
// namespaces 指定命名空间匹配
) ;
}
参数的传递
传值:
localhost/home/index?id=123&name=123
或者
localhost/home/index/123/123
3.3 Razor视图知识
(1)@变量名、@(变量名)
@标记的作用之一是作为C#变量的开始标记(返回C#变量的值)。一般格式为:“@变量名”或者“@(变量名)”。换言之,对于单个变量来说,如果能将变量名和其他符号区分开,可省略@后的小括号,否则必须加小括号。例如:
<h2>@ViewBag.Chapter MyTest</h2> // 加空格
<h2>@(ViewBag.Chapter)MyTest</h2> // 加括号
(2)@(表达式)
@标记的另一个作用是返回C#内联表达式计算的结果。当@符号的后面为C#的内联表达式时,必须用大括号将表达式括起来。一般格式为:“@(表达式)”。例如:
@( i + j)
(3)@单条语句、@{语句块}
如果C#代码只有1条语句,在@符号的后面既可以不使用大括号,也可以使用大括号;但是,如果@后面的C#代码包含多条语句,则必须用大括号将这些语句括起来。例如:
@for(int i = 1; i <= 3; i++)
{
<p>你打我呀 @i</p>
}
@{
for(int i=1; i <= 3; i++)
{
<p>大家都听见了,是他让我打的,我从来没听过这种要求 @i</p>
@*这是注释*@
}
}
3.文件路径表示法(“/”、“~”)
相对路径(也叫虚拟路径)和应用程序绝对路径中的分隔符都用正斜杠(“/”)分隔。
用相对路径表示时,“.”表示当前目录,“..”表示上层目录。
用应用程序绝对路径表示时,用“~”符号表示应用程序的根目录,或者用“/”开头表示应用程序的根目录。
@{
var a = "~/images/img1.jpg"; //应用程序绝对路径(从项目的根目录开始) 不可使用
var b = "/images/img.jpg"; //应用程序绝对路径,与"~/images/img1.jpg"的作用相同 一般使用这个(个人)
var c = "./images/img1.jpg"; //相对路径,它等价于"images/img1.jpg" 需要本地有这个目录
var d = "../../images/img1.jpg"; //相对路径 这个写着麻烦
}
4.@Html.Raw方法
对于@符号本身以及双引号等特殊符号,可通过@Html.Raw方法和转义符将其原样显示出来。例如:
<p>@Html.Raw("@标记的用法")</p> // 这里面就可以用@了
<p>@Html.Raw("张三说:\"今天天气真好!\"")</p> // '\'是转义字符,能输出 "
5.分支、循环、对象和集合操作
由于在视图中可以混编C#代码和HTML代码,因此在C#代码块中,还可以使用分支语句、循环语句、数组、泛型集合以及.NET类库的所有功能。
第四章 控制器技术
4.1 概述
ASP.NET MVC的核心就是Controller(控制器),它负责处理客户端(常常是浏览器)发送来的所有请求,并决定将什么内容响应给客户端,通过这种方式,Controller负责响应用户的输入,并且在响应时修改Model,把数据输出到相关的View。MVC架构中的Controller主要关注应用程序流入、输入数据的处理,以及提供向View输出的数据。
控制器(Controller)本身是一个派生于Controller的类,这个类包含有多个方法,这些方法中声明为public的即被当作动作(Action),可以通过这些Action接收网面接收请求并决定应用的视图(View)。
控制器类型
(1)空MVC控制器
(2)包含读/写操作控制器和视图的MVC控制器(使用Entity Frameword)(3)包含空的读/写操作的MVC控制器
(4)其它控制器
Controller的执行过程
(1)当Controller被MvcHandler选中之后,下一步就是通过ActionInvoker选取适当的Action来执行。在Controller中,Action可以声明参数也可以不声明参数;ActionInvoker根据当前的RouteValue及客户端传来的信息准备好可输入到Action参数的数据,并正式调用被选中的Action对应的方法。
(2) Controller在执行时,还有动作过滤器(Action Filter)机制,过滤器主要分为授权过滤器(Authorization Filter)、动作过滤器(Action Filter)、结果过滤器(Result Filter)和异常过滤器(Exception Filter)。
(3)当ActionInvoker找不到对应的Action可用时,默认会执行System.Web.Mvc.Controller类的HandlerUnkownAction方法,在此类中,HandlerUnkownAction方法默认会响应“HTTP 404无法找到资源”的错误信息
(4)由于HandlerUnkownAction方法在Controller类中被声明为virtual方法,所以可以在自己创建的各种Controller中覆盖为自己需要的实际处理流程。
二、C#特性
类似于关键字的描述性声明,以便批注编程元素(如类型、字段、方法和属性)。 编译运行时的代码时,它将被转换为 Microsoft 中间语言 (MSIL),并和编译器生成的元数据一起放置在可移植可执行 (PE) 文件内。 特性使你能够将额外的描述性信息放到可使用运行时反射服务提取的元数据中。 当你声明派生自 System.Attribute 的特殊类的实例时,编译器会创建特性。
.NET Framework 出于多种原因且为解决许多问题而使用特性。 特性描述如何将数据序列化、指定用于强制安全性的特征并限制通过实时 (JIT) 编译器进行优化,从而使代码易于调试。 特性还可记录文件的名称或代码的作者,或控制窗体开发过程中控件和成员的可见性。
4.2 动作名称选择器
public class HomeController : Controller
{
[ActionName(“OtherName”)]
public ActionResult Index()
{
return View();
}
}
//
// 当ActionInvoker选取Controller中Action时,默认会应用反射机制找到相同名字的方法,这个过程就是动作名称选择器(Action Name Selector)运作的过程,选择查找过程对Action的名称字符大小写不进行区分。
// 个人理解: 在index上加了actionname之后,原本的index便不可访问
4.3 动作方法选择器
public class HomeController : Controller
{
[NonAction] // 加上这个不会发布到web隐藏了,或者用 private
public ActionResult Index()
{
return View();
}
}
4.4 过滤器属性
授权过滤器:
授权:认证和授权(判断用户是否存在;角色,以及能做到业务)
AutorizationFilter
[Authorize]
// 新的使用oauth2.0 认证授权分开
// 检查用户是否登陆和身份(user admin)一大堆的判断
// [Authorize]
// [Authorize(Users ="admin,user"] // 允许配置的账号
// [Authorize(Roles="user,admin,root")] // 允许配置的角色使用
利用FormsAuthentication机制验证的基本步骤:
- <authentication mode="Forms">
<forms loginUrl="~/Account/login" timeout="2880">
- 对保护资源添加[Authorize]
- 实现认证逻辑,并保存登录信息
[ChildActionOnly] :只能由Rederaction请求,添加一些附加信息,(不需要用户请求)
- 在控制器上加入[ChildActionOnly]
- 在需要的网页上:@{Html.RenderAction("[action]","[控制器]");}
// 前提有访问权限,不然加[AllowAnonymous]
[RequireHttps] : 网站支持https协议
[ValidateInput(true/false)] : true会验证 检测恶意代码
[ValidateAntiForgeryToken] : 阻止跨站请求 在html中也要加入@Html.AntiForgeryToken();
授权:
在没有数据库的情况下 web.config 13行 加入
<authentication mode="Forms">
<forms loginUrl="~/home/login" timeout="2880"> //登陆页,被保护的页面会重定向到这个地址 后面是超时时间
<credentials passwordFormat="Clear">
<user name="user" password="1234"/>
<user name="admin" password="123456"/>
</credentials>
</forms>
</authentication>
在要保护地方加上 [Authorize]
public class HomeController : Controller
{
// [Authorize(Users ="admin")] // 指定只有 admin才能登陆
[Authorize] // 通过授权过滤器就可进入
// [AllowAnonymous] // 匿名登陆,搭配Roles默认使用admin登陆
public ActionResult Index(string id ,string name)
// 对应的是views/home/index.cshtml
{
return View();
}
在另一个控制器 应该在同一个控制器里也行,只是我没试
public class AccountController : Controller
{
// GET: Account
public ActionResult Login() // 视图
{
return View();
}
[HttpPost]
public ActionResult Login(string username ,string password,string returnUrl) // 数据处理
{
bool result = FormsAuthentication.Authenticate(username,password); // 认证 判断用户是否存在
if (result)
{
FormsAuthentication.SetAuthCookie(username,false); // 保存用户名称到Cookie
HttpContext.Session.Add("name", username); // 应该是添加到session
return Redirect(returnUrl ?? Url.Action("Index","home")); // 返回路径
}
else
{
ModelState.AddModelError("", "账号或者密码错误"); // 新建模型错误 第一个就是空"",第二个才能填"123123"
return View();
}
}
}
login.cshtml:
@using (Html.BeginForm()) { // 要在这里面写才会识别
Html.ValidationSummary(); // 母鸡
<form action="/Accout/Login" method="post">
<input type="text" name="username" value="" />
<br />
<input type="password" name="password" value="" />
<button>登陆</button>
</form>
}
自定义授权过滤器:
继承:AuthorizeAttribute类
重写:AuthorizeCore方法
获取特性中的Roles值,获取当前用户的权限,匹配Roles值和当前用户权限,如果一致返回真,否则返回假
CustomAuthAttribute.cs:
protected override bool AuthorizeCore(HttpContextBase httpContext) {
var umapes = new Dictionary<string, string>();//所有用户名 角色(权限)的对应表
umapes.Add("user","User");
umapes.Add("admin", "Admin");
var attrroles=this.Roles;
string currentuser = httpContext.Session["name"]?.ToString();
if (string.IsNullOrEmpty(currentuser))
{
return false;
}
if (!umapes.ContainsKey(currentuser))
{
return false;
}
var userole = umapes[currentuser]; //
if (attrroles.Contains(userole)) // 比较是否包含
{
return true;
}
else
{
return false;
}
}
动作:记录日志(用户,ip,操作)
Action Filter
结果:返回view的时候使用
Result Filter
[OutputCache(Duration =20)] // 缓存时间20秒
异常:程序出现问题后如何处理
Exception Filter
web.config:
过滤器的主要作用:职责分明,适合团队协作,提高生产效率,降低成本
4.5 动作执行结果
bilibili mvc
基础
App_Start/
- BundleConfing.cs // 打包器 压缩,更新文件时时满足打包规则
- FilterConfing.cs // 过滤器
- RouteConfing.cs // 路由
Controllers/ //控制器文件夹
- HomeController.cs // 控制器名称
views/ // 视图文件夹
- Home/ // 对应控制器名称的文件夹
- index.cshtml // 对应控制器中的ActionResult
- shared // 公共文件夹
- _Layout.cshtml
// 类似于模板文件,里面 @RenderBody()会变成对应的/Views/*/*.cshtml
// 如果某个页面不想用,在页面最上方的@{}中加入 Layout=null;
- _ViewStart.cshtml // 指定用哪一个
- 文件内容:
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
控制器内置对象:
Request 请求
// 服务器接收客户端数据
Request.MapPath() // 将虚拟路径转换为物理路径
get请求
Request.QueryString[""]
多值$"{Request.QueryString[""]}-{Request.QueryString[""]}" ,请求时?name=123&id=321
post请求
- controller
Request.Form[""]
- html :
<form action="/Login/PostDate" method="post">
<input type="text" name="loginname" value="" />
<button>提交</button>
</form>
post 上传文件:
- controller:
Request.Files["file"].SaveAs(Request.MapPath("~/uploads/"+Request.Files["file"].FileName));
return Content("ok");
- html:
<form action="/Login/FileDate" method="post" enctype="multipart/form-data">
<input type="file" name="file" value="" />
<button>提交</button>
</form>
Response 响应
Response.Write("hello world !"); // 向客户端输出内容
Response.Redirect("htpp://www.baidu.com"); // 重定向
Response.Headers["hello"] = "world"; // 加一个请求头
return Content(Request.Headers["token"]); // 不明白
Session 会话
// 从请求网站开始就开始了,存在二十分钟,点击之后重新计时,数据保存在服务器中,且会话独立
// session越多,内存占用越多
// session 90%用于存少量重要信息,如登陆后的账号
// session 是一个键值对 Key:value
session.add([Key],[value]) // 保存
session[Key] // 获取
Session["user"] = Request.Form["user"]; // session的值=post上传的"user"
Session["user"].Abandon(); // 清除session
Session["user"].Clear(); // 清除session
Cookie 客户端数据
// 不安全 不可靠 有时效性
Response.Cookies.Add(new HttpCookie("token")
{
Value = "abc123321cba",
Expires=DateTime.Now.AddDays(7 ) // 时效性,不加的话接收到就失效,时间是格林尼治时间,-8小时
// 清除cookie还是这句,把时间改为-1就行
}) ;
return Content("ok");
// response的数据由request查看
Application 当前网站对象
HttpContext.Application["user"] = "123"; // 赋值
Content(HttpContext.Application["user"].ToString()); // 取值
// 整个项目共有
Server 服务器对象
// .MapPath 虚拟路径转物理路径
// .HtmlEncode
// .HtmlDecode
Server.Transfer("/[页面]"); // 转发,路径不变,页面改变,与重定向不同,且不能转发外站
控制器把数据传给界面
public ActionResult Index()
{
// 一般存放一些不主要的数据
ViewBag.zyx="zyxweb.cn"; // 在视图index中直接@ViewBag.zyx即可使用
ViewData["zyx"] = 40; // 在试图index中ViewData["zyx"]
// 这两个是一样的,现在ViewBag.zyx==40
TempData["hello"]="world" //在视图中加@TempData["hello"] 本质就是session且只能调用一次
return View(new student(){Id =1, Age=20}); // 可以传对象,但不能传多个 // 且亦在model文件夹下新建了类并在控制器引入了命名空间
// 在视图中 想有对象的提示可以添加: @model [项目名].Models.student 且model里的数据类型一定要和View方法参数里的model类型一致 别别忘了在控制器引入命名空间
return View("页面名字","模板页",[对象]) // 可以转发
}
把数据从界面传到控制器
public ActionResult Index(string name)
// 在浏览器地址栏/controller/action?zyx 使用get方法 或者直接表单提交都可以
[HttpGet]
public ActionResult Index(string name)
// 限制只能Get请求
/Models/LoginViewModel
public class LoginViewModel
{
[Display(Name ="电子邮件")]
[EmailAddress]
[Required,StringLength(10,MinimumLength =2)]
public string Email { get; set; }
[Display(Name ="密码")]
[DataType(DataType.Password)]
[Required,MinLength(6)]
public string Password { get; set; }
}
// DemoController
----------------------------------------------------------------------------
[HttpGet]
public ActionResult Login()
{
return View();
}
// 登陆界面
----------------------------------------------------------------------------
[HttpPost]
[ValidateAntiForgeryToken] // 浏览器也要设置 @Html.AntiForgeryToken() 防伪戳
public ActionResult Login(Models.LoginViewModel model )
{
if (ModelState.IsValid) // 添加数据验证,不加这一步类里的数据校验便
{
if (model.Email == "admin" && model.Password == "123")
return View();
else
ModelState.AddModelError("","账号或者密码出错");
return View(model);
}
else {
ModelState.AddModelError("", "账号或者密码出错");
return View(model);
}
// 微软通过使用类来写 在model文件夹下新建了类并在控制器引入了命名空间
// 数据验证
// 右键Login-> 添加视图,模板Create,模型类-> LoginViewModel,引用脚本库,添加
Result
ViewResult
// 返回相应的视图
ContentResult
// 返回字符串
RedirectResult
// 重定向
RedirectToAction
// 跳转action方法 路由跳转
FileResult
// 向客户端输出文件
JsonResult
// 向客户端返回对象的json序列化后的结果
HttpStatusCodeResult
// 显示不同的状态码信息
PartialView
// 部分页面 类似于组件