一. 前世今生

  乍眼一看,该标题写的有点煽情,最近也是在不断反思,怎么能把博客写好,让人能读下去,通俗易懂,深入浅出。

  接下来几个章节都是围绕框架本身提供特性展开,有MVC程序集提供的,也有其它程序集提供;在本章节将重点介绍几个MVC框架提供的且作用于方法上的特性,并且模仿其源码自定义特性。

  其实早在前面的 DotNet进阶章节,就写过一篇关于特性的文章了,这里重新总结一下特性核心要点。

     1. 什么是特性?

   特性是一个类,在不影响程序封装的情况下,额外的给程序添加一些信息,用于运行时描述程序或者影响程序的行为。

  2. 特性的作用范围?

   提到特性的作用范围,就不得不提到 AttributeUsage了,该类本身就是一个特性,继承了Attribute类,用于约束自定义特性(你可以看到系统提供的很多特性中,均能看到它的身影),下面先看一        下它的源码:

    

   该特性有一个参数,两个核心属性,AttributeTargets参数约束了该给特性可以作用的范围,通过右面的代码可知,可以作用于:类、方法、参数、属性、返回值等等,该参数默认为ALL。

    AllowMultiple:约束该特性能否同时作用于某个元素(类、方法、属性等等)多次,默认为false。

Inherited:约束该特性作用于基类(或其它)上,其子类能否继承该特性,默认为true。

  3. 如何自定义特性?

    简单来说,声明一个以Attribute结尾的类,继承Attribute类,然后加上AttributeTargets特性约束,一个简单的特性就产生了。

二. MVC中的常用特性

  有了前面的铺垫,这里讲解【System.Web.Mvc】程序集下的一些特性就很好理解,理解源码的同时,主要掌握其如何使用。

    MVC中提供的常用特性有:【HttpGet】、【HttpPost】、【AcceptVerbs】、【ActionName】、【NoAction】、【AllowAnonymous】、【ValidateAntiForgeryToken】、【ChildActionOnly】、【Bind】这九个特性。

  查看源码可知,其中【HttpGet】【HttpPost】【AcceptVerbs】【ActionName】【NoAction】【ChildActionOnly】均继承ActionNameSelectorAttribute类,实现了IsValidForRequest这个抽象方法,且特性约束为: [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)],显然这些特性均是作用于方法上的,且不需要同时作用,允许子类继承该特性。

  以【HttpGet】的源码为例:

  其中【AllowAnonymous】直接继承Attribute类,源码如下:

  

  其中【ValidateAntiForgeryToken】继承了FilterAttribute类,实现了IAuthorizationFilter接口,源码如下:

  (扩展一下:AuthorizeAttribute类也是继承了FilterAttribute类,实现了IAuthorizationFilter接口)

1. HttpGet和HttpPost

(1).  HttpGet:只允许Get请求访问

底层运用的AcceptVerb特性实现的,所以等价于[AcceptVerbs(HttpVerbs.Get)]或[AcceptVerbs("Get")]

测试:前端用Ajax请求,如果非Get请求方式进行请求,则提示404找不到

(2).  HttpPost:只允许Post请求访问

底层运用的AcceptVerb特性实现的,所以等价于[AcceptVerbs(HttpVerbs.Post)]或[AcceptVerbs("Post")]

测试:前端用Ajax请求,如果非Post请求方式进行请求,则提示404找不到

 特别注意:如果一个方法要同时允许Get和Post请求[HttpGet]和[HttpPost]同时加载上面是错误的!!这个时候就需要使用AcceptVerb特性了(当然方法上如果什么特性也不加,什么请求均支持)

2. AcceptVerbs

AccetpVerbs:用于限定请求方式(包括:Get、Post、Put、Delete、Head、Patch、Options)

查看源码可知:该特性有两个构造函数,所有两种写法,如:只允许Get请求,可以:[AcceptVerbs(HttpVerbs.Get)]和[AcceptVerbs("Post")]

若要同时支持多种请求,可以:[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]或[AcceptVerbs("Get", "Post")]

相关测试代码如下:

        //1. 下面三种写法均为只允许Get请求
//[HttpGet]
//[AcceptVerbs(HttpVerbs.Get)]
//[AcceptVerbs("Get")] //2. 下面三种写法均为只允许Get请求
//[HttpPost]
//[AcceptVerbs(HttpVerbs.Post)]
//[AcceptVerbs("Post")] //3. 下面两种写法表示:既允许Get请求也允许Post请求
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
//[AcceptVerbs("Get", "Post")]
public ActionResult TestMethordWay()
{
return Content("请求成功");
}
         //1. 测试只允许Get或Post请求
$("#btn1").click(function () {
$.ajax({
type: "Put", //Post 、Put
url: "TestMethordWay",
data: "",
success: function (msg) {
alert(msg);
}
});
});

3. ActionName

ActionName:修改Action本身的方法名

测试:请求TestActionName1方法,报404找不到

请求TestActionName2方法,正常访问

