I would like to create an ETag filter in MVC. The problem is that I can't control the Response.OutputStream, if I was able to do that I would simply calculate the ETag according to the result stream. I did this thing before in WCF but couldn't find any simple idea to do that in MVC.
I want to be able to write something like that
[ETag]
public ActionResult MyAction()
{
var myModel = Factory.CreateModel();
return View(myModel);
}
Any idea?
This is the best I could come up with, I didn't really understand what you meant by you can't control the Response.OutputStream.
This should work, but is doesn't.
Apparently Microsoft overrode System.Web.HttpResponseStream.Read(Byte[] buffer, Int32 offset, Int32 count) so that it returns "Specified method is not supported.", not sure why they would do that, since it inherits for the System.IO.Stream base class...
Which is mix up of the following resources, the Response.OutputStream is a write only stream, so we have to use a Response.Filter class to read the output stream, kind of quirky that you have to use a filter on a filter, but it works =)
http://bytes.com/topic/c-sharp/answers/494721-md5-encryption-question-communication-java
http://www.codeproject.com/KB/files/Calculating_MD5_Checksum.aspx
http://blog.gregbrant.com/post/Adding-Custom-HTTP-Headers-to-an-ASPNET-MVC-Response.aspx
http://www.infoq.com/articles/etags
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
Update
After much fighting I was finally able to get this to work:
More Resources:
http://authors.aspalliance.com/aspxtreme/sys/Web/HttpResponseClassFilter.aspx
http://forums.asp.net/t/1380989.aspx/1
this is the code i created to solve this problem - i inherit from gzip because i want to gzip the stream as well ( you can always use a regular stream) the difference is that i calculate the etag for all my response and not just chunk of it.
There are quite a few promising answers. But none of them is complete solution. Also it was not part of the question and nobody mentioned it. But ETag should be used for Cache validation. Therefore it should be used with Cache-Control header. So clients don't even have to call the server until the cache expires (it can be very short period of time depends on your resource). When the cache expired then client makes a request with ETag and validate it. For more details about caching see this article.
Here is my CacheControl attribute solution with ETags. It can be improved e.g. with Public cache enabled, etc... However I strongly advise you to understand caching and modify it carefully. If you use HTTPS and the endpoints are secured then this setup should be fine.
Usage e.g: with 1 min client side caching:
Thanks a lot it is exactly what I was looking for. Just made a small fix to the ETagFilter that will handle 304 in case that the content wasn't changed