Skip to content

Instantly share code, notes, and snippets.

@paulczy
Last active April 26, 2018 15:32
Show Gist options
  • Save paulczy/4f13bc5ab7ac34eaa6a7da4d0ba16958 to your computer and use it in GitHub Desktop.
Save paulczy/4f13bc5ab7ac34eaa6a7da4d0ba16958 to your computer and use it in GitHub Desktop.
Add ETags to your ASP.NET Core responses.
using System;
using System.IO;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
// ReSharper disable once CheckNamespace
public class ETagAttribute : ResultFilterAttribute
{
public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
var result = context.Result as OkObjectResult;
if (result == null) return base.OnResultExecutionAsync(context, next);
string token;
using (var ms = new MemoryStream())
{
using (var writer = new BsonWriter(ms))
{
var serializer = new JsonSerializer();
serializer.Serialize(writer, result);
token = GetToken(ms.ToArray());
}
}
var clientToken = context.HttpContext.Request.Headers["If-None-Match"];
if (token != clientToken)
{
context.HttpContext.Response.Headers["ETag"] = token;
}
else
{
context.Result = new StatusCodeResult(304);
}
return base.OnResultExecutionAsync(context, next);
}
private static string GetToken(byte[] bytes)
{
var checksum = MD5.Create().ComputeHash(bytes);
return Convert.ToBase64String(checksum, 0, checksum.Length);
}
}
@definitelynotsoftware
Copy link

super helpful - thanks for making this!

Copy link

ghost commented May 14, 2017

This code totally wrong from point of view of it purpose...
IActionResult is not always OkObjectResult. There are a lot of results including own ones:

JsonResult
ContentResult
ObjectResult
OkObjectResult
NotFoundObjectResult
FileContentResult
FileStreamResult
VirtualFileResult
PhysicalFileResult

Only ObjectResult is related to OkObjectResult... All other will not be cached... For example if you want to serve static html templates with ViewResult or some own static file it will not work...

So maybe to avoid misunderstanding it should be named something like ETagObjectResultAttribute... because as universal etag attribute it is wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment