Attribute分多种

Attribute称为特性,语法:特性(Attribute)的名称和值是在方括号内规定的,放置在它所应用的元素之前。

1、FilterAttribute(过滤器)可以看出mvc 引用的是System.Web.Mvc,webapi 引用的是System.Web.Http.Filters ,不知道小伙伴们有看出来别的区别没有,对的,有的 ,虚方法传入类不同,这样导致传入构造与输出构造也将不同了。

ActionFilterAttribute过滤器-基于Web.MVC

自定义Filter需要继承ActionFilterAttribute抽象类:例如Action控制器用于登录时候的验证有四种:分别

public class FilterAttribute : ActionFilterAttribute
{
public string Message { get; set; } public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
filterContext.HttpContext.Response.Write("Action执行之前" + Message + "<br />");
} public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.HttpContext.Response.Write("Action执行之后" + Message + "<br />");
} public override void OnResultExecuting(ResultExecutingContext filterContext)
{
base.OnResultExecuting(filterContext);
filterContext.HttpContext.Response.Write("返回Result之前" + Message + "<br />");
} public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
filterContext.HttpContext.Response.Write("返回Result之后" + Message + "<br />");
}
} 

  然后在调用过滤器的时候,添加上该参数,Controller代码如下:

[Filter(Message="刘备")] //参数给上
public ActionResult Index()
{
return View();
} 

另一种使用方式是进入Control执行下Action也执行一下

通过如果标签打到Controller上的话,TestFilterAttributeFilter将作用到Controller下的所有的Action。

  默认情况下Action上打了某个自定义标签后,虽然在Controller上也打上了此标签,但它只有Action上的标签起作用了。
  补充:如果Action没有打上该标签,那么Controller上的标签便会被执行。

如果想让Action上的标签执行一次,然后Controller上的标签也执行一次,那么应该如何操作呢?

我们只需在FilterAttribute类的定义上打上标记[AttributeUsage(AttributeTargets.All, AllowMultiple = true)]即可也就是让其成为可以多次执行的Action。

[AttributeUsage(AttributeTargets.All,AllowMultiple = true)]
public class FilterAttribute : ActionFilterAttribute
{
public string Message { get; set; }
......

  

有时我们想有些公共的方法需要每个Action都执行,但是又不想再每一个Controller上都打上Action标签?答案就在Global.asax中。

如果是WebAPI则是WebApiConfig.cs中配置全局。

例如:项目Session过滤

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace WebDemo
{
public class LoginAttribute: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var user = HttpContext.Current.Session["user"];
if (user==null)
{
filterContext.HttpContext.Response.Write("<script>top.location.href = '/Account/Index'</script>");
}
}
}
}

  使用方式

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace WebDemo.Controllers
{
[Login]
public class HomeController : Controller
{
// GET: Home
public ActionResult Index()
{
return View();
}
}
}

ActionFilterAttribute过滤器-基于Web.Http.Filters

WebAPI 执行Action执行后执行的过滤器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http.Filters; namespace WebApplication2.App_Start
{
public class VLDHousingEnquiriesAttribute :ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
//抓取API控制器返回的值 注:该控制器必须是WebApi类型的控制器
/*
public string index()
{
return "请求成功!";
}
*/
var data = actionExecutedContext.ActionContext.Response.Content.ReadAsAsync<object>().Result;
/*即data="请求成功!"*/ if (data.ToString() != "请求成功!")
{
// 取得由 API 返回的状态代码
var StatusCode = actionExecutedContext.ActionContext.Response.StatusCode;
//请求是否成功
var IsSuccess = actionExecutedContext.ActionContext.Response.IsSuccessStatusCode;
//判断基本请求是经过action的状态标识
//结果转为自定义消息格式
var str = new { dsa = "更改action内容" };
HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(str.ToString(), Encoding.GetEncoding("UTF-8"), "application/json") };
// 重新封装回传格式
actionExecutedContext.Response = result;//过滤器内部会监听内容是否被改变
return;
}
else
{
//这里不做任何更改
}
}
}
}

 

  执行action之前执行的过滤器

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters; namespace Web.App_Start
{
public class VLDApiAttribute
{
}
public class VLDHousingEnquiriesAttribute : ActionFilterAttribute //必须引用using System.Web.Http.Filters;
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
/*var str = new { dsa = "dasdas" };
HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(str.ToString(), Encoding.GetEncoding("UTF-8"), "application/json") };
actionContext.Response = result;*/ //如果不注释就不会执行action 因为你拿到过滤器的actionContext上下文 进行Response操作了。
        //var request = HttpContext.Current.Request;var s = request["apiId"];
base.OnActionExecuting(actionContext);
} }
}

  