相关测试代码如下:

         /// <summary>
/// 名字变为:TestActionName2了
/// </summary>
/// <returns></returns>
[ActionName("TestActionName2")]
public ActionResult TestActionName1()
{
return Content("我是TestActionName1");
}
    //2. 测试ActionName特性
$("#btn2").click(function () {
$.ajax({
type: "Get",
url: "TestActionName2", //TestActionName1
data: "",
success: function (msg) {
alert(msg);
}
});
});

4. NoAction

NoAction: 标记控制器中的action将不在是一个方法,不能前端Http请求访问

测试:前端页面ajax进行请求,报404找不到

     但在其它action中进行调用,能正常调用

相关测试代码如下:

        /// <summary>
/// 标记该方法将不是一个方法
/// </summary>
/// <returns></returns>
[NonAction]
public ActionResult TestNoAction()
{
return Content("请求成功");
}
   //3. 测试NoAction特性
$("#btn3").click(function () {
$.ajax({
type: "Get",
url: "TestNoAction", //TestNoAction
data: "",
success: function (msg) {
alert(msg);
}
});
});

5. AllowAnonymous

AllowAnonymous:该特性用于标记在授权期间要跳过 AuthorizeAttribute 过滤器的验证

解释:AuthorizeAttribute是MVC框架自带的实现IAuthorizationFilter过滤器的一个类,内部有一套自身业务验证(感兴趣的可以自己研究源码)

而AllowAnonymous就是为了标记跨过AuthorizeAttribute验证的

这里不做详细测试

6. ValidateAntiForgeryToken

ValidateAntiForgeryToken:阻止跨站请求伪造攻击(CSRF).

①. CSRF原理是什么:

  a.用户mr访问正规网站A,登录验证通过,并在用户mr处产生Cookie

  b.用户mr在不关闭A网站的情况下打开危险的B网站,在B网站中要求访问A网站,发出一个Request请求

  c.这时候浏览器带着A网站在mr出产生的Cookie进行访问A网站

  d.这时候A网站就无法判断这个cookie是谁产生的,默认就给通过了

详细见:https://www.cnblogs.com/hechunming/p/4647646.html

②:解决方案

  a. 在Controller中的action上加上特性[ValidateAntiForgeryToken]

  b. 对于增删改查操作前端调用: $.ajaxAntiForgery方法进行ajax请求(需要引入jqueryToken的js文件)

这里不做详细测试

7. ChildActionOnly

ChildActionOnly:限制操作方法只能由子操作进行调用。

  ①. 测试直接输入:http://localhost:7559/SpecialAttribute/Index2, 无法访问报错.

  ②. 需要通过RenderAction来调用(存在问题,与Unity改造框架冲突冲突)

这里RenderAction不做详细测试

8. Bind

①. 源码的角度分析:该特性可以作用于类或参数(本章节测试作用于参数)

②. 该特性有三个核心属性:

  a. Exclude:获取或设置不允许绑定的属性名称的列表(各属性名称之间用逗号分隔)

  b. Include:获取或设置允许绑定的属性名称的列表(各属性名称之间用逗号分隔),与Exclude一个道理,通常根据情况使用一个即可

  c. Prefix:获取或设置在呈现表示绑定到操作参数或模型属性的标记时要使用的前缀

不适用与ajax提交,适用于razor语法中的@{Html.TextBox(stu.id)},在现在前后端分离盛行的情况下,有点不适合了

测试:

  前端过个ajax传过来三个参数:id、name、sex, 参数中的stu只能收到id和name,sex为null,若想收到sex,需要在方法中通过request进行接收

         /// <summary>
/// stu中的sex属性为null
/// var 中sex为男
/// </summary>
/// <param name="stu"></param>
/// <returns></returns>
public ActionResult TestBindAttribute([Bind(Include = "id,name")]Student stu)
{
var sex = Request["sex"];
return Content("请求成功");
}
          //4.测试BindAttribute特性
$("#btn4").click(function () {
$.ajax({
type: "Get",
url: "TestBindAttribute",
data: {"id":"123","name":"ypf","sex":"男"},
success: function (msg) {
alert(msg);
}
});
});

三. 自定义一个类似的特性

要求:支持Get请求,且必须是Ajax请求

思路:由HttpGet特性可以知道:需要继承ActionMethodSelectorAttribute类,然后覆写IsValidForRequest方法即可

     public class HttpGetAndAjaxAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)
{
//1.获取请求方式
string HttpWay = controllerContext.HttpContext.Request.GetHttpMethodOverride(); //2. 获取是否是Ajax请求
bool isAjax = controllerContext.HttpContext.Request.IsAjaxRequest(); if (HttpWay.ToLower() == "get" && isAjax == true)
{
return true;
}
return false; }
} [HttpGetAndAjax]
public ActionResult GetAndAjax()
{
return Content("请求成功");
}
         //5.测试自定义特性
