Simple way to calculate Response length in MVC4
asp.net, asp.net-mvc
Solution
You could write a custom Response filter:
public class ResponseLengthCalculatingStream: MemoryStream
{
private readonly Stream responseStream;
private long responseSize = 0;
public ResponseLengthCalculatingStream(Stream responseStream)
{
this.responseStream = responseStream;
}
public override void Write(byte[] buffer, int offset, int count)
{
this.responseSize += count;
this.responseStream.Write(buffer, offset, count);
}
public override void Flush()
{
var responseSize = this.responseSize;
// Here you know the size of the response ...
base.Flush();
}
}
and register it in your `Global.asax`:
protected void Application_BeginRequest()
{
Context.Response.Filter = new ResponseLengthCalculatingStream(Context.Response.Filter);
}
And if you wanted to apply this filter only on particular controller actions you could write a custom action filter instead of applying it in the BeginRequest event in Global.asax:
public class ResponseLengthCapturingAttribute: ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var response = filterContext.HttpContext.Response;
response.Filter = new ResponseLengthCalculatingStream(response.Filter);
}
}
and then all that's left is decorate the controller action with the corresponding action filter:
[ResponseLengthCapturing]
public ActionResult Index()
{
...
return View();
}
Problem
I was trying to calculate the length of a `HTTP Response`. Seems the stream doesn't want to play. (no read allowed. and the Content-Length doesn't seem set) I was hoping to simply call some length property on the `HttpContent` response. I have since googled and seen what looks to me like convoluted solutions around filters which I don't understand. Is it possible to access the length (content itself is option extra ) If not I would appreciate a link to an example for 'mvc4/.net 4.5 filter' included that I should work though till I do understand. :-) ``` public override void Init() { base.Init(); EndRequest += new EventHandler(EndRequestHandler); } public void EndRequestHandler(object sender, EventArgs e) { var admService = new AdminServices(); admService.HTTPTrace(Context); } public void HTTPTrace(HttpContext httpContext) { try { var eventTrace = new MasterEventTrace(); eventTrace.RemoteAddress = req.UserHostAddress; eventTrace.RequestLengthBytes = req.ContentLength; // var targetMemoryStream = new MemoryStream(); // res.OutputStream.CopyTo(targetMemoryStream); int len; int.TryParse(res.Headers["Content-Length"], out len ); eventTrace.StatusCode = res.StatusCode; eventTrace.ResponseLengthBytes = len; // <<<<<<< HOW to calculate this ``` EDIT: Based on Darin's response I got this working, Thank You Darin I made a few tweaks to suit the situation, but otherwise as suggested. It shows a little more from Global.asax.cs, and logging the Request and Response info as required. ``` //Global.asax.cs public override void Init() { base.Init(); BeginRequest += new EventHandler(BeginRequestHandler); EndRequest += new EventHandler(EndRequestHandler); } public void EndRequestHandler(object sender, EventArgs e) { var adminService = new AdminServices(); var handler = Context.Response.Filter as ResponseStreamHandler; adminService.HTTPTrace(Context, handler); } public void BeginRequestHandler(object sender, EventArgs e) { BootStrapUnauthentiated(); Context.Response.Filter = new ResponseStreamHandler(Context.Response.Filter); } public void HTTPTrace(HttpContext httpContext, ResponseStreamHandler responseStreamFilter) { try { var _ILuwMaster = BosGlobal.BGA.ILuwMaster(); var req = httpContext.Request; var res = httpContext.Response; var eventTrace = new MasterEventTrace(); eventTrace.EventName = req.RequestType +":"+ req.Url.LocalPath; eventTrace.EventDateTime = BosGlobal.BGA.Calendar.Now; eventTrace.RemoteAddress = req.UserHostAddress; eventTrace.RequestLengthBytes = req.ContentLength; eventTrace.ResponseLengthBytes = responseStreamFilter.ResponseSize; //<<<<<<HERE eventTrace.StatusCode = res.StatusCode; // save trace entry in DB _ILuwMaster.GetRepository<MasterEventTrace>().Add(eventTrace); _ILuwMaster.Commit(); } catch (Exception ex ) {} // DONT KILL Live traffic when logging errors occur } public class ResponseStreamHandler : MemoryStream { private readonly Stream _responseStream; public long ResponseSize { get; private set; } public ResponseStreamHandler(Stream responseStream) { this._responseStream = responseStream; ResponseSize = 0; } public override void Write(byte[] buffer, int offset, int count) { this.ResponseSize += count; this._responseStream.Write(buffer, offset, count); } public override void Flush() { base.Flush(); } } ```