Executing->Action->Executed

using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Http.Filters;
using WebApplication2.Controllers; namespace WebApplication2.App_Start
{
public class VLDHousingEnquiriesAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
{
/*var str = new { dsa = "dasdas" };
HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(str.ToString(), Encoding.GetEncoding("UTF-8"), "application/json") };
actionContext.Response = result;*/ //上面将做实体验证,判断是否返回Response值对应将执行不执行Action和Executed(Executed是跟在Action后的,Action都不执行何来的Executed)
base.OnActionExecuting(actionContext);
} /* //Action是WebApi类型
[VLDHousingEnquiriesAttribute]
[HttpGet]
public dynamic index()
{
return new { id = "3",name="5" };
}
*/ public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var response = actionExecutedContext.Response = actionExecutedContext.Response ?? new HttpResponseMessage();
var data = response.Content.ReadAsAsync<object>().Result; if (data.ToString() == "请求成功!")//通过判断返回Response值封装请求 这里Data是json对象 返回都要转换 Json字符串传到前台
{
// 取得由 API 返回的状态代码
var StatusCode = response.StatusCode;
//请求是否成功
var IsSuccess = response.IsSuccessStatusCode;
//结果转为自定义消息格式
var str = new { dsa = "更改action内容" };
// 重新封装回传格式
//HttpResponseMessage result = new HttpResponseMessage { Content = new StringContent(str.ToString(), Encoding.GetEncoding("UTF-8"), "application/json") };
//actionExecutedContext.Response = result;//过滤器内部会监听内容是否被改变
//或者
response.Content = new StringContent(Json.Encode(str), Encoding.UTF8, "application/json");//过滤器内部会监听内容是否被改变
return;
}
else
{
//这里不做任何更改
} } }
}

  

  

在OnActionExecuting中阻止后面Action的执行

 filterContext.Result = new HttpNotFoundResult();//阻止后续Action的执行  原理一样改变了 Result基于 mvc的过滤器。原由是:filterContext.Result只要不为空Action就会终止。直接响应请求。

带参数的自定义Filter

还是按照之前添加自定义过滤器的方法,添加一个自定义过滤器,只是里面多了一个属性,代码如下:

public class FilterAttribute : ActionFilterAttribute
{
public string Message { get; set; } public override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
filterContext.HttpContext.Response.Write("Action执行之前" + Message + "<br />");
} public override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.HttpContext.Response.Write("Action执行之后" + Message + "<br />");
} public override void OnResultExecuting(ResultExecutingContext filterContext)
{
base.OnResultExecuting(filterContext);
filterContext.HttpContext.Response.Write("返回Result之前" + Message + "<br />");
} public override void OnResultExecuted(ResultExecutedContext filterContext)
{
base.OnResultExecuted(filterContext);
filterContext.HttpContext.Response.Write("返回Result之后" + Message + "<br />");
}
}

  

[Filter(Message="刘备")]  //参数给上
public ActionResult Index()
{
return View();
}

  输出结果如下:

AuthorizeAttribute过滤器-基于Web.Http.Filters还是MVC 看你是MVC控制器还是WebAPI

使用场景:1、未登录访问功能模块的时候 2、未登录获取分页数据  解决方式1、 父控制器继承处理 2、过滤器

1、重写Authorize有以下几个要点需注意:

1、HandleUnauthorizedRequest中基类方法已经将Response的状态设为”HttpStatusCode.Unauthorized(即401)“,重写时手请动改为”HttpStatusCode.Forbidden(即403)“,否则按401状态往下执行,就要被重定向到登录页-401错误又对应了Web.config中的

<authentication mode="Forms">

<forms loginUrl="~/" timeout="2880" />

</authentication>

2、webApi下的授权筛选attribute为System.Web.Http.AuthorizeAttribute,而Mvc下用的是System.Web.Mvc.AuthorizeAttribute。这里别继承错了,否则授权筛选attrbute拦截不了。

3、WebApi下Authorize.HandleUnauthorizedRequest的参数filterContext在此上下文里response还为空,需要手动创建。

/// <summary>
/// 重写实现处理授权失败时返回json,避免跳转登录页
/// </summary>
public class ApiAuthorize : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext); var response = filterContext.Response = filterContext.Response ?? new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Forbidden;
var content = new Result
{
success = false,
errs = new[] { "服务端拒绝访问:你没有权限,或者掉线了" }
};
response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
}
}

  为防止上下文为null

