I'm working on an Asp.Net MVC application to provide an REST / JSON API to data in the Microgroove platform. WCF is overkill for us as this is meant to be a publically accessible, HTTP-based API. In other words, standard stuff.

There is a link to a very small MVC Visual Studio solution at the end of this entry. It simply combines the jQuery $.getJSON example with the standard MVC solution template. The homepage uses jQuery to get some JSON data and supplies a callback parameter:

<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %>

<asp:Content ID="indexTitle" ContentPlaceHolderID="TitleContent" runat="server">
JSONP Example
</asp:Content>

<asp:Content ID="indexContent" ContentPlaceHolderID="MainContent" runat="server">
<h2><%= Html.Encode(ViewData["Message"])%></h2>

<div id="images"></div>

<script type="text/javascript">
$(document).ready(function() {
$.getJSON("/feeds/getjson?jsoncallback=?",
function(data) {
$.each(data.items, function(i, item) {
$("<img/>").attr("src", item.media.m).appendTo("#images");
if (i == 3) return false;
});
});
});
</script>

</asp:Content>

Looking at the "/feeds/getjson" controller action, you'll see a new ActionResult derived class named "JsonpResult":

    /// <summary>
    /// An action result that renders the given object using JSONP to the response stream.
    /// </summary>
    public class JsonpResult : ActionResult
    {
        /// <summary>
        /// The result object to render using JSON.
        /// </summary>
        public object JsonData { get; set; }

        /// <summary>
        /// Gets or sets the callback handler.
        /// </summary>
        /// <value>The callback handler.</value>
        public string CallbackHandler { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="JsonpResult"/> class.
        /// </summary>
        /// <param name="data">The data.</param>
        /// <param name="callbackHandler">The callback handler.</param>
        public JsonpResult(object data, string callbackHandler)
        {
            JsonData = data;
            CallbackHandler = callbackHandler;
        }

        /// <summary>
        /// Enables processing of the result of an action method by a custom type
        /// that inherits from <see cref="T:System.Web.Mvc.ActionResult"/>.
        /// </summary>
        /// <param name="context">The context within which the result is executed.</param>
        public override void ExecuteResult(ControllerContext context)
        {
            context.HttpContext.Response.ContentType = "application/json";

            JavaScriptSerializer ser = new JavaScriptSerializer();
            string json = ser.Serialize(JsonData);
            string jsonp = CallbackHandler + "(" + json + ")";

            new ContentResult { Content = jsonp }.ExecuteResult(context);
        }
    }

I have used the standard .NET JavaScript serializer and then use the ContentResult helper to write the JSON back to the controler context. So, here's the link to the full thing:

JsonpExample.zip (250.93 kb)


Here's how we have been using model binder and UpdateModel of ASP.NET MVC to persist form data consisting of "Check all that apply" type questions.

The Model

This C# contains a Program class which in turn contains a list of Disciplines.

public class Program
{
    public virtual Guid ID { get; set; }
    public virtual IList<Discipline> Disciplines { get; set; }

    public Program()
    {
        Disciplines = new List<Discipline>();

        var discipline = new[] { "Dance", "Literary Arts", "Media" };

        foreach ( var detail in discipline )
        {
            Disciplines.Add( new Discipline { Title = detail } );
        }
    }
}

public class Discipline
{
    public virtual Guid ID { get; set; }
    public virtual string Title { get; set; }
    public virtual bool? IsSelected { get; set; }
}

The properties are marked virtual as we use NHibernate for the ORM. When a Program instance is created, we also pre-populate its collection of Disciplines. Now, it's true that from the relational point of view, this leads to what looks like a 2nd-normal form schema. But, that post is for another day...

The View

<% for (int i = 0; i < Model.Disciplines.Count; i++) {  %> 
<p>
    <%= Model.Disciplines[i].Title %><br />
    <input type="hidden" name="Disciplines.Index" value="<%= i %>" />
    <input type="hidden" name="Disciplines[<%= i %>].Title" value="<%= Model.Disciplines[i].Title %>" />
    <%= Html.RadioButton( "Disciplines[" + i + "].IsSelected", "true", Model.Disciplines[i].IsSelected ?? false ) %> Yes
    <%= Html.RadioButton( "Disciplines[" + i + "].IsSelected", "false", !(Model.Disciplines[i].IsSelected ?? true) ) %> No
</p>
<% } %>

You will see that we check for the null booleans, which is really a way to check whether the end user has selected Yes, No or nothing.

The Controller

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Program(FormCollection collection)
{
    var program = new Program();

    UpdateModel( program, new[]{ "Disciplines" } );

    //call our service to persist the new program
    _programService.SaveOrUpdate( program );

    return View( program );
}

 


Brett Nagy

Software development, engineering and everything in between