Thursday, 29 December 2011

Creating custom ActionResult

It is possible to inherit the ActionResult class and create a custom ActionResult.
The following class creates a new kind of ActionResult for spewing out the serialized string of an inputted data contract instance.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Runtime.Serialization;

namespace TestActionMethodSelectorAttribute.ActionResult
{

public class DataContractSerializedResult : System.Web.Mvc.ActionResult
{

private object data;

public DataContractSerializedResult(object data)
{
this.data = data;
}

public override void ExecuteResult(ControllerContext context)
{
var response = context.HttpContext.Response;
response.ContentType = "text/xml";
DataContractSerializer serializer = new DataContractSerializer(data.GetType());
serializer.WriteObject(response.OutputStream, data);
}
}

}


You will need to add a reference to the System.Runtime.Serialization assembly and namespace. We use DataContractSerializer to serialize the object to a string value. The stream in use is the context.HttpContext.Response.OutputStream, where context is the ControllerContext (current).

It is required to set the ContentType to "text/xml" to output xml.

Usage, adding a test method to homecontroller (ignore Hungarian notation, this is for demonstration purposes..) :


public DataContractSerializedResult About2()
{
return new DataContractSerializedResult(
new AgeNameDataContract
{
Age = 93,
Name = "Gamla Olga"
});
}


Then we get the xml outputted of the data contract passed in:



The morale of the story, to create a new kind of ActionResult:

- inherit from ActionResult
- implement abstract method ExecuteResult

Timing your MVC Actions

Add the following attribute to your MVC actions to view the timing of your mvc actions using System.Diagnostics.Stopwatch class.

This is another filter attribute example.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Diagnostics;

namespace TestActionMethodSelectorAttribute.Attributes
{
public class StopwatchAttribute : ActionFilterAttribute
{
private Stopwatch _stopWatch;

public StopwatchAttribute()
{
_stopWatch = new Stopwatch();
}

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_stopWatch.Start();
}

public override void OnActionExecuted(ActionExecutedContext filterContext)
{
_stopWatch.Stop();
var response = filterContext.HttpContext.Response;
response.AddHeader("X-elapsed-milliseconds", _stopWatch.ElapsedMilliseconds.ToString());
}
}
}


Usage (homecontroller):


[Stopwatch]
public ActionResult About()
{
return View();
}


It is nice to output the elapsed time in millisecond in the http headers, since we then easily can monitor the values outside Visual Studio, in our browser:

Using ActionMethodSelectorAttribute in MVC

If you want an MVC controller action to be only available for Ajax methods, use theAjaxMethodSelectorAttribute. Inherit this abstract class to create the attribute AjaxOnlyAttribute below and tag this attribute with your method:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace TestActionMethodSelectorAttribute.Attributes
{
public class AjaxOnlyAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return controllerContext.HttpContext.Request.IsAjaxRequest();
}
}
}


Usage (testing the attribute out in HomeController):



[AjaxOnly]
public ActionResult About()
{
return View();
}


If the current request is not an AjaxRequest, a Http 404 is returned. The attribute [HttpPost] and [HttpGet]is inherited from the ActionMethodSelectorAttribute. They also implement the abstract method IsValidForRequest.