Po chwili próbowania, aby działało z oprogramowaniem pośredniczącym, zorientowałem się, że MVC action filters są lepiej dostosowane do tej funkcji.
public class ETagFilter : Attribute, IActionFilter
{
private readonly int[] _statusCodes;
public ETagFilter(params int[] statusCodes)
{
_statusCodes = statusCodes;
if (statusCodes.Length == 0) _statusCodes = new[] { 200 };
}
public void OnActionExecuting(ActionExecutingContext context)
{
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.HttpContext.Request.Method == "GET")
{
if (_statusCodes.Contains(context.HttpContext.Response.StatusCode))
{
//I just serialize the result to JSON, could do something less costly
var content = JsonConvert.SerializeObject(context.Result);
var etag = ETagGenerator.GetETag(context.HttpContext.Request.Path.ToString(), Encoding.UTF8.GetBytes(content));
if (context.HttpContext.Request.Headers.Keys.Contains("If-None-Match") && context.HttpContext.Request.Headers["If-None-Match"].ToString() == etag)
{
context.Result = new StatusCodeResult(304);
}
context.HttpContext.Response.Headers.Add("ETag", new[] { etag });
}
}
}
}
// Helper class that generates the etag from a key (route) and content (response)
public static class ETagGenerator
{
public static string GetETag(string key, byte[] contentBytes)
{
var keyBytes = Encoding.UTF8.GetBytes(key);
var combinedBytes = Combine(keyBytes, contentBytes);
return GenerateETag(combinedBytes);
}
private static string GenerateETag(byte[] data)
{
using (var md5 = MD5.Create())
{
var hash = md5.ComputeHash(data);
string hex = BitConverter.ToString(hash);
return hex.Replace("-", "");
}
}
private static byte[] Combine(byte[] a, byte[] b)
{
byte[] c = new byte[a.Length + b.Length];
Buffer.BlockCopy(a, 0, c, 0, a.Length);
Buffer.BlockCopy(b, 0, c, a.Length, b.Length);
return c;
}
}
a następnie użyć go od działań lub kontrolerów chcesz jako atrybut:
[HttpGet("data")]
[ETagFilter(200)]
public async Task<IActionResult> GetDataFromApi()
{
}
Ważne rozróżnienie między Middleware i filtrów jest to, że middleware można uruchomić przed i po MVC middlware i może jedynie pracować z HttpContext. Także gdy MVC zacznie wysyłać odpowiedź z powrotem do klienta, jest już za późno, aby wprowadzić jakiekolwiek zmiany.
Filtry z drugiej strony są częścią oprogramowania pośredniego MVC. Mają dostęp do kontekstu MVC, w którym w tym przypadku łatwiej jest zaimplementować tę funkcjonalność. More on Filters i ich potok w MVC.
zgodnie z [this] (http://blog.lesierse.com/2015/12/20/cache-busting-using-aspnet5.html) etagi są implementowane dla plików statycznych, jeśli użyto app.UseStaticFiles(). –