Reputation: 313
I'm writing custom ActionFilterAttribute
and trying to write some data directly into output stream in ASP.NET MVC 3. The data that i'm writing is all that i need to be in response, but after writing there is a extra data after my data - rendered view. I'm trying to close OutputStream
, but it still stay accesible for writing. How can I close this stream for writing or ignore following HTML rendering?
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
var acceptTypes = request.AcceptTypes ?? new string[] {};
var response = filterContext.HttpContext.Response;
if (acceptTypes.Contains("application/json"))
{
response.ContentType = "application/json";
Serializer.Serialize(data, response.ContentType, response.OutputStream);
}
else if (acceptTypes.Contains("text/xml"))
{
response.ContentType = "text/xml";
Serializer.Serialize(data, response.ContentType, response.OutputStream);
}
response.OutputStream.Close();
}
UPD
For example my data is {"Total": 42, "Now": 9000}
And my view is like this
<div>
<span>The data that shouldn't be here</span>
</div>
In response i get
{"Total": 42, "Now": 9000}
<div>
<span>The data that shouldn't be here</span>
</div>
and it's not valid JSON, as you can see. My aim is to send only JSON or XML
Upvotes: 2
Views: 2365
Reputation: 313
After big amount of efforts I found out decision that suits my requirements. It was on the top of the problem. All that I need is to flush response before closing it. But in this case Content-Length
HTTP header is missed and content's length is written right into response body. So we need just to set this header manually before flushing response.
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var request = filterContext.RequestContext.HttpContext.Request;
var acceptTypes = request.AcceptTypes ?? new string[] {};
var response = filterContext.HttpContext.Response;
if (acceptTypes.Contains("application/json"))
{
WriteToResponse(filterContext, data, response, "application/json");
}
else if (acceptTypes.Contains("text/xml"))
{
WriteToResponse(filterContext, data, response, "text/xml");
}
}
private void WriteToResponse(ActionExecutedContext filterContext, object data, HttpResponseBase response, String contentType)
{
response.ClearContent();
response.ContentType = contentType;
var length = Serializer.Serialize(data, response.ContentType, response.OutputStream);
response.AddHeader("Content-Length", length.ToString());
response.Flush();
response.Close();
}
Stream is written into it by Serializer.Serialize
and this method also returns length of content written in output stream.
Upvotes: 1
Reputation: 39685
The ASP.NET pipeline manages the lifecycle of the response object. If you were to abruptly close the stream or end the response, the components downstream will fail when they attempt to write.
If you want to force the system to end the response, you should call HttpApplication.CompleteRequest()
. It will bypass the rest of the events in the ASP.NET pipeline, so it's not without potentially unwanted side-effects, but it is the recommended approach.
More information can be found here.
Upvotes: 1