zoukankan      html  css  js  c++  java
  • webapi filter

    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Net.Http;
    using System.Net.Http.Headers;
    using System.Runtime.Caching;
    using System.Text;
    using System.Web;
    using System.Web.Http.Filters;
    
    
    namespace SH3H.WAP.WorkSheet.Outgoing.WebApi.Filters
    {
        /// <summary>
        /// 定义过滤2s内重复提交的action
        /// </summary>
        [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
        public class FWActionSubmitFilterAttribute : ActionFilterAttribute
        {
            MemoryCacheHelper _cache = new MemoryCacheHelper();
            /// <summary>
            /// 客户端缓存(用户代理)缓存相对过期时间
            /// </summary>
            public int ClientCacheExpiration { set; get; }
            /// <summary>
            /// 服务端缓存过期时间
            /// </summary>
            public int ServerCacheExpiration { set; get; }
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="clientCacheExpiration">客户端过期时间。单位为秒,默认为600秒(10分钟)</param>
            /// <param name="serverCacheExpiration">服务端过期时间。单位为秒,默认为7200秒(120分钟)</param>
            public FWActionSubmitFilterAttribute(int clientCacheExpiration = 10, int serverCacheExpiration = 30)
            {
                this.ClientCacheExpiration = clientCacheExpiration;
                this.ServerCacheExpiration = serverCacheExpiration;
            }
    
            /// <summary>
            /// 判定是否用缓存中的内容,还是执行action是去取内容
            /// 注:一旦给actionContext.Response赋值了,则会使用这个值来输出响应
            /// </summary>
            /// <param name="actionContext"></param>
            public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
            {
    
                // ****************************************   穿透缓存 *********************************************
                // 若无缓存,则直接返回
                string cacheKey = getCacheKey(actionContext);
                if (_cache.Contains(cacheKey) == false)
                    return;
                if (_cache.Contains(cacheKey + ":etag") == false)
                    return;
    
                // ****************************************   使用缓存  *********************************************
                // 获取缓存中的etag
                var etag = _cache.Get<string>(cacheKey + ":etag");
                // 若etag没有被改变,则返回304,
                if (actionContext.Request.Headers.IfNoneMatch.Any(x => x.Tag == etag))  //IfNoneMatch为空时,返回的是一个集合对象
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.NotModified); // 响应对象还没有生成,需要先生成 // 304 not modified
                    actionContext.Response.Headers.CacheControl = GetDefaultCacheControl();
                    actionContext.Response.Headers.ETag = new EntityTagHeaderValue(etag);
                    return;
                }
                else //从缓存中返回响应
                {
                    actionContext.Response = actionContext.Request.CreateResponse(); // 响应对象还没有生成,需要先生成
                    // 设置协商缓存:etag
                    actionContext.Response.Headers.ETag = new EntityTagHeaderValue(etag); //用缓存中的值(为最新的)更新它
                    // 设置user agent的本地缓存
                    actionContext.Response.Headers.CacheControl = GetDefaultCacheControl();
    
                    // 从缓存中取中响应内容
                    var content = _cache.Get<byte[]>(cacheKey);
                    actionContext.Response.Content = new ByteArrayContent(content);
                    return;
                }
            }
    
    
    
    
    
    
            /// <summary>
            ///  将输出保存在缓存中。
            /// </summary>
            /// <param name="actionExecutedContext"></param>
            /// <param name="cancellationToken"></param>
            /// <returns></returns>
            public override async System.Threading.Tasks.Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, System.Threading.CancellationToken cancellationToken)
            {
                // 响应对象已经生成,可以直接调用   actionExecutedContext.Response
    
                // 设置协商缓存:etag
                EntityTagHeaderValue etag = new EntityTagHeaderValue(""" + Guid.NewGuid().ToString() + """);  // 根据http协议, ETag的值必须用引号包含起来
                actionExecutedContext.Response.Headers.ETag = etag;
                // 设置user agent的本地缓存
                actionExecutedContext.Response.Headers.CacheControl = GetDefaultCacheControl();
    
                // actionExecutedContext.Response.Headers.Remove("Content-Length"); // 改变了值,它会发生变化。删除它的话,后续的程序会自动地再计算
    
                // 保存到缓存
                string cacheKey = getCacheKey(actionExecutedContext.ActionContext);
                var contentBytes = await actionExecutedContext.Response.Content.ReadAsByteArrayAsync();
    
                _cache.Add(cacheKey + ":etag", etag.Tag, DateTimeOffset.Now.AddSeconds(this.ServerCacheExpiration));
                _cache.Add(cacheKey, contentBytes, DateTimeOffset.Now.AddSeconds(this.ServerCacheExpiration));
    
            }
    
    
    
    
    
            /// <summary>
            /// 默认的用户代理本地缓存配置,10分钟的相对过期时间
            /// 对应响应header中的 Cache-Control
            /// 这里设置里面的子项max-age。如:Cache-Control: max-age=3600
            /// </summary>
            /// <returns></returns>
            CacheControlHeaderValue GetDefaultCacheControl()
            {
                CacheControlHeaderValue control = new CacheControlHeaderValue();
                control.MaxAge = TimeSpan.FromSeconds(this.ClientCacheExpiration);  // 它对应响应头中的 cacheControl :max-age=10项
    
                return control;
            }
    
    
    
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="actionContext"></param>
            /// <returns></returns>
            string getCacheKey(System.Web.Http.Controllers.HttpActionContext actionContext)
            {
                string cacheKey = null;
             //获取POST中data
                var context = (HttpContextBase)actionContext.Request.Properties["MS_HttpContext"];
                context.Request.InputStream.Seek(0, SeekOrigin.Begin);
                using (var sr = new StreamReader(context.Request.InputStream, Encoding.UTF8, true, 1024, true))
                {
                    string body = sr.ReadToEnd();
                    // Logging here...
    
                }
    
          
                cacheKey = actionContext.Request.RequestUri.PathAndQuery; // 路径和查询部分,如: /api/values/1?ee=33&oo=5
    
                // 对路径中的参数进行重排,升序排列
    
                string controllerName = actionContext.ControllerContext.ControllerDescriptor.ControllerName;
                string actionName = actionContext.ActionDescriptor.ActionName;
    
                if (actionContext.ActionArguments.ContainsKey("id") == false)
                {
                    cacheKey = controllerName + "/" + actionName;
                }
                else
                {
                    string id = actionContext.ActionArguments["id"].ToString();
                    cacheKey = controllerName + "/" + actionName + "/" + id;
                }
    
                return cacheKey;
            }
    
        }
    
    
    
        /// <summary>
        /// 缓存辅助类
        /// </summary>
        public class MemoryCacheHelper
        {
            private static readonly MemoryCache _cache = MemoryCache.Default;
    
            /// <summary>
            /// 
            /// </summary>
            /// <param name="key"></param>
            public void RemoveStartsWith(string key)
            {
                lock (_cache)
                {
                    _cache.Remove(key);
                }
            }
            /// <summary>
            /// 
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="key"></param>
            /// <returns></returns>
            public T Get<T>(string key) where T : class
            {
                var o = _cache.Get(key) as T;
                return o;
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            [Obsolete("Use Get<T> instead")]
            public object Get(string key)
            {
                return _cache.Get(key);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="key"></param>
            public void Remove(string key)
            {
                lock (_cache)
                {
                    _cache.Remove(key);
                }
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="key"></param>
            /// <returns></returns>
            public bool Contains(string key)
            {
                return _cache.Contains(key);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="key"></param>
            /// <param name="o"></param>
            /// <param name="expiration"></param>
            /// <param name="dependsOnKey"></param>
            public void Add(string key, object o, DateTimeOffset expiration, string dependsOnKey = null)
            {
                var cachePolicy = new CacheItemPolicy
                {
                    AbsoluteExpiration = expiration
                };
    
                if (!string.IsNullOrWhiteSpace(dependsOnKey))
                {
                    cachePolicy.ChangeMonitors.Add(
                        _cache.CreateCacheEntryChangeMonitor(new[] { dependsOnKey })
                    );
                }
                lock (_cache)
                {
                    _cache.Add(key, o, cachePolicy);
                }
            }
            /// <summary>
            /// 
            /// </summary>
            public IEnumerable<string> AllKeys
            {
                get
                {
                    return _cache.Select(x => x.Key);
                }
            }
        }
    }
  • 相关阅读:
    What's the most secure desktop operating system?
    合肥一中在校学生丁雯琪(中美班)被麻省理工学院(MIT)录取
    Classic Computer Science 1980s-1990s
    HOWTO do Linux kernel development
    选择器zuoye
    HTML+css 小组件
    弹性盒子
    CSS3 学习笔记(动画 多媒体查询)
    CSS3 学习笔记(边框 背景 字体 图片 旋转等)
    学习笔记css3
  • 原文地址:https://www.cnblogs.com/myloveblogs/p/13958236.html
Copyright © 2011-2022 走看看