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; }
}
}
}