using System.Security.Claims; namespace Admin.NET.Core { public class IdempotentAttribute : Attribute, IAsyncActionFilter { /// /// 请求间隔时间 /// public int Delay = 7; /// /// 错误提示内容 /// public string Msg = "您的操作太快了,请稍稍慢一点!"; /// /// 自定义缓存Key 缓存规则 Key + 请求路由 + 用户id + 请求参数 /// public string Key = ""; /// /// false 返回上次请求结果 true 直接抛出异常 /// public bool Ops = false; private SysCacheService _sysCacheService { get; set; } public IdempotentAttribute() { _sysCacheService = App.GetService(); } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { var httpContext = context.HttpContext; var path = httpContext.Request.Path.Value.ToString(); var userId = httpContext.User?.FindFirstValue(ClaimConst.UserId); var tenSeconds = TimeSpan.FromSeconds(Delay); var parameters = ""; foreach ( var parameter in context.ActionDescriptor.Parameters) { parameters += parameter.Name; parameters += context.ActionArguments[parameter.Name].ToJson(); } var cacheKey = MD5Encryption.Encrypt(Key + path + userId + parameters); if (_sysCacheService.ExistKey(cacheKey)) { if (Ops) throw Oops.Oh(Msg); try { var cachedResult = _sysCacheService.Get(cacheKey); context.Result = new ObjectResult(cachedResult.value); } catch (Exception) { throw Oops.Oh(Msg); } } else { //先加入一个空的缓存,防止第一次请求结果没回来导致连续请求。 _sysCacheService.Set(cacheKey, "", tenSeconds); var resultContext = await next(); if (resultContext.Result is ObjectResult objectResult) { var valueType = objectResult.Value.GetType(); var requestData = new RequestData { type= valueType.Name, value = objectResult.Value }; _sysCacheService.Set(cacheKey, requestData, tenSeconds); } } } /// /// 请求结果 /// private class RequestData { /// /// 请求结果返回的数据 /// public dynamic value { get; set; } /// /// 结果类型 /// public string type { get; set; } } } }