zoukankan      html  css  js  c++  java
  • 四、Attribute

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

     方案二

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

     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的类型。
    

      

  • 相关阅读:
    openssl自签发证书
    安装tomcat8 env
    路由信息相关 route 网卡
    安装jdk env
    sublime使用与配置
    docker仓库登录 配置insecure-registries
    harobor私有docker镜像仓库
    git版本回退的两种方式
    git diff命令的使用
    Kali Linux中的自带字典&crunch自建字典
  • 原文地址:https://www.cnblogs.com/fger/p/10706308.html
Copyright © 2011-2022 走看看