Nachdem ich eine Weile versucht habe, es mit Middleware arbeiten zu lassen, habe ich herausgefunden, dass MVC action filters tatsächlich besser für diese Funktionalität geeignet sind.
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;
}
}
und dann verwenden, auf die Aktionen oder Controller Sie als Attribut wollen:
[HttpGet("data")]
[ETagFilter(200)]
public async Task<IActionResult> GetDataFromApi()
{
}
Der wichtige Unterschied zwischen Middleware und Filter ist, dass Ihre Middleware vor und nach dem MVC middlware laufen und kann nur arbeite mit HttpContext. Auch wenn MVC beginnt, die Antwort an den Client zu senden, ist es zu spät, um Änderungen daran vorzunehmen.
Filter auf der anderen Seite sind ein Teil von MVC Middleware. Sie haben Zugriff auf den MVC-Kontext, mit dem es in diesem Fall einfacher ist, diese Funktionalität zu implementieren. More on Filters und ihre Pipeline in MVC.
Laut [this] (http://blog.lesierse.com/2015/12/20/cache-busting-using-aspnet5.html) werden Etags für statische Dateien implementiert, wenn app.UseStaticFiles() verwendet wird. –