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; } } }