var response = filterContext.Response = filterContext.Response ?? new HttpResponseMessage();
或者
if (filterContext == null )
{
throw new ArgumentNullException( "filterContext" );
}else
{
string path = context.HttpContext.Request.Path;
string strUrl = "/Account/LogOn?returnUrl={0}" ;
context.HttpContext.Response.Redirect( string .Format(strUrl, HttpUtility.UrlEncode(path)), true );
}

  

chrome下查看返回状态:

还有一种方式

跨域攻击---自然来路页面和目标页面不在同一个域下,所以直接判断来路域和当前自己的域就可以了。

比如内嵌Iframe或者Ajax调用的

代码顺序为:OnAuthorization-->AuthorizeCore-->HandleUnauthorizedRequest

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc; namespace Admin.MyAttribute
{
[AttributeUsage(AttributeTargets.All, Inherited = true)]
public class CheckAuthority : AuthorizeAttribute
{ protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool Pass = true;
Uri UrlReferrer = httpContext.Request.UrlReferrer;//获取来路
if (UrlReferrer == null)
{
httpContext.Response.StatusCode = 401;//无权限状态码 Pass = false;
}
else
{
Uri ThisUrl = httpContext.Request.Url;//当前请求的URL
if (UrlReferrer.Authority != ThisUrl.Authority)
{
httpContext.Response.StatusCode = 401;//无权限状态码
Pass = false;
}
} return Pass;
} protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
base.HandleUnauthorizedRequest(filterContext);
if (filterContext.HttpContext.Response.StatusCode == 401)
filterContext.Result = new RedirectResult("/");
} }
}

  AuthorizeAttribute的OnAuthorization方法内部调用了AuthorizeCore方法,这个方法是实现验证和授权逻辑的地方,如果这个方法返回true,

  表示授权成功,如果返回false, 表示授权失败, 会给上下文设置一个HttpUnauthorizedResult,这个ActionResult执行的结果是向浏览器返回。   

  关于 HttpUnauthorizedResult 测试 结果可以这样写 filterContext.Result = new HttpUnauthorizedResult("no authentication");

调用方法

 [MyAttribute.CheckAuthority]--先验证,通过验证才执行
public ActionResult Index()
{ return View();
}

 

当我们因不想每个控制器都添加授权属性的时候,而在全局配置文件内注册后,如果有些控制器的action方法不需要验证,则在action上添加属性[AllowAnonymous]

注意:

