using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Web.Mvc;
using System.Xml.Serialization;
using Website.UI;
namespace Website.Controllers
{
///
/// 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 attach the "renderMode" querystring to a request
/// it will replace the current ActionResult with the appropriate
/// serialized data.
///
public class SerializableViewDataAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Get the (lowercase) render mode from the querystring
var method = filterContext.HttpContext.Request
.QueryString["renderMode"] ?? string.Empty;
method = method.ToLowerInvariant();
// If this isn't a serializable request, just return
if(string.IsNullOrEmpty(method)) return;
var viewData = new AsynchronousViewDataResponse(filterContext);
// Decide which method to use
switch (method)
{
case("xml"):
filterContext.Result = getXmlResult(viewData);
break;
case("json"):
filterContext.Result = getJsonResult(viewData);
break;
}
}
private static ActionResult getJsonResult(AsynchronousViewDataResponse viewData)
{
return new JsonResult { Data = viewData };
}
private static ActionResult getXmlResult(AsynchronousViewDataResponse viewData)
{
// There's no "XmlResult" so we have to serialize it ourselves
var sb = new StringBuilder();
using (var writer = new StringWriter(sb))
{
sb.AppendLine("");
sb.AppendFormat("\n", viewData.IsError);
// TODO: Make output XML-friendly
if (!string.IsNullOrEmpty(viewData.Message))
sb.AppendFormat("{0}\n", viewData.Message);
if (viewData.Model != null)
{
sb.Append("");
new XmlSerializer(viewData.Model.GetType()).Serialize(writer, viewData.Model);
sb.AppendLine("");
}
if (viewData.Values != null && viewData.Values.Count > 0)
{
sb.AppendLine("");
foreach (var val in viewData.Values)
sb.AppendFormat("{1}\n", val.Key, val.Value);
sb.AppendLine("");
}
sb.Append("");
}
// ...then pass it into a ContentResult
return new ContentResult { ContentType = "text/xml", Content = sb.ToString() };
}
protected class AsynchronousViewDataResponse : AsynchronousResponse
{
public const string ERROR_MESSAGE_KEY = "ErrorMessage";
#region Constructors
public AsynchronousViewDataResponse()
{
PopulateResponseData(new Dictionary(), null, null);
}
public AsynchronousViewDataResponse(ViewDataDictionary viewData)
{
PopulateResponseData(viewData, viewData.Model, null);
}
public AsynchronousViewDataResponse(ActionExecutedContext context)
{
var controller = ((Controller)context.Controller);
// Only show the exception if it hasn't been handled
var exception = !context.ExceptionHandled ? context.Exception : null;
PopulateResponseData(
controller.ViewData.Concat(controller.TempData).ToDictionary(x => x.Key, x => x.Value),
controller.ViewData.Model,
exception);
}
///
/// The "main" object of this response.
///
[DataMember(EmitDefaultValue = false)]
public object Model { get; set; }
///
/// Get the list of key-value pairs
///
[DataMember(EmitDefaultValue = false)]
public Dictionary Values { get; set; }
#endregion
#region Helpers
private void PopulateResponseData(IDictionary values, object model, Exception exception)
{
var errorMessage = string.Empty;
// If we've got an Exception in the context, try to use the error from that.
if(exception != null)
errorMessage = exception.Message;
// Otherwise, try to glean the message from the View- and TempData.
else if (values.ContainsKey(ERROR_MESSAGE_KEY))
{
errorMessage = values[ERROR_MESSAGE_KEY] as string;
values.Remove(ERROR_MESSAGE_KEY);
}
// Now set the rest of the data
Model = model;
Values = new Dictionary(values);
IsError = !string.IsNullOrEmpty(errorMessage);
// If we have an error, set the error message as our main message
if (IsError)
Message = errorMessage;
// Otherwise, if we've got a success message, show that as our main message
else if (Values.ContainsKey("SuccessMessage"))
Message = values["SuccessMessage"] as string;
}
#endregion
}
}
}