Dopo aver provato a farlo funzionare con il middleware, ho capito che MVC action filters sono effettivamente più adatti per questa funzionalità.
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;
}
}
E poi usarlo sulle azioni o controller che si desidera come un attributo:
[HttpGet("data")]
[ETagFilter(200)]
public async Task<IActionResult> GetDataFromApi()
{
}
l'importante distinzione tra Middleware e filtri è che il middleware può essere eseguito prima e dopo MVC middlware e solo può lavorare con HttpContext. Inoltre, una volta che MVC inizia a inviare la risposta al client, è troppo tardi per apportare eventuali modifiche.
I filtri d'altra parte fanno parte del middleware MVC. Hanno accesso al contesto MVC, con il quale in questo caso è più semplice implementare questa funzionalità. More on Filters e la loro pipeline in MVC.
fonte
2016-11-06 22:00:05
secondo [questo] (http://blog.lesierse.com/2015/12/20/cache-busting-using-aspnet5.html) gli etags sono implementati per i file statici se si usa app.UseStaticFiles(). –