WebApi层接口效果示例

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using Web.Common.Method;
using Web.Common.ReqResult;
using WebBLL;
using WebCommon; namespace Web.App_Start
{
public class SignVerifyAttribute : ActionFilterAttribute
{
private static readonly int ApiMinutes = Convert.ToInt32(ConfigHelper.GetConfigValue("ApiMinutes")); //请求超时时间
private static readonly IList<string> BaseParamKey = new List<string>()
{
"apiId" //必填-用户标识
, "timeStamp"//必填-时间戳[单位毫秒]
, "nonce_Str"//必填-随机字符串
, "sign" //必填-签名
};
public override void OnActionExecuting(HttpActionContext actionContext)
{ try
{
var context = (HttpContextBase)actionContext.Request.Properties["MS_HttpContext"];
var param = new NameValueCollection();
var method = context.Request.HttpMethod.ToUpperInvariant();
param = method.Equals("GET", StringComparison.OrdinalIgnoreCase) ? context.Request.QueryString : context.Request.Form;
#region 判断基础参数是否存在
foreach (var item in BaseParamKey)
{
if (!param.AllKeys.Any(x => x.Trim().Equals(item, StringComparison.OrdinalIgnoreCase)))
{
var response = actionContext.Response = actionContext.Response ?? new HttpResponseMessage();
var content = new ReqResult<string>
{
code = Convert.ToString((int)SatausCode.CommonCode.incomplete),
message = item + SatausCode.GetDisplayDescription(SatausCode.CommonCode.incomplete),
result = null
};
response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
return;
}
}
#endregion
#region 验证时间戳格式&&请求时间
var currentTimeStamp = OperData.GetTmeStamp(DateTime.Now);
var getTimeStamp = param["timestamp"];
long getIntTimeStamp = 0;
if (!long.TryParse(getTimeStamp, out getIntTimeStamp))
{
var response = actionContext.Response = actionContext.Response ?? new HttpResponseMessage();
var content = new ReqResult<string>
{
code = Convert.ToString((int)SatausCode.CommonCode.timeStamp),
message = SatausCode.GetDisplayDescription(SatausCode.CommonCode.timeStamp),
result = null
};
response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
return;
}
//请求时间默认不能超过5分钟
if (Convert.ToInt64(currentTimeStamp) - getIntTimeStamp > new TimeSpan(0, 0, ApiMinutes, 0).Ticks)
{
var response = actionContext.Response = actionContext.Response ?? new HttpResponseMessage();
var content = new ReqResult<string>
{
code = Convert.ToString((int)SatausCode.CommonCode.timeout),
message = SatausCode.GetDisplayDescription(SatausCode.CommonCode.timeout),
result = null
};
response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
return;
}
#endregion
#region 验证ApiId用户是否有权限->生成key
string ApiKeyUserKey = Convert.ToString(CacheHelper.Instance.Get(String.Format(param["apiId"], "ApiKeyUserKey")));//仅获取key
if (ApiKeyUserKey == null)
{
var ApiKeyInfo = Tbl_ApiUserManager.GetTbl_ApiUserAll().Where(x => x.ApiId == param["apiId"]).SingleOrDefault();
if (!string.IsNullOrWhiteSpace(ApiKeyInfo.ApiId))
{
CacheHelper.Instance.Add(String.Format(ApiKeyInfo.ApiId, "ApiKeyUserKey"), ApiKeyInfo.ApiKey, 5);
}
else
{
var response = actionContext.Response = actionContext.Response ?? new HttpResponseMessage();
var content = new ReqResult<string>
{
code = Convert.ToString((int)SatausCode.CommonCode.power),
message = SatausCode.GetDisplayDescription(SatausCode.CommonCode.power),
result = null
};
response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
return;
}
}
#endregion
#region 按key升序排序的待签名字符串并将所有参数加密
//按key升序排序的待签名字符串
var str = new StringBuilder();
foreach (var key in param.AllKeys.OrderBy(x => x))
{
if (key.Equals("sign", StringComparison.OrdinalIgnoreCase))
{
continue;
}
str.AppendFormat("{0}={1}&", key, HttpUtility.UrlEncode(param.Get(key.Trim())));
}
str.AppendFormat("apikey={0}", ApiKeyUserKey);
var calSignature = OperData.MD5Encrypt16(str.ToString());
var signature = param.Get("sign").Trim();
if (!calSignature.Equals(signature, StringComparison.OrdinalIgnoreCase))
{
var response = actionContext.Response = actionContext.Response ?? new HttpResponseMessage();
var content = new ReqResult<string>
{
code = Convert.ToString((int)SatausCode.CommonCode.sign),
message = SatausCode.GetDisplayDescription(SatausCode.CommonCode.sign),
result = null
};
response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
return;
}
#endregion
}
catch (Exception ex)
{
var response = actionContext.Response = actionContext.Response ?? new HttpResponseMessage();
var content = new ReqResult<string>
{
code = Convert.ToString((int)SatausCode.CommonCode.ex),
message = SatausCode.GetDisplayDescription(SatausCode.CommonCode.ex),
result = null
};
response.Content = new StringContent(Json.Encode(content), Encoding.UTF8, "application/json");
return;
}
base.OnActionExecuting(actionContext);
}
}
}

我的业务 写接口的 ing 验证接口合法性 action 处理事件 ed 记录日志的 但是出现了 ing 验证 ed 不会执行的(ed里面的日志不记录了)具体是

onactionexecuting里面不让他进入action里面对么?

但是 会导致 onactionexecuted 这个记录日志的过滤器 也不执行了,解决方案:onactionexecuting 创建日志  通过状态码Guid ,然后如果经过在action就在 onactionexecuted 更新日志,否在就在不进入action也就不会进入onactionexecuted 的onactionexecuting 过滤器return false 上一行去更新。

(onactionexecuting、onactionexecuted 统简称ing和ed过滤器)

3、异常拦截器

