.Net Core WebAPI IActionFilterによるリクエストキャッシュ
.Net Core WebAPI IActionFilterによるリクエストキャッシュ
この文書では、Redisキャッシュ方式を使用します.1新規クラスは、メソッドにタグを付ける必要があるため、まずキャッシュクラス を再参照し実現する.2注入redisキャッシュは.Net coreでは、すべてのキャッシュオブジェクトを操作するインタフェース 3拡張取得DI注入対象新規静的クラス .4キャッシュ拡張キャッシュでは、単に1つのメソッドをキャッシュするだけでなく、メソッドの拡張キャッシュを行うべきであり、メソッドの戻り値のキャッシュを異なるパラメータに基づいて行うため、メソッドのパラメータをシーケンス化する必要がある.方法は以下の通りである: 5拡張キャッシュの有効期限は、メソッドごとに結果が返され、異なる更新頻度に応じて異なるキャッシュ時間が設定されます.ヘッダ寸法用に属性を宣言します. 8使用
もし文の中に間違いがあれば、皆さんの指摘を歓迎します.ありがとうございます.転載する必要がある場合は、元の出所を明記してください.
この文書では、Redisキャッシュ方式を使用します.
CustomActionCacheAttribute
を新規作成し、Attribute
を継承する.IActionFilter
インタフェースpublic class CustomActionCacheAttribute: Attribute, IActionFilter
{
//
public void OnActionExecuting(ActionExecutingContext context)
{
}
//
public void OnActionExecuted(ActionExecutedContext context)
{
}
}
IDistributedCache
が提供され、using Microsoftを参照する必要がある.Extensions.Caching.Distributedは、クラスで変数を宣言します. private IDistributedCache _cache;
Filter , ,
IDistributedCache
CustomDIContainer
コードは以下の通りである:///
/// /// public static class CustomDIContainer { private static IHttpContextAccessor _httpContextAccessor; ///
/// HttpContext /// /// ///
public static IApplicationBuilder UseCustomHttpContext(this IApplicationBuilder app) { _httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>(); return app; } /// /// Http /// public static HttpContext Current => _httpContextAccessor.HttpContext; ///
/// DI /// ///
/// public static T GetSerivce<T>() => (T)Current?.RequestServices.GetService(typeof(T)); }
使用到了IHttpContextAccessor
,所以需要在Startup
的ConfigureServices
方法中进行http上下文初始化注入.
public void ConfigureServices(IServiceCollection services)
{
......
// NewtonsoftJson
services.AddControllers().AddNewtonsoftJson();
//
services.AddDistributedRedisCache(r => r.Configuration = Configuration["Redis:ConnectionString"]);
//
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
......
}
///
/// /// /// ///
public string GetParams(HttpContext context) { try { NameValueCollection form = HttpUtility.ParseQueryString(context.Request.QueryString.ToString()); HttpRequest request = context.Request; string data = string.Empty; switch (request.Method) { case "POST": request.Body.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(request.Body, Encoding.UTF8)) { data = reader.ReadToEndAsync().Result; data = data.StringReplaceEmpty("{", "}", "\"", "\'").Replace(":", "=").Replace(",", "&"); } break; case "GET": // : get IDictionary<string, string> parameters = new Dictionary<string, string>(); for (int f = 0; f < form.Count; f++) { string key = form.Keys[f]; parameters.Add(key, form[key]); } // : Key IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters); IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator(); // : StringBuilder query = new StringBuilder(); while (dem.MoveNext()) { string key = dem.Current.Key; if (!string.IsNullOrEmpty(key)) query.Append(key).Append("=").Append(dem.Current.Value).Append("&"); } data = query.ToString().TrimEnd('&'); break; default: data = string.Empty; break; } return data; } catch { return string.Empty; } }
并在方法内部声明存储请求参数及方法的字符串
private string _urlParams;
///
/// [ ] 30 /// public int ValidTimeMinutes { get; set; } = 30;
- 6 完整代码
public class CustomActionCacheAttribute : Attribute, IActionFilter { ///
/// [ ] 30 /// public int ValidTimeMinutes { get; set; } = 30; private string _urlParams; private IDistributedCache _cache; public void OnActionExecuting(ActionExecutingContext context) { // DI IDistributedCache this._cache = CustomDIContainer.GetSerivce<IDistributedCache>(); // key _urlParams = $"{ context.HttpContext.Request.Path}?{ GetParams(context.HttpContext)}"; // byte[] cacheValue = _cache.Get(_urlParams); // if (cacheValue == null || cacheValue.Length == 0) return; // // Deserialize byte[] IActionResult result = cacheValue.Deserialize<string>().Json2Object<ObjectResult>(); // , context.Result , if (result != null) context.Result = result; } public void OnActionExecuted(ActionExecutedContext context) { var result = context.Result.ConvertJson(); var options = new DistributedCacheEntryOptions().SetSlidingExpiration(TimeSpan.FromMinutes(ValidTimeMinutes)); // Serialize String byte[] this._cache.SetAsync(_urlParams, result.Serialize(), options); } ///
/// /// /// ///
public string GetParams(HttpContext context) { try { NameValueCollection form = HttpUtility.ParseQueryString(context.Request.QueryString.ToString()); HttpRequest request = context.Request; string data = string.Empty; switch (request.Method) { case "POST": request.Body.Seek(0, SeekOrigin.Begin); using (var reader = new StreamReader(request.Body, Encoding.UTF8)) { data = reader.ReadToEndAsync().Result; data = data.StringReplaceEmpty("{", "}", "\"", "\'").Replace(":", "=").Replace(",", "&"); } break; case "GET": // : get IDictionary<string, string> parameters = new Dictionary<string, string>(); for (int f = 0; f < form.Count; f++) { string key = form.Keys[f]; parameters.Add(key, form[key]); } // : Key IDictionary<string, string> sortedParams = new SortedDictionary<string, string>(parameters); IEnumerator<KeyValuePair<string, string>> dem = sortedParams.GetEnumerator(); // : StringBuilder query = new StringBuilder(); while (dem.MoveNext()) { string key = dem.Current.Key; if (!string.IsNullOrEmpty(key)) query.Append(key).Append("=").Append(dem.Current.Value).Append("&"); } data = query.ToString().TrimEnd('&'); break; default: data = string.Empty; break; } return data; } catch { return string.Empty; } } }
- 7 最后注意
在.Net Core 3需要配置读取body,在代码中方法执行前和方法执行后中多次使用了HttpContext
的Body参数,所以需要在Startup
中Configure
方法添加可多次读取。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
......
app.Use(next => context =>
{
context.Request.EnableBuffering();
return next(context);
});
......
}
///
///
///
///
[HttpGet("get_organization")]
[CustomActionCache(ValidTimeMinutes = 60 * 24)]
public async Task<ExecuteResult<string>> GetOrganizationAsync()
{
//
......
}
もし文の中に間違いがあれば、皆さんの指摘を歓迎します.ありがとうございます.転載する必要がある場合は、元の出所を明記してください.