Mark Keats

Software Engineer and UX/IA Pro

Moving from WCF JSON Services to MVC

September 1st, 2009

Currently I’m working on porting a WebForms/ WCF ASP.NET application over to the ASP.NET MVC framework. The client-side code is written wholly in jQuery and the server-side code is in WCF .SVC files. For the move I wanted to move the code out of the .SVC files and into actions on the relevant controllers, so that it was in a more logical place.

Currently the JavaScript for calling a POST method looks like this (standard jQuery AJAX):

$.ajax({
	url: '/MyWcfService.svc/MyMethod',
	type: "POST",
	dataType: 'json',
	data: JSON.stringify({ Name: 'Test', Enabled: true }),
	contentType: "application/json; charset=utf-8",
	success: function(result) {
		alert('Result' + result);
	}
});

[See http://www.json.org/json2.js for the JSON2 library]

And the server-side code looks like this:

[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json)]
bool MyMethod(SomeDto dto)
{
	// Do some work here.
	return true;
}

[DataContract]
public class SomeDto
{
	[DataMember]
	public string Name{ get; set; }

	[DataMember]
	public bool Enabled { get; set; }
}

If you simply port over to an MVC action that uses strongly-types objects you’ll find that the framework doesn’t de-serialize the JSON object into your object correctly. To make it work in the same way as the WCF solution requires you to create an ActionFilterAttribute that intercepts the request and de-serializes the JSON object manually. Here is my filter (created using an example from StackOverflow):

public class JsonFilter : ActionFilterAttribute
{
	public string Param { get; set; }
	public Type JsonDataType { get; set; }

	public override void OnActionExecuting(ActionExecutingContext filterContext)
	{
		if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
		{
			var jsonSerializer = new DataContractJsonSerializer(JsonDataType);
			var result = jsonSerializer.ReadObject(filterContext.HttpContext.Request.InputStream);
			filterContext.ActionParameters[Param] = result;
		}
		else
			throw new InvalidOperationException("Cannot use the JSON filter on this request as the content type is not marked as 'application/json'.");
	}
}

Now you can decorate your action with this attribute and your JSON will be de-serialized into your strongly-typed object exactly as it was in WCF:

[HttpPost]
[JsonFilter(Param="dto", JsonDataType=typeof(SomeDto))]
public ActionResult MyMethod(SomeDto dto)
{
	// Do some work here.
	return Json(true);
}

Written by Mark Keats

No comments

Posted in Uncategorized

Leave a Reply