1、创建拦截器并写入代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http.Filters;
using System.Web.Mvc; namespace Web.App_Start
{
/// <summary>
/// 异常拦截/实践通过拦截视图
/// </summary>
public class ExceptionFilterAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled)
{
return;
}
Exception ex = filterContext.Exception;
string message =
$"消息类型:{ex.GetType().Name}<br />" +
$"消息内容:{ex.Message}<br />" +
$"引发异常的方法:{ex.TargetSite}<br />" +
$"引发异常的对象:{ex.Source}<br />" +
$"异常目录:{filterContext.RouteData.GetRequiredString("controller")}<br />" +
$"异常方法:{filterContext.RouteData.GetRequiredString("action")}<br />" +
$"错误详细记录:{ex.StackTrace}";
/*string message = string.Format("<br>消息类型:{0}<br>消息内容:{1}<br>引发异常的方法:{2}<br>引发异常的对象:{3}"
, filterContext.Exception.GetType().Name
, filterContext.Exception.Message
, filterContext.Exception.TargetSite
, filterContext.Exception.Source);
string errorMessage = string.Format(
"Error Message: {0}<br/>Error StackTrace: {1}",
ex.message,
ex.StackTrace
);*/
filterContext.HttpContext.Response.Write(message);
filterContext.ExceptionHandled = true; //不报告异常
}
}
}

  

2、添加全局

3、运行测试

特例:

2、系统过滤器 OutputCache过滤器

1、ActionResult结果进行缓存,概括地说,就是当你的请求参数没有发生变化时,直接从缓存中取结果,不会再走服务端的Action代码了。

[OutputCache(Duration = 300)]
public ActionResult Index(int? id,string name)
{
return DateTime.Now.ToString();
}

  如果你重复调用Index() action(不断刷新当前页面), 那么你将看到当前的内容在Duration = 20秒内是不变的.

 

请求此Action的url可以为: person/Index?id=100&name="bird"。
当第一次请求这个地址时,会执行Index方法,并把结果缓存起来,且过期时间为300秒。
接下来,如果不改变id和name参数的前提下,在距离上次请求300秒内,再来请求这个地址,不会执行Index方法,直接从缓存中拿结果。
当id或者name的参数值发生变化时,发送请求时,会执行index方法,然后再缓存此结果。
[Output(Duration=300)],这种方法没有指明具体针对哪个参数来缓存,所以默认是针对所有参数,即任何一个参数值发生变化,都会缓存一份。
那么,如果,我想指定具体的参数,进行缓存该如何做呢?请看下一个方案。

2、通过对请求指定参数的ActionResult结果进行缓存

[OutputCache(Duration = 300,VaryByParam="id")]

  此种方式,指明了缓存是针对哪个参数来做的,即只有当id参数值发生变化的时候,才做缓存,其他机制同第一种。

2、FlagAttribute

枚举优雅基本用法-在值String和int之间转换

  //需要的方法
  public string GetEnumDescription(Enum enumValue)
{
string str = enumValue.ToString();
System.Reflection.FieldInfo field = enumValue.GetType().GetField(str);
object[] objs = field.GetCustomAttributes(typeof(System.ComponentModel.DescriptionAttribute), false);
if (objs == null || objs.Length == 0) return str;
System.ComponentModel.DescriptionAttribute da = (System.ComponentModel.DescriptionAttribute)objs[0];
return da.Description;
} //定义枚举
enum RoleType
{
[Description("子公司负责人")]
ZMSManager = 1,
[Description("集团人力")]
JTHR = 2,
[Description("考核人")]
AssessPerson = 3,
[Description("订立人")]
MakePerson = 4,
[Description("系统管理员")]
SysManager = 5
} //调用方法
  string returnValue = GetEnumDescription((RoleType)(Enum.Parse(typeof(RoleType),"1"))); //返回值字符串:子公司负责人

  

Flags方式

  如果对一个值可以包含多个,那么可以使用枚举,加上Flags

  1. 使用FlagsAttribute枚举才是对数字值执行按位运算 (AND、 OR 独占或) 的自定义属性。
  2. 在 2 的幂,即 1、 2、 4、 8 等中定义枚举常量。 这意味着不重叠中组合的枚举常量的各个标志。

在权限的管理中,常常会出现一个权限包含的现象。例如,有三种基本权限:职员A、职员B、职员C.在此基础上,有经理权限,它包括A和B两种权限;还有老板权限,包含A/B/C三种权限。

在代码中,我们可以用枚举来管理这些权限。

 class Program
{
[Flags]//表示可以将枚举对象视为位标志
public enum EnumHasFlag
{
A = 1 << 0,
B = 1 << 1,
C = 1 << 2, //定义权限枚举
Manager = A | B, //通过Flags进行域计算得到的另一个枚举
Boss = A | B | C,
}//权限设计如果是常量的话通常用2的幂次方,防止值重复 /*
<<左移操作符,
将第一个操作数向左移动第二个操作数指定的位数,空出的位置补0。
左移相当于乘. 左移一位相当于乘2;左移两位相当于乘4;左移三位相当于乘8。
如:
x<<1= x*2
x<<2= x*4
x<<3= x*8
x<<4= x*16 //至于为什么是 2/4/8?答:因为左移动计算就是将二进制的1向左边移动例如:左边二进制|右边常量 0001=1 左移则为0010=2 继续左移动 0100=4 位移计算方式常量则就是4,这是位移的计算方式。
*/ static void Main(string[] args)
{
var rightA = EnumHasFlag.Boss;
var rightB = EnumHasFlag.Manager; if (rightA.HasFlag(EnumHasFlag.C)) Console.WriteLine("rightA can do this");
if (rightB.HasFlag(EnumHasFlag.C)) Console.WriteLine("rightB can do this");
}
}  