$("#btn5").click(function () {
$.ajax({
type: "Get",
url: "GetAndAjax",
data: "",
success: function (msg) {
alert(msg);
}
});
});

第九节:从源码的角度分析MVC中的一些特性及其用法的更多相关文章

  1. 从源码的角度分析ViewGruop的事件分发

    从源码的角度分析ViewGruop的事件分发. 首先我们来探讨一下,什么是ViewGroup?它和普通的View有什么区别? 顾名思义,ViewGroup就是一组View的集合,它包含很多的子View ...

  2. 从Android源码的角度分析Binder机制

    欢迎访问我的个人博客,原文链接:http://wensibo.top/2017/07/03/Binder/ ,未经允许不得转载! 前言 大家好,好久不见,距离上篇文章已经有35天之久了,因为身体不舒服 ...

  3. 第74讲:从Spark源码的角度思考Scala中的模式匹配

    今天跟随王老师学习了从源码角度去分析scala中的模式匹配的功能.让我们看看源码中的这一段模式匹配: 从代码中我们可以看到,case RegisterWorker(id,workerHost,.... ...

  4. 从源码的角度分析List与Set的区别

    很多时候我们在讨论List与Set的异同点时都在说: 1.List.Set都实现了Collection接口 2.List是有序的,可以存储重复的元素,允许存入null 3.Set是无序的,不允许存储重 ...

  5. [转]Android事件分发机制完全解析,带你从源码的角度彻底理解(上)

    Android事件分发机制 该篇文章出处:http://blog.csdn.net/guolin_blog/article/details/9097463 其实我一直准备写一篇关于Android事件分 ...

  6. 从源码的角度解析View的事件分发

    有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图 ...

  7. 【转】Android事件分发机制完全解析,带你从源码的角度彻底理解(下)

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/9153761 记得在前面的文章中,我带大家一起从源码的角度分析了Android中Vi ...

  8. 从源码的角度解析Mybatis的会话机制

    坐在我旁边的钟同学听说我精通Mybatis源码(我就想不通,是谁透漏了风声),就顺带问了我一个问题:在同一个方法中,Mybatis多次请求数据库,是否要创建多个SqlSession会话? 可能最近撸多 ...

  9. Android AsyncTask完全解析,带你从源码的角度彻底理解

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/11711405 我们都知道,Android UI是线程不安全的,如果想要在子线程里进 ...

随机推荐

  1. LinuxCPU性能监控工具---mpstat

    mpstat是 Multiprocessor Statistics的缩写,是实时系统监控工具.其报告与CPU的一些统计信息,这些信息存放在/proc/stat文件中.在多CPU系统里,其不但能查看所有 ...

  2. springboot项目屏蔽mq或者mongodb的监控日志输出

    最近写项目,用的是springboot,其中用到了rabbitmq和mongodb,配置完成 项目启动后,会输出如下日志: mongodb和mq的检测,会一直打印日志,这样会影响开发人员的测试. 如何 ...

  3. Flafka: Apache Flume Meets Apache Kafka for Event Processing

    The new integration between Flume and Kafka offers sub-second-latency event processing without the n ...

  4. SQL ROUND() 函数

    ROUND() 函数 ROUND 函数用于把数值字段舍入为指定的小数位数. SQL ROUND() 语法 SELECT ROUND(column_name,decimals) FROM table_n ...

  5. 转://linux下的CPU、内存、IO、网络的压力测试工具与方法介绍

    转载地址:http://wushank.blog.51cto.com/3489095/1585927 一.对CPU进行简单测试: 1.通过bc命令计算特别函数 例:计算圆周率 echo "s ...

  6. 微信小程序 初步认识一(微信运动步数)

    1.注册微信小程序 2.安装小程序开发工具 3.实例(显示微信运动步数) 4.后端处理(c#) 一 注册微信小程序 注册地址:https://mp.weixin.qq.com/cgi-bin/regi ...

  7. 【Android】pidcat 不显示日志输出

    问题: 直接安装了 pidcat :  brew install pidcat ,装完以后执行 pidcat <package name> ,发现没有日志输出,adb devices 也能 ...

  8. rsync用法详细解释

    提要 熟悉 rsync 的功能及其特点 掌握 rsync 语法及常用选项的功能 掌握 rsync 命令的三种基本使用方法 掌握如何筛选 rsync 的传输目标 掌握使用 rsync 进行镜像和增量备份 ...

  9. Windows 与Office 镜像的区别

    .SW开头是批量授权的版本. .CN开头是简体中文版镜像文件 零售版本. 其实建议使用 SW开头的镜像 可以直接使用KMS进行激活了. 转帖一个百度知道的内容: 看安装包的名称 cn开头的是零售版的, ...

  10. 使用ffmpeg视频切片并加密

    想达到的目的:将一个mp4视频文件切割为多个ts片段,并在切割过程中对每一个片段使用 AES-128 加密,最后生成一个m3u8的视频索引文件: 电脑环境 Fedora,已经安装了最新的ffmpeg: ...