using System;
using System.IO;
using System.Text;
using System.Web.Mvc;
using System.Web.Routing;
namespace ChadSoft.Web.Mvc.Filters
{
///
/// Sample Action Filter showing how to modify the ActionResult in a helpful way.
/// This particular filter will normally not do anything at all,
/// but if you ask it to (by, say, attaching the "renderMode" querystring to a request)
/// it will replace the current ActionResult with the appropriate serialized data.
///
public class SerializableViewDataAttribute : ActionFilterAttribute
{
private enum SerializationMethod
{
None,
Json,
Xml
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Try to figure out what serialization method we're dealing with (if any)
var method = getSerializationMethod(filterContext);
// If this isn't a serializable request, just return
if(method == SerializationMethod.None)
return;
// Decide which method to use
switch (method)
{
case(SerializationMethod.Xml):
filterContext.Result = getXmlResult(filterContext.GetViewData());
break;
case (SerializationMethod.Json):
filterContext.Result = getJsonResult(filterContext.GetViewData());
break;
}
}
private static SerializationMethod getSerializationMethod(RequestContext filterContext)
{
// Get the (lowercase) render mode from the querystring.
// NOTE: This is what you would modify if you wanted to use other
// parts of the environment - such as Route Data, for instance -
// to glean the render mode
var querystring = filterContext.HttpContext.Request.QueryString["renderMode"] ?? string.Empty;
var method = SerializationMethod.None;
try
{
if(!string.IsNullOrEmpty(querystring))
method = (SerializationMethod)Enum.Parse(typeof(SerializationMethod), querystring, true);
}
catch { /* Ignore any exceptions */ }
return method;
}
private static ActionResult getJsonResult(object viewData)
{
// Since there's a JsonResult Action,
// all we have to do is pass in the data
return new JsonResult {
// Overridding the ContentType for easier demo-ing.
// This doesn't need to be set for real apps.
ContentType = "text",
Data = viewData
};
}
private static ActionResult getXmlResult(object viewData)
{
// There's no "XmlResult" so we have to serialize it ourselves
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
new System.Xml.Serialization.XmlSerializer(viewData.GetType())
.Serialize(writer, viewData);
}
// ...then pass it into a ContentResult
return new ContentResult {
ContentType = "text/xml",
Content = sb.ToString()
};
}
}
public static class FilterExtensions
{
///
/// This is just a helper method to get the ViewData from
/// the ControllerContext without having to drill down 2 levels
///
///
/// The context's ViewData
public static object GetViewData(this ControllerContext context)
{
// Cast the controller to the abstract Controller type
var controller = context.Controller as Controller;
// If we don't have a controller, bail out now
if (controller == null)
return null;
// Get the view data from the controller.
var viewData = controller.ViewData;
// If it is strongly-typed (i.e. has a Model)
// return only the model.
// Otherwise, return the whole thing.
return viewData != null && viewData.Model != null ? viewData.Model : viewData;
}
}
}