与数据库管理

using System;
using System.ComponentModel;
namespace myApp
{
class Program
{
[Flags]
public enum Permission
{
create = 1,
read = 2,
update = 4,
delete = 8,
} static void Main(string[] args)
{
Permission permission = Permission.create | Permission.read | Permission.update | Permission.delete;
Console.WriteLine("1、枚举创建,并赋值……");
Console.WriteLine(permission.ToString());
Console.WriteLine((int)permission); permission = (Permission)Enum.Parse(typeof(Permission), "5");
Console.WriteLine("2、通过数字字符串转换……");
Console.WriteLine(permission.ToString());
Console.WriteLine((int)permission); permission = (Permission)Enum.Parse(typeof(Permission), "update, delete, read", true);
Console.WriteLine("3、通过枚举名称字符串转换……");
Console.WriteLine(permission.ToString());
Console.WriteLine((int)permission); permission = (Permission)7;
Console.WriteLine("4、直接用数字强制转换……");
Console.WriteLine(permission.ToString());
Console.WriteLine((int)permission); permission = permission & ~Permission.read;
Console.WriteLine("5、去掉一个枚举项……");
Console.WriteLine(permission.ToString());
Console.WriteLine((int)permission); permission = permission|Permission.delete;
Console.WriteLine("6、加上一个枚举项……");
Console.WriteLine(permission.ToString());
Console.WriteLine((int)permission);
//1 3 5 7 都是在权限指定 在数据库内
       /*
判断是否包含指定枚举:
        | 符号,把所有二进制数据进行合并,有一个或两个1都返回1
则: color1|Color.Red; 等于5|1,等于5 color1|Color.Bule; 等于5|4,等于5 color1|Color.Green; 等于5|2,等于7 color1|Color.White; 等于5|8,等于13        */ 
}
}
}

  

 在数据库中判断:

AND (@permission IS NULL OR @permission=0 OR permission &@permission =@permission)

  上面的sql语句同样可以判断多个权限

这里权限我改了 不是枚举 是int数据结构如下

/*
Navicat MySQL Data Transfer Source Server : 47.94.174.85_3306
Source Server Version : 50719
Source Host : 47.94.174.85:3306
Source Database : testDb Target Server Type : MYSQL
Target Server Version : 50719
File Encoding : 65001 Date: 2019-04-14 23:54:20
*/ SET FOREIGN_KEY_CHECKS=0; -- ----------------------------
-- Table structure for t_authorization
-- ----------------------------
DROP TABLE IF EXISTS `t_authorization`;
CREATE TABLE `t_authorization` (
`Id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Id自增',
`Name` varchar(50) NOT NULL,
`Pass` varchar(50) NOT NULL,
`permission` int(11) DEFAULT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8; -- ----------------------------
-- Records of t_authorization
-- ----------------------------
INSERT INTO `t_authorization` VALUES ('1', '张三', '4444', '1');
INSERT INTO `t_authorization` VALUES ('2', '李四', '123456', '2');
INSERT INTO `t_authorization` VALUES ('3', '王五', '123456', '4');

  执行的操作如下

set @permission=1;
UPDATE t_authorization SET Name= '4444' WHERE id= '1' AND (@permission IS NULL OR @permission=0 OR permission &@permission =@permission) -- AND (@permission IS NULL OR @permission=0 OR permission &@permission =@permission) 如何数据是我上面的那样的话 这样Sql执行就相当于 验证该字段 @permission局部变量是否等于数据库permission字段,permission字段为int类型-- 权限肯定不会这样做的,存的应该是权限标识的集合 已测--   

经验证 permission 我一开始写 1   2  4  是错的 不应该是数*(这数不是奇偶数而是2的立方数叠加的),应该是对应的数即权限的集合值 例如 3  5  6  7  9。    网上写法   (@permission IS NULL OR @permission=0 OR permission &@permission =@permission)  中解读

@permission IS NULL    是null 为true执行

@permission=0   是0为true执行

OR permission &@permission =@permission  按位与

比如:

SELECT 4&1            0

SELECT 4&2            0

SELECT 4&4            4

SELECT 5&4            4

SELECT 6&4            4

SELECT 7&4            4

SELECT 8&4            0

SELECT 9&4            4

SELECT 10&4          4

SELECT 8&2            0  //说明值相没有包含值9

SELECT 9&2            0  //说明值相没有包含值9

SELECT 8&2            2

SELECT 9&2            0

注意:左边&右边      即左边是权限集合,右边是权限标识   最后结果也是权限标识

SQL语句如下:

SELECT * FROM TableName WHERE ColumnName & 1=1
/*或者*/
SELECT * FROM TableName WHERE ColumnName | 1=ColumnName

  

或者

set @permission=1;
UPDATE t_authorization SET Name= '4444' WHERE id= '1' AND (@permission IS NOT NULL OR @permission!=0 OR permission &@permission =@permission)
--
@permission IS NOT NULL 不为空
@permission!=0 不为0 permission某个权限集合 @permission 某个权限 最好关联外表即权限的列表
--

  

  

首先:

1、判断权限不是靠  大于比较的     1      2     4     8         这是权限每一种展示              3    5   6  7  9 10  11  12  13  14  15  则是这几个可以拼接的合  代表一种包含的权限      通过位移 计算是哪几种权限的集合

2、靠位移(经检验位移运算符已解决, 比如4这个权限集合是从1开始 那几个数值位移得到的,然后就可以几个数值进行判断是否包含-   位移的是二进制的1 所以和1组合的对于我们二进制数)

数据库动态添加权限数据

INSERT INTO `t_authorization` VALUES ('', '张三', '', '');
INSERT INTO `t_authorization` VALUES ('', '李四', '', '');
INSERT INTO `t_authorization` VALUES ('', '王五', '', '');
例如要动态插入这个三个后面,可能出现的情况1、位移数会越来越大。2、删除一个值,将新的插入进入 可能会导致权限 乱(仅局限与编辑操作)
解决方案:
方案一
1、Id设置自增。
2、设置权限值全部为2。
3、权限计算通过 2>>(主键-1)
即我们插入的数据格式 INSERT INTO `t_authorization` VALUES ('', '张三', '', '');
INSERT INTO `t_authorization` VALUES ('', '李四', '', '');
INSERT INTO `t_authorization` VALUES ('', '王五', '', ''); 注:这样我们的权限控制都是通过计算得出(甚至字段列2都不需要)。

方案二

INSERT INTO `t_authorization` VALUES ('', '张三', '', '');
INSERT INTO `t_authorization` VALUES ('', '李四', '', '');
INSERT INTO `t_authorization` VALUES ('', '王五', '', ''); 这种添加一个权限列 把权限值 写入类内

3、DescriptionAttribute

所谓的enum扩展 其实就是用反射动态获取给定值

4、HelpAttribute

[HelpAttribute("Information on the class MyClass")]
class MyClass
{
}

一、C#中几个简单的内置Attribute

1、Conditional:起条件编译的作用,只有满足条件,才允许编译器对它的代码进行编译。一般在程序调试的时候使用。 
2、DllImport:用来标记非.NET的函数,表明该方法在一个外部的DLL中定义。 
3、Obsolete:这个属性用来标记当前的方法已经被废弃,不再使用了。

C# typeof() 和 GetType()区是什么?
1、typeof(x)中的x,必须是具体的类名、类型名称等,不可以是变量名称。
2、GetType()方法继承自Object,所以C#中任何对象都具有GetType()方法,它的作用和typeof()相同,返回Type类型的当前对象的类型。 比如有这样一个变量i:
Int32 i = new Int32(); i.GetType()返回值是Int32的类型,但是无法使用typeof(i),因为i是一个变量,如果要使用typeof(),则只能:typeof(Int32),返回的同样是Int32的类型。

  

四、Attribute的更多相关文章

  1. Attribute注解(用于判断权限)

    一  Attribute原理: Attribute注解,是附加上方法.属性.类等上面的标签,可以通过方法的GetCustomAttribute获得粘贴的这个Attribute对象通过反射调用到粘贴到属 ...

  2. OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)和varying,uniform,attribute修饰范围

    OpenGL ES着色器语言之变量和数据类型(一)(官方文档第四章)   所有变量和函数在使用前必须声明.变量和函数名是标识符. 没有默认类型,所有变量和函数声明必须包含一个声明类型以及可选的修饰符. ...

  3. angular2系列教程(四)Attribute directives

    今天我们要讲的是ng2的Attribute directives.顾名思义,就是操作dom属性的指令.这算是指令的第二课了,因为上节课的components实质也是指令. 例子

  4. 从Unity中的Attribute到AOP(四)

    本篇我们将逐一讲解Unity中经常使用的Attribute(Unity对应的文档版本为2018.1b). 首先是Serializable,SerializeField以及NonSerialized,H ...

  5. Web API (四) 特性路由(Attribute Route)

    特性路由 是Web API 2 中提出的一种新的类型的路由,正如其名称那样,它是通过特性(Attribute) 来定义路由的,相比之前的基于模式(Convertion Based)的路由,特性路由 能 ...

  6. 我的C#跨平台之旅(四):使用AOP(filter、attribute)进行系统增强

    1.使用OData提速REST API开发 引入NuGet包:Microsoft.AspNet.WebApi.OData 在启动类中添加如下配置(示例为全局配置,也可基于Controller或Acti ...

  7. 四、Attribute(2)授权角色过滤器

    一.授权过滤器 1.新建一个mvc 项目 2.首先创建一个过滤器 MyAuthorizeAttribute 继承AuthorizeAttribute,并重写 AuthorizeCore public ...

  8. jQuery中的属性过滤选择器(四、五):[attribute] 、[attribute=value]、[attribute!=value] 、[attribute^=value] 等

    <!DOCTYPE html> <html> <head> <title>属性过滤选择器</title> <meta http-equ ...

  9. [C#] 剖析 AssemblyInfo.cs - 了解常用的特性 Attribute

    剖析 AssemblyInfo.cs - 了解常用的特性 Attribute [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/5944391.html 序 ...

随机推荐

  1. Yii2基本概念之——配置(Configurations)

    在Yii中创建新对象或者初始化已经存在的对象广泛的使用配置,配置通常包含被创建对象的类名和一组将要赋值给对象的属性的初始值,这里的属性是Yii2的属性.还可以在对象的事件上绑定事件处理器,或者将行为附 ...

  2. 博弈论进阶之Every-SG

    Every-SG 给定一张无向图,上面有一些棋子,两个顶尖聪明的人在做游戏,每人每次必须将可以移动的棋子进行移动,不能移动的人输 博弈分析 题目中的要求实际是"不论前面输与否,只要最后一个棋 ...

  3. ArcGIS API for JavaScript 4.2学习笔记[20] 使用缓冲区结合Query对象进行地震点查询【重温异步操作思想】

    这个例子相当复杂.我先简单说说这个例子是干啥的. 在UI上,提供了一个下拉框.两个滑动杆,以确定三个参数,使用这三个参数进行空间查询.这个例子就颇带空间查询的意思了. 第一个参数是油井类型,第二个参数 ...

  4. 从.Net到Java学习第八篇——SpringBoot实现session共享和国际化

    从.Net到Java学习系列目录 SpringBoot Session共享 修改pom.xml添加依赖 <!--spring session--> <dependency> & ...

  5. Adapter刷新数据的坑

    adapter刷新数据的时候,要能够刷新成功,要保证每次刷新的时候都是改变数据源. 于是,我这样做了,在适配器的构造方法里面写到: private List<ListBean> listI ...

  6. RelativeLayout设置wrap_content无效

    尊重劳动成果,转载请标明出处:http://www.cnblogs.com/tangZH/p/8419053.html 在做项目的过程中,遇到了一个奇怪的现象,我设置RelativeLayout为的宽 ...

  7. Android 反射获取一个方法(方法的参数不一样)

    private Method forget; private Method connect_netID; private Method connect_wifiConfig; private Meth ...

  8. Django 如何获取真实远程客户端IP

    问题简述 我们知道HttpRequest.META字典包含所有HTTP头部信息(可用的头部信息取决于客户端和服务器).一般情况下,HttpRequest.META.get('REMOTE_ADDR') ...

  9. Cygwin 编译 ffmpeg

    1.在官网下载linux下的压缩包 https://ffmpeg.zeranoe.com/builds/source/ffmpeg/ffmpeg-3.2.4.tar.xz 2.进入cygwin,假定将 ...

  10. 关于MongoDB数据库的日志解析

    MongoDB日志记录了数据库实例的健康状态.语句的执行状况.资源的消耗情况,所以日志对于分析数据库服务和性能优化很有帮助. 因此,很有必要花费一些时间来学习解析一下MongoDB的日志文件. 日志信 ...