RSS

Tag Archives: MVC

Posting JavaScript types to MVC 6 in .NET core, using Ajax

This is an update to several posts I did years ago, mainly: https://evolpin.wordpress.com/2012/07/22/posting-complex-types-to-mvc. If you are interested in the source code then download it from here.

In this post are included several methods to post data to .NET core 2.2 MVC controller. The example uses the default MVC template that comes with bootstrap, jQuery validate and unobtrusive scripts.

If you rather just visit a possible custom model binding solution to send multiple objects in a POST JSON request, click here.

The test form is quite simple: a scaffolded Person form with several test buttons.

Note the Scripts section beneath the html. It provides the unobtrusive and validate jQuery code. You don’t have to use it and you may very well use whatever validation you prefer. I just preferred to use it as it comes out-of-the-box with the Visual Studio MVC template.

The ViewModel I used for this example is that of a Person:

    public class Person
    {
        [Required]
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

One more code change that I introduced into my Startup.cs, is to use the DefaultContractResolver. This will override the, well…, default behavior in MVC 6 that returns camel cased JSON (e.f. firstName instead of FirstName). I prefer the original casing.

        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .AddJsonOptions(f => f.SerializerSettings.ContractResolver = new DefaultContractResolver());
        }

‘Regular post’ button

The first button is a regular post of the form data. This being a submit button, it’ll auto activate validation.

You can use either this controller code, which receives the IFormCollection (including any form items such as the AntiForgery token).

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(IFormCollection collection)
        {
            try
            {
                if (!ModelState.IsValid)
                    throw new Exception($"not valid");

                foreach (var item in collection)
                {
                    _logger.LogInformation($"{item.Key}={item.Value}");
                }

                return RedirectToAction(nameof(Index));
            }
            catch
            {
                return View();
            }
        }

Alternatively you can use this code which focuses on binding the posted form variables to the Person C# object:

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Person person)
        {
            try
            {
                if (!ModelState.IsValid)
                    throw new Exception($"not valid");

                _logger.LogInformation($"{nameof(person.FirstName)}={person.FirstName}");
                _logger.LogInformation($"{nameof(person.LastName)}={person.LastName}");

                return RedirectToAction(nameof(Index));
            }
            catch
            {
                return View();
            }
        }

Enough of this, where’s the Ajax?

The ‘Create ajax’ button uses the following jQuery to post. Note the ‘beforeSend’ which adds the Anti Forgery token. You must specify this or the request will fail due to the controller code [ValidateAntiForgeryToken] attribute that validates it.

            // Ajax POST using regular content type: 'application/x-www-form-urlencoded'
            $('#btnFormAjax').on('click', function () {

                if (myForm.valid()) {
                    var first = $('#FirstName').val();
                    var last = $('#LastName').val();
                    var data = { FirstName: first, LastName: last };

                    $.ajax({
                        url: '@Url.Action("CreateAjaxForm")',
                        type: 'POST',
                        beforeSend: function (xhr) {
                            xhr.setRequestHeader("RequestVerificationToken",
                                $('input:hidden[name="__RequestVerificationToken"]').val());
                        },
                        data: data
                    }).done(function (result) {
                        alert(result.FullName);
                    });
                }

            });

The controller code is quite the same (I omitted the try-catch for abbreviation purposes). Note, that the returned result in this example is JSON but it doesn’t have to be.

        // Ajax POST using regular content type: 'application/x-www-form-urlencoded' (non-JSON)
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CreateAjaxForm(Person person)
        {
            if (!ModelState.IsValid)
                throw new Exception($"not valid");

            _logger.LogInformation($"{nameof(person.FirstName)}={person.FirstName}");
            _logger.LogInformation($"{nameof(person.LastName)}={person.LastName}");

            return Json(new { FullName = $"{person.FirstName} {person.LastName}" });
        }

This is the Ajax request:

OK, but I want to POST JSON and not application/x-www-form-urlencoded

I prefer to post and receive JSON. It is more consistent and will allow me more flexibility to use more complex objects as will be shown later on.

The default ‘contentType’ for $.ajax is ‘application/x-www-form-urlencoded; charset=UTF-8‘ so we did not have to specify it earlier. To send JSON we now specify a content type of ‘application/json; charset=utf-8‘.

The ‘data’ is now converted to JSON using JSON.stringify() common browser method.

The ‘dataType’ indicates expecting a JSON as the return object.

            $('#btnFormAjaxJson').on('click', function () {

                if (myForm.valid()) {
                    var first = $('#FirstName').val();
                    var last = $('#LastName').val();
                    var data = { FirstName: first, LastName: last };

                    $.ajax({
                        url: '@Url.Action("CreateAjaxFormJson")',
                        type: 'POST',
                        beforeSend: function (xhr) {
                            xhr.setRequestHeader("RequestVerificationToken",
                                $('input:hidden[name="__RequestVerificationToken"]').val());
                        },
                        dataType: 'json',
                        contentType: 'application/json; charset=utf-8',
                        data: JSON.stringify(data)
                    }).done(function (result) {
                        alert(result.FullName)
                    });
                }

            });

The controller code has one small but important change: The [FromBody] attribute of the Person argument. Without this, person will not be populated with the values from the request payload and we will waste a lot of time understanding why.

        // Ajax POST using JSON (content type: 'application/json')
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CreateAjaxFormJson([FromBody] Person person)
        {
            if (!ModelState.IsValid)
                throw new Exception($"not valid");

            _logger.LogInformation($"{nameof(person.FirstName)}={person.FirstName}");
            _logger.LogInformation($"{nameof(person.LastName)}={person.LastName}");

            return Json(new { FullName = $"{person.FirstName} {person.LastName}" });
        }

This time, the request looks like this:

But what if I want to POST more data?

This is where it gets tricky. Unlike the good old WebMethod/PageMethods which allowed you to post and receive multiple JSON and complex data transparently, unfortunately, in MVC controllers this can’t be done and you can have only a single [FromBody] parameter (why??) as you can read here: https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api#using-frombody.

So, if you want to send a more complex type, that includes for example arrays or multiple objects, you need to receive them as a single argument. The ‘Create ajax json complex type’ button demonstrates this. The View Model used here is:

    public class Person
    {
        [Required]
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

    public class People
    {
        public Person[] SeveralPeople { get; set; }
    }

In the sending Javascript, it is very important to note the identically structured ‘people’ object as highlighted below:

             // form ajax with json complex type
            $('#btnFormAjaxJsonComplexType').on('click', function () {

                var joe = { FirstName: 'Joe' };
                var jane = { FirstName: 'Jane' };
                var people = { SeveralPeople: [joe, jane] };

                $.ajax({
                    url: '@Url.Action("CreateAjaxFormJsonComplexType")',
                    type: 'POST',
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader("RequestVerificationToken",
                            $('input:hidden[name="__RequestVerificationToken"]').val());
                    },
                    dataType: 'json',
                    contentType: 'application/json; charset=utf-8',
                    data: JSON.stringify(people)
                }).done(function (result) {
                    alert(result.Count)
                });

            });

The controller code receives a single object:

        // Ajax POST of a more complex type using JSON (content type: 'application/json')
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CreateAjaxFormJsonComplexType([FromBody] People people)
        {
            if (!ModelState.IsValid)
                throw new Exception($"not valid");

            foreach (var person in people.SeveralPeople)
            {
                _logger.LogInformation($"{nameof(person.FirstName)}={person.FirstName}");
            }

            return Json(new { Count = people.SeveralPeople.Count() });
        }

And the request:

A step back

While ‘people’ might make sense to send as one array object, what happens if you want to send multiple objects which are less related? Again, in past WebMethods this was trivial and transparent. Here, you are required to send them as a single object. For some reason, Microsoft decided to take a step back from a well working and decent WebMethods that exists for years.

Consider the Javascript below. It looks very much alike the previous example, but this time the ‘data’ is not related to the People class in our server side. Instead, it simply binds two objects together to be sent over as JSON.

Please note that I named the parameters ‘one’ and ‘two’. This will be important for the server side binding.

             // form ajax with multiple json complex types
            $('#btnFormAjaxJsonMultipleComplexTypes').on('click', function () {

                var joe = { FirstName: 'Joe' };
                var jane = { FirstName: 'Jane' };
                var data = { one: joe, two: jane };

                $.ajax({
                    url: '@Url.Action("CreateAjaxFormJsonMultipleComplexType")',
                    type: 'POST',
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader("RequestVerificationToken",
                            $('input:hidden[name="__RequestVerificationToken"]').val());
                    },
                    dataType: 'json',
                    contentType: 'application/json; charset=utf-8',
                    data: JSON.stringify(data)
                }).done(function (result) {
                    alert(result.Count)
                });

            });

The server side controller that we would like to have has two parameters (‘one and ‘two’ as send from the client Javascript), but explained earlier, the default model binder in MVC today does not support it and it would not work.

        // this would FAIL and not work
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CreateAjaxFormJsonMultipleComplexType([FromBody] Person one, [FromBody] Person two)
        {
            if (!ModelState.IsValid)
                throw new Exception($"not valid");

            var people = new[] { one, two };
            foreach (var person in people)
            {
                _logger.LogInformation($"{nameof(person.FirstName)}={person.FirstName}");
            }

            return Json(new { Count = people.Length });
        }

I was looking for a way this can be done. Fortunately it seems that we can tailor our own model binder, meaning that we can implement a custom class to bind the request body to our parameters. Here are a couple of references that helped me out:

https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/custom-model-binding?view=aspnetcore-2.2

https://www.c-sharpcorner.com/article/custom-model-binding-in-asp-net-core-mvc/

Writing a custom binder seems easy enough (although I reckon there is much to learn). You need to code a ‘binding provider’. This gets called once per parameter.

    public class CustomModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (/* some condition to decide whether we invoke the custom binder or not */)
                return new CustomModelBinder();

            return null;
        }
    }

The CustomModelBinder needs to do some work parsing content and create an object. That object will be passed to your controller method. This method will also be called once per parameter.

    public class CustomModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var obj =/* some code to populate the parameter that will be passed to your controller method */

            bindingContext.Result = ModelBindingResult.Success(obj);

            return Task.CompletedTask;
        }
    }

You need to modify the ConfigureServices in your Startup class to use this binder.

            services.AddMvc(
                config => config.ModelBinderProviders.Insert(0, new CustomModelBinderProvider()))
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .AddJsonOptions(f => f.SerializerSettings.ContractResolver = new DefaultContractResolver());

In my case I wanted to populate not a specific model type (as can be seen in the 2 links above), but something that will populate any parameter type. In other words, I wanted something like the [FromBody] that will work with multiple parameters. So I named it [FromBody2]… I even placed a Required option so if a parameter is missing from the request, it may trigger an exception if set.

    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
    public class FromBody2 : Attribute
    {
        public bool Required { get; set; } = false;
    }

Note: originally I did not use [FromBody2], and the custom binder worked for ALL parameters. But then I thought it might be better to have some sort of attribute to gain better control, as input arguments in various requests might be different than what we expect.

My binder provider class is checking whether the parameter has the [FromBody2] parameter. If found, it will also pass it to the custom binder so it can be used internally.

    public class CustomModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            var metaData = context.Metadata as Microsoft.AspNetCore.Mvc.ModelBinding.Metadata.DefaultModelMetadata;
            var attr = metaData?.Attributes?.Attributes?.FirstOrDefault(a => a.GetType() == typeof(FromBody2));
            if (attr != null)
                return new CustomModelBinder((FromBody2)attr);

            return null;
        }
    }

Now the binder itself. This was a bit tricky to write because I am consuming the request body stream, which can be done just once, whereas the custom binder is called once per parameter. Therefore I read the stream once and store it in the HttpContext.Items bag for other parameters. I reckon that there could be much more elegant solutions, but this will do for now. Explanation follows the example.

    public class CustomModelBinder : IModelBinder
    {
        private FromBody2 _attr;
        public CustomModelBinder(FromBody2 attr)
        {
            this._attr = attr;
        }

        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));

            var httpContext = bindingContext.HttpContext;
            var body = httpContext.Items["body"] as Dictionary<string, object>;

            // read the request stream once and store it for other items
            if (body == null)
            {
                string json;
                using (StreamReader sr = new StreamReader(httpContext.Request.Body))
                {
                    json = sr.ReadToEnd();

                    body = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
                    httpContext.Items["body"] = body;
                }
            }

            // attempt to find the parameter in the body stream
            if (body.TryGetValue(bindingContext.FieldName, out object obj))
            {
                JObject jsonObj = obj as JObject;

                if (jsonObj != null)
                {
                    obj = jsonObj.ToObject(bindingContext.ModelType);
                }
                else
                {
                    obj = Convert.ChangeType(obj, bindingContext.ModelType);
                }

                // set as result
                bindingContext.Result = ModelBindingResult.Success(obj);
            }
            else
            {
                if (this._attr.Required)
                {
                    // throw an informative exception notifying a missing field
                    throw new ArgumentNullException($"Missing field: '{bindingContext.FieldName}'");
                }
            }

            return Task.CompletedTask;
        }
    }

Explanation:

  • Line 6: Stores the [FromBody2] instance of the parameter. This will be used later to check on the Required property if the request is missing the expected parameter data.
  • Line 14: Get the HttpContext.
  • Line 15: Check whether we have already cached the body payload.
  • Lines 18-28: A one time (per http request) read of the body payload. It will be deserialized to a Dictionary<string, object> and stored in the HttpContext for later parameters to use. Consider adding further validation code here, maybe checking on the ContentType etc.
  • Line 31: This is the nice part. The ModelBinder is given the name of the parameter. As a reminder, our desired method signature had a couple of arguments: Person ‘one’ and Person ‘two’. So the FieldName would be ‘one’ and in a second invocation ‘two’. This is very useful because we can extract it from the Dictionary.
  • Lines 33-35: We attempt to cast the object to JObject (JSON complex types). If we are successful, we further convert it to the actual parameter type.
  • Lines 39-42: If the object is a primitive non-JObject, we simply cast it according to the expected type. You may consider further validations here or just let it fail if the casting fails.
  • Line 45: We take the final object and pass it as a ‘successful result’. This would be handed over to our controller method.
  • Lines 49-53: If the request payload did not contain the expected parameter name, we may decide to throw an exception if it is marked as Required.

Finally, the controller code looks almost identical to the [failed] example somewhere above. Only this time, the parameters are decorated with [FromBody2]. As a reminder, we did not have to use [FromBody2] at all. This was only in order to gain more control over the binding process and avoid future situations in which this solution might not be suitable.

        // Ajax POST of multiple complex type using JSON (content type: 'application/json')
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CreateAjaxFormJsonMultipleComplexType([FromBody2] Person one, [FromBody2] Person two)
        {
            if (!ModelState.IsValid)
                throw new Exception($"not valid");

            var people = new[] { one, two };
            foreach (var person in people)
            {
                _logger.LogInformation($"{nameof(person.FirstName)}={person.FirstName}");
            }

            return Json(new { Count = people.Length });
        }

This looks like this:

We can even add more parameters e.g. a Required ‘three’. The current calling Javascript does not pass ‘three’ so an informative exception will be raised, specifying that ‘three’ is missing.

        // Ajax POST of multiple complex type using JSON (content type: 'application/json')
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CreateAjaxFormJsonMultipleComplexType([FromBody2] Person one,
[FromBody2] Person two,
[FromBody2(Required = true)] Person three)
        {
            if (!ModelState.IsValid)
                throw new Exception($"not valid");

            var people = new[] { one, two };
            foreach (var person in people)
            {
                _logger.LogInformation($"{nameof(person.FirstName)}={person.FirstName}");
            }

            return Json(new { Count = people.Length });
        }

Summary: it is really nice to have complete control over everything, but in the end I would expect Microsoft to fix this and provide an out of the box implementation for receiving multiple JSON objects as multiple parameters.

 
2 Comments

Posted by on 09/02/2019 in Software Development

 

Tags: , , ,

Posting complex JavaScript types to MVC, using Ajax

This post demonstrates how to send Complex client types to MVC using JSON. If you require the same information but for ASP.NET WebForms, you can go and read this post instead.

Note: I published an updated post for MVC6 and ASP.NET core here.

Background
Sending data to MVC using jQuery is something that I wrote about in several blog posts. Just as a quick reminder, this post discusses the basics of sending data, including simple-typed arrays. The problem is that I had to send over an array of complex-typed objects. Originally, this was intended to be a post which performs some sort of a work around by sending a JSON string to the server, and uses a JavaScriptSerializer & dynamics to retrieve the objects. But, after Googling some more it turns out by sending and receiving data in a certain way, MVC will perform this process out of the box, by binding the sent data to your custom server side classes. For simple types, sending data to the server is very “forgiving” and easy. But if you require to send complex types which involve JSON strings – you have to be more strict and follow “the rules”.

If you’re just into the solution, click here. If you would like to see some basic examples and the problem explained, read on.

Basic implementation
Here’s a reminder on how to send simple types, slightly complex types and simple typed arrays. First, this is the server side code:

    public class HomeController : Controller
    {
        public ActionResult Index() { return View("Test"); }

        public ActionResult GotSimple(string name, int age)
        {
            return Content(string.Format("name: {0}; age: {1}", name, age));
        }

        public ActionResult GotArrays(string[] names, int[] ages)
        {
            return Content(string.Format("names: {0}; ages: {1}",
                string.Join(",", names),
                string.Join(",", ages)));
        }

        public ActionResult GotComplexType(string name, int age)
        {
            return Content(string.Format("name: {0}; age: {1}", name, age));
        }
    }

And this is the client code (excluding the buttons html):

<script type="text/javascript">// <![CDATA[
        $(function () {
            $('#sendSimple').click(function () {
                 $.get("@Url.Action("GotSimple")",
                     {
                        name: "Joe" ,
                        age: 20
                     },
                     function (result){
                         alert("Server replied: " + result);
                     }
                 );
            });

            $('#sendArray').click(function () {
                 $.get("@Url.Action("GotArrays")",
                     $.param({
                        names: ["Joe", "Jane"],
                        ages: [20,30]
                     }, true),
                     function (result){
                         alert("Server replied: " + result);
                     }
                 );
            });

            $('#sendComplexType').click(function () {
                var Joe = { name: 'Joe', age: 20};
                $.get("@Url.Action("GotComplexType")",
                    Joe,
                    function (result){
                        alert("Server replied: " + result);
                    }
                );
            });
        });
// ]]></script>

There are three examples here:

  • ‘Simple’ demonstrates sending two simple types and the server receives them “as-is”.
  • ‘Array’ demonstrates that you can send simple typed arrays using $.param with the traditional flag set to true. The server receives them as expected.
  • ‘ComplexType’ shows an even cooler example, that you can send an simple object and receive it’s properties on the server side similarly to the ‘Simple’ example.

Note the traffic sent over to the server: ‘Simple’ (1) and ‘Complex’ (3) send the data exactly the same way, so clearly the server handles the sent data in a similar way. ‘Array’ (2) sends the data in duplicate keys which is received and interpreted by MVC as arrays.

Moreover: MVC also supports receiving the arguments directly to a custom class (e.g. Person), which is really cool:


public ActionResult GotComplexType(Person person)
{
   return Content(string.Format("name: {0}; age: {1}", person.name, person.age));
}

public class Person
{
   public string name { get; set; }
   public int age { get; set; }
}

This actually works (You can read about it here, under “JavaScript and AJAX Improvements”.

Complex typed arrays

But… when I wanted to send an array of complex types, this was more of a problem. First, lets review the client code:

            $('#sendComplexTypeArrays').click(function () {
                var Joe = { name: 'Joe', age: 20};
                var Jane = { name: 'Jane', age: 30};
                $.get("@Url.Action("GotComplexTypeArrays")",
                    $.param({
                        people: [Joe,Jane]
                    }, true),
                    function (result){
                        alert("Server replied: " + result);
                    }
                );
            });

And here is how it is sent over by the browser:

Clearly, this is not what I wanted. OK, let’s try to remove the traditional flag from $.param:

Looks more promising. Let’s review the server side code this time:

public ActionResult GotComplexTypeArrays(dynamic data)
{
    return Content("");
}

Unfortunately “data” is just an object, nothing more, and I did not get what I wanted.

Solution
I Googled and found this post which gave me a good direction. Turns out that MVC will know how to parse your sent data from the client on the server side, but there are a few catches I had to overcome before this properly worked:

  1. (Client) You must send a JSON content-type in the form of: ‘application/json’.
  2. (Client) The data must be POSTed and in JSON format (use JSON.stringify).
  3. (Server) The server data type must match that of the client:
    • Property names must match (although it seems like case-sensitivity is not an issue);
    • Client arrays must match a server IEnumerable type (array, list etc.);
    • Client data type must match the server side data type to a certain extent or you’re risking losing data (e.g. can’t send a client string and receive it as an int on the server side.)
  4. (Server) All properties must be, well, Properties (e.g. get;set; implemented). Can’t use global fields. They should also be public.
  5. (Server) Apparently the name of the argument cannot be identical to one of the properties. I’m not sure why, but this seem to confuse the binder and results in ‘null’. So you cannot call your argument ‘people’, and have a ‘people’ property in that class at the same time. At least not in the immediate class of the argument.

So after making a few changes to my code, here is the client side:

$.ajaxSetup({
    dataType: 'json',
    contentType: 'application/json, charset=utf-8'
});

The above code ensures that Ajax calls sent to the server are with a JSON content-type, and that JSON is to be received from the server (you may choose to add more global jQuery Ajax settings here such as error handling, or POST method etc.).

Important: if you don’t need all of your Ajax calls to be in JSON format, you can simply use the dataType and contentType in explicit Ajax calls. Just replace $.post with $.ajax and use POST.

$('#sendComplexTypes').click(function () {
    var Joe = { name: 'Joe', age: 20};
    var Jane = { name: 'Jane', age: 30};

    $.post("@Url.Action("GotComplexTypes")",
        JSON.stringify({ people: [ Joe,Jane ]}),
        function (result){
            alert("Server replied: " + result);
        }
    );
});

The code above converts the data into JSON format, and will require a ‘people’ property on the server side for binding purposes.

Below is the modified server side code. It receives a ‘data’ (not ‘people’ – remember?), performs binding to the different attributes, matching name to name and data type to data type. Properties and not global fields.

public ActionResult GotComplexTypes(MyPeople data)
{
    return Json(string.Format("People: {0}", data.People.Count()), JsonRequestBehavior.AllowGet);
}

public class MyPeople
{
    public IEnumerable<Person> People { get; set; }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Here’s the traffic shown which can help understand whether you’re POSTing JSON strings correctly:

Summary
Apart for being a really cool feature, to be able to bind JSON strings to server side objects, it can save a lot of effort if you thought of doing so yourself. However, this was no picnic. If you don’t follow “the rules” specified above, expect a hard-time and lots of frustration. But don’t despair – it’s worthwhile once it works, and after the first time, its supposed to get much easier.

 
5 Comments

Posted by on 22/07/2012 in Software Development

 

Tags: , , ,

MVC 4 Code Enhancements

Here are 2 minor nice enhancements for MVC 4.

Conditional Attribute Enhancements
This enhancement is something I really like. If you are accustomed to write server-side code embedded with HTML, you probably ran into ugly spaghetti code like this:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        string css = "myDiv";
    }
    <div class='@{ if (css != null) {<text>@css</text>} }'></div>
</body>
</html>

In MVC 4, one enhancement allows you to save quite a lot of spaghetti confusing code, by interpreting the Code Nugget for you, like so:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        string css = "myDiv";
    }
    <div class='@css'></div>
</body>
</html>

Even more, you can really shorten things by inserting lengthy strings and render less HTML:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        string css = "class=myDiv";
    }
    <div @css></div>
</body>
</html>

Note that if you would have used apostrophes, they would have been HTML encoded. So this:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        string css = "class='myDiv'";
    }
    <div @css></div>
</body>
</html>

is rendered like this:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
 <div class=&#39;myDiv&#39;></div>
</body>
</html>

If you would like to avoid encoding, just use Html.Raw( ) as usual:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        var css = @Html.Raw("class='myDiv'");
    }
    <div @css></div>
</body>
</html>

Note that Html.Raw returns an IHtmlString, and this works just as well. It seems like the Code Nugget simply performs a ToString( ) with HTML encoding on the given variable. This can be tested easily. Consider this code:

using System.Web.Mvc;

namespace MVCEnhancements.Controllers
{
    public class MyModel
    {
        public override string ToString()
        {
            return "t'is my code";
        }
    }
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            return View(new MyModel());
        }
    }
}

and the corresponding cshtml (note the @Model in line 9):

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    @{
        var css = @Html.Raw("class='myDiv'");
    }
    <div @css>@Model</div>
</body>
</html>

This renders the following:

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <div class=&#39;myDiv&#39;>t&#39;is my code</div>
</body>
</html>

As you can well see, ToString( ) was called and it was also Html Encoded.

URL Resolution Enhancements
Instead of using Url.Content with a tilde,

<!DOCTYPE html>
<html>
<head>
    <script src='@Url.Content("~/Scripts/jquery-1.6.2.js")'></script>
</head>
<body>
    <div>
    </div>
</body>
</html>

You can just use the tilde like so:

<!DOCTYPE html>
<html>
<head>
    <script src='~/Scripts/jquery-1.6.2.js'></script>
</head>
<body>
    <div>
    </div>
</body>
</html>
 
2 Comments

Posted by on 20/05/2012 in Software Development

 

Tags: , ,

Long Poll Sally – ASP.NET MVC AsyncController

Just like the rest of us, I use polling occasionally. When I learned of WebSockets, I came across my reading about a term I wasn’t acquainted with: Long Polling (or “Comet“). It can be viewed schematically here. To put it simply, while polling can be explained as a series or recurring requests to the server for updates, Long Polling is more or less the same, only technically, the client opens a request to the server, but the server doesn’t return an immediate response and keeps the connection open. When the server has a response, it will use that open connection to notify the client. The client then has to perform another request to reopen a connection for the next update.

At first, when I realized what Long Polling is, I didn’t like the idea much. I mean, if you end up reopening a request to the server like regular polling, why bother? This comes in handy only for less-frequent notifications from the server side, otherwise its just like Polling. Besides, with the new WebSockets in place – who needs it? But then I did some more reading and decided that it might come in handy after all. The main problem I see for using WebSockets is IE9. The major browsers (Chrome, Firefox and the soon to be released IE10) support WebSockets. Cool. But IE9 does not support it. “Fine” you say, have your users upgrade their browsers to IE10. Ahhhh, but MS has decided to limit IE10 to Windows 7 or above. MS is taking several steps to force us to upgrade to their latest releases: No IE10 for Vista, just like WebSockets isn’t planned for IIS7. Funny enough, Google’s Chrome supports XP and Firefox is also compatible with older Windows (in fact, a short visit to Wikipedia reveals that: “Windows XP SP2, XP SP3 and above is now the minimum requirement for Firefox 13.0 and above”…) I find it quite amazing, that MS’ latest browsers cannot be installed on their own operating systems, while their biggest competitors can. It’s as if Microsoft believes that users will upgrade to their latest operating systems just to get their better browser, when they have major competition which is compatible with legacy Windows. Gregg Keizer rightfully points to an anonymous comment on IE’s blog: “IE9 is the new IE6.” Microsoft is working so hard on renewing IE and kicking out IE6, but it performs such a strategic mistake by leaving IE8 and IE9 for a long long time.

Anyway, that’s a major issue as far as I’m concerned. IE6 to IE9 will probably remain with us for quite sometime, as many users still use Windows XP or Vista. All of these users will not enjoy WebSockets support, and we developers will have to continue to develop alternatives to MS’ browser policy of not allowing their own users to upgrade. I guess that this more or less explains why Polling and Long Polling are still relevant: we simply can’t rely on WebSockets alone in the upcoming years.

“Hello World”

Following several blog posts, especially this one by Clay Lenhart, I ended up with the following “Hello World”-like example. Here is the client. It’s fairly simple and self explanatory:

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Simple</title>
</head>
<body>
    <script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js"></script>
    <script type="text/javascript">
        $(function () {
            openConnection();
        });

        function openConnection() {
            $.post("@Url.Action("Simple", "MyAsync")", function (results) {
                if (results.Data) {
                    $('#log').text(results.Data);
                }

                openConnection();
            });
        }
    </script>
    <div id='log'>
    </div>
</body>
</html>

Here is the server side (explanation below):

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public void SimpleAsync()
        {
            AsyncManager.OutstandingOperations.Increment();

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(TimeSpan.FromSeconds(10));
                AsyncManager.Parameters["contents"] = DateTime.Now.TimeOfDay.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });
        }

        public JsonResult SimpleCompleted(string contents)
        {
            return Json(new { Data = contents });
        }
    }
}

The server code works similarly to the Web Services Async pattern: There is a ‘Begin’ (SimpleAsync), and an ‘End’ (SimpleCompleted). Here is what we see here:

  • Line 8: A would-be async controller must derive from AsyncController. This is what gives us the AsyncManager property through which we accomplish async behavior in MVC.
  • Line 10 is where the async begins. Note, that while the client called the “Simple” Action, our method is called SimpleAsync. In Line 22 you will find it’s counterpart callback method which will be called upon completion (“complete” callback).
  • Lines 12 & 18 are completing operations: In line 12 you announce how many “outstanding operations” you have, which is simply a counter you set at the start of the async operation. When the async operation ends you decrement this counter. When the counter reaches zero, the “completed” callback is called and the response returns to the client. This resembles a C++ reference counter for a smart pointer.
  • Lines 14-19 simulate an async task call. This is where you call time consuming logic, or where you register to receive notifications for two-way communication, simulating WebSockets behavior.
  • Line 17 is how you may pass arguments to the “completed” callback (Line 22).

Here’s a screenshot from IE9 running as IE8:

  1. Response from the server.
  2. Interval of the 10 second requests.
  3. Current pending request.
  4. Browser running in IE8 mode – after all, this is what this effort is all about.

There you have it – quite a simple mechanism to perform async MVC operation, which can evolve into a WebSocket-like operation (see below).

Multiple “outstanding operations”

The OutstandingOperations property which returns an OperationCounter class which is a sort of a reference counter for “pending async operations”. This means that if you have multiple async operations scheduled per a single async request, you may set the counter to the number of those operations, and have each operation decrement the counter when it completes. When the counter reaches zero, the “completed” callback will be returned. Here’s an example:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public void MultipleAsync()
        {
            AsyncManager.OutstandingOperations.Increment(3);

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(1000);
                AsyncManager.Parameters["param1"] = DateTime.Now.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(2000);
                AsyncManager.Parameters["param2"] = DateTime.Now.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });

            Task.Factory.StartNew(() =>
            {
                Thread.Sleep(3000);
                AsyncManager.Parameters["param3"] = DateTime.Now.ToString();
                AsyncManager.OutstandingOperations.Decrement();
            });
        }

        public JsonResult MultipleCompleted(string param1, string param2, string param3)
        {
            return Json(new { Data = string.Format("{0} {1} {2}", param1, param2, param3) });
        }
    }
}
  • Line 12 states that there are three async pending operations to be completed before returning a response.
  • Three new threads simulate those async operations. Each completes in a Decrement being called, to signal an async operation completion (lines 18,25,32). Each also provides a different argument with the result of the pending operation, which will be passed on to the “completed” callback.
  • Line 36: the “completed” callback receives the results of the pending operations and returns a response.

WebSocket-like implementation

UPDATE: Before you dig into this code, you might be interested in SignalR. Turns out that this is a broadcasting solution from guys at MS. It supposed to auto-detect and use WebSockets, Long Polling or whichever technology is available on the client. I have not tried this yet, but it looks very promising. You can see Scott Guthrie talk about this here (1:09:38).

Now it comes down to the “main event”: Implementing a WebSocket like implementation. Instead of opening a WebSocket from the browser to the server for two-way communication, the idea is to open a request which the server will maintain asynchronously but not so much for the purpose of supporting a lengthy operation, as much as to maintain the connection for a future response from some business logic component. Here’s an example for accomplishing this. First, the publisher (i.e. class which publishes business logic events to subscribers):

using System;
using System.Timers;

namespace LongPolling.Controllers
{
    public static class MyPublisher
    {
        public class MyEventArgs : EventArgs
        {
            public string Contents { get; set; }
        }

        public static event EventHandler<MyEventArgs> Notify;

        private static Timer timer;
        static MyPublisher()
        {
            timer = new Timer();
            timer.Interval = 10000;
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.AutoReset = false;
            timer.Start();
        }

        static void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            try
            {
                timer.Stop();

                if (Notify != null)
                {
                    Notify(null, new MyEventArgs { Contents = DateTime.Now.ToString() });
                }
            }
            finally
            {
                timer.Start();
            }
        }
    }
}

Not much here to tell. The MyPublisher class simulates receiving notifications from the business logic using a simple timer, that every 10 seconds publishes to subscribers the current DateTime. Next comes the AsyncController:

using System;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public void LogicAsync()
        {
            AsyncManager.OutstandingOperations.Increment();

            MyPublisher.Notify += MyPublisher_Notify;
        }

        private void MyPublisher_Notify(object sender, MyPublisher.MyEventArgs e)
        {
            MyPublisher.Notify -= MyPublisher_Notify;
            AsyncManager.Parameters["contents"] = e.Contents;
            AsyncManager.OutstandingOperations.Decrement();
        }

        public JsonResult LogicCompleted(string contents)
        {
            return Json(new { Data = contents });
        }
    }
}
  • Line 12: Register to receive an event from the business logic class (“MyPublisher”). MyPublisher will raise an event each time it attempts to notify whatever message to registered clients.
  • Line 15 is the event handler which is raised by MyPublisher. Here we set the argument to be passed to the “completed” callback and decrement the Outstanding Operations reference counter.
  • Line 17 is probably the most important here as it’s the easiest part to forget: we have to release the event handler from MyPublisher, or MyPublisher will keep a reference to our AsyncController instance and it will never be Garbage Collected. In other words: a managed code memory leak. This is just like in Winforms: a form registers with a business class to receive events in order to display a progress bar or some other UI feedback. When you are done you call a Close( ) on that form. You mistakenly believe that because you called Close and don’t see the form anymore – it is disposed of and eligible for Garbage Collection: not remotely. The business class maintains a reference to the form instance and it is not removed at all. After a while, you begin to witness your memory growing more and more although you’re certain that you have cleaned up everything, and you end-up “windebugging” with SOS to detect that leak. In the screenshot below you can see how the event’s invocation list gets populated with just several requests from the same client browser. The event handlers are never released, which cause the MyAsyncController instances generated per request to remain in memory. By issuing a ‘-=’ we unregister correctly from the event, and the invocation list is kept clean.

Regardless of the potential memory leak described above, the major difference in this implementation from the previous sample is conceptual, and not necessarily technological: In the previous sample, the async method was used to start an async operation, which actually opened new threads. When the threads complete, each decrements the reference counter thus signaling the end of the lengthy async operation. The entire process was started as a browser initiative and simply freed ASP.NET’s threads for the time of the lengthy operation. However, in the current example, the browser opened a request for no particular operation but in order to wait for a callback from the server. The server on an entirely different logical class (“MyPublisher”) will decide when and what to return to the client. A server may return different operations, such as “display notification” about a new email, or “redirect to another page” and so forth.

Timeout

Moving on to implementing a WebSocket like behavior, one issue that was bothering is the Timout. It’s one thing to use an async server operation which is due in a reasonable time; it’s another thing when you attempt to implement a WebSocket-like behavior that may time-out due to less-frequent updates. For example, if you would like to implement a chat, updates might be frequent, but if you implement a mechanism which is most of the time idle, and just prompts notifications every now and then to the end user, we could be discussing here relatively long interval updates. Consider Gmail. When you are positioned on an email correspondence, if suddenly you receive an email related to that correspondence – a notification appears informing you that there’s a new message and you may click on “show” or “hide” to proceed. This is a good example for when a website may be open for a lengthy time without any operation, but a server may “push” a message when relevant. Therefore I tried to test whether a Timeout occurs on the client or the server, by a simple Thread.Sleep() to lengthy time intervals on the server side. It seems that an AsyncController (MVC 4) defaults to 45 seconds. After that, the client is expected to receive the following timeout exception:

“System.TimeoutException: The operation has timed out.”

I have no idea why, but settings the Timeout property seems to be completely ignored. For example, setting the Timeout to “infinite” (Timeout.Infinite) or to a simple 60000 ms (and extending the server’s Sleep to a much lengthier operation), returned a Timeout exception after 45 seconds. Luckily, I read here that you could set a NoAsyncTimeoutAttribute on the async method to state that there should not be a timeout, and in fact – this actually works (viewing the Timeout property in a debug watch shows -1, which is the value of Timeout.Infinite, but it actually works.)

Now that I have server Timeout set to infinite, I tested different clients’ behavior. On Chrome and Firefox – the browsers did not timeout even when I set the server to respond after 6 hours. This was a good behavior as far what I expected. However, in IE it timed out. This was quite frustrating, because IE is the target of this Long Polling alternative in the first place. If it times out, it means that now I have to detect how long it takes before the client times out, and that I have to implement a mechanism for having the server return a response no longer than that timeout value or I’m risking losing the connection with the client. Testing this several times shows that IE times out at approx 60 minutes (see pics below).

Now comes the harder part, which is what to do when those 60 minutes time-out. Remember: the idea is to return a response to the client browser before reaching the client time-out, and have the client re-open a new connection. I thought I could use a simple Timer for this. The timer has to be set to a predefined interval (e.g. 30/45/60 minutes etc. – depends on how much risk you wish to take here…), and decrement the Outstanding Operations reference counter if it elapses. This way the server returns a response to the client, which the clients reads as “timeout”, meaning that there’s nothing to do but re-open a request.

Here’s the code:

using System;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        private System.Timers.Timer timer;

        [NoAsyncTimeout]
        public void LogicAsync()
        {
            this.timer = new System.Timers.Timer();
            this.timer.Interval = 4000;
            this.timer.AutoReset = false;
            this.timer.Elapsed += delegate
            {
                timer.Stop();
                MyPublisher.Notify -= new MyPublisher_Notify;
                AsyncManager.Parameters["contents"] = "timeout";
                AsyncManager.OutstandingOperations.Decrement();
            };

            this.timer.Start();

            AsyncManager.OutstandingOperations.Increment();

            MyPublisher.Notify += MyPublisher_Notify;
        }

        private void MyPublisher_Notify(object sender, MyPublisher.MyEventArgs e)
        {
            this.timer.Stop();
            MyPublisher.Notify -= MyPublisher_Notify;
            AsyncManager.Parameters["contents"] = e.Contents;
            AsyncManager.OutstandingOperations.Decrement();
        }

        public JsonResult LogicCompleted(string contents)
        {
            return Json(new { Data = contents });
        }
    }
}
  • Line 8 declares a Timer variable. This timer is started in the ‘Begin’ method (LogicAsync) and is set to 4 seconds (just for this example – it’s supposed to be set to a much lengthier interval but less than 60 minutes).
  • Lines 16-22: When this timer’s Elapsed event is raised, this means that the request is timing out and should be renewed, so we unregister from the publisher (we do not want to process the event handler during re-connection), and decrement the Outstanding Operations reference counter in order to immediately return a response to the browser. The browser is supposed to interpret this response as “do nothing” (NOP) and re-open a request.
  • Line 33: If the timer did not elapse but we did get an event from the Publisher, we immediately stop the timer, and execute the returning response as normal. This ensures that the timer won’t elapse till we finish implementing the response logic.

In the example above, assuming that a MyPublisher is set to return a response every 10 seconds, you are expected to see two “NOP” responses per one correct response of the handler being raised:

await/async

This here is just an extra to this post. I was thinking whether I could use the new async lib from C#. I came up with this:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public async Task<JsonResult> MyAction()
        {
            string contents = null;
            await Task.Factory.StartNew(() =>
            {
                Thread.Sleep(TimeSpan.FromMinutes(30));
                contents = DateTime.Now.TimeOfDay.ToString();
            });

            return Json(new { Data = contents });
        }
    }
}

The code above seems to be working well but I’m somewhat uncertain whether it’s the correct implementation or best practice for using await/async in MVC.

UPDATE: In Scott Guthrie’s lecture (1:15:25), you can view async/await support which is similar to the example above.

However, when I tried to rewrite the “MyPublisher pattern” using await/async (excluding the timer part), I ended up with something I wasn’t pleased with:

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace LongPolling.Controllers
{
    public class MyAsyncController : AsyncController
    {
        public async Task<JsonResult> MyAction()
        {
            ManualResetEvent ev = new ManualResetEvent(false);
            string contents = null;
            EventHandler<MyPublisher.MyEventArgs> d = null;
            d = delegate(object sender, MyPublisher.MyEventArgs e)
            {
                MyPublisher.Notify -= d;
                contents = e.Contents;
                ev.Set();
            };

            await Task.Factory.StartNew(() =>
            {
                MyPublisher.Notify += d;
                ev.WaitOne();
            });

            return Json(new { Data = contents });
        }
    }
}

Nope, I was clearly unhappy with this code.

Summary

To be honest – I’m not thrilled at all to have to use Long Polling. I didn’t like polling either, but polling was simple – the browser makes requests at (almost) regular intervals, checks for updates. End of story. But with IE10 limited to Windows 7 and above, it seems like Long Polling is a possible solution to achieve a “less frequent polling” but still with “real-time” updates. Having said that, one needs to remember that other solutions are available such as using Flash or Silverlight for achieving two-way communications, and to be honest, I’m uncertain how Google Docs document sharing was implemented. You might also be interested in pubsubhubbub which is based on Atom/RSS feeds (at least watch their really cool “what is PubSubHubbub” video). There are other utils which provide reverse-Ajax and server-pushing such as WebSync, but I haven’t used them myself.

UPDATE: As specified above, SignalR is a .NET based solution from guys at MS which you should also probably look up.

Although the majority of my blog posts relate to stuff that I am learning and documenting as I go along, in this particular case I feel like Long Polling is a technique that I have not experienced sufficiently in order to recommend it. Although this is also true for WebSockets, WebSockets are designed to provide a two-way communication so I was feeling a lot more comfortable recommending them. I see Long Polling not as a technology on its own, but rather as a technique which is designated to provide a solution to a problem using existing technology, which isn’t specifically targeting that same problem. However, I am planning on implementing this soon in order to learn whether it proves itself as reliable and comfortable.

UPDATE: I attempted to implement a Publisher which will be able to filter out the browser that initiates updates to the rest of them using the above technique. My solution had one open Long Polling Ajax request and another Ajax request posted to the server from the same browser representing a user’s update. This was supposed to be nothing too clever: just exclude the current user from the Publisher’s event notification list. I thought of using the Session’s ID to make that distinction, when I noticed that my async requests got stuck almost immediately. At first I thought that this was related to the number of requests I had open from several browsers over a Windows 7 workstation, but slowly and painfully I discovered that this was because I inserted something into the Session in order to make the Session ID sticky. Googling revealed a reason: seems like AsyncController locks the Session in order to make it thread-safe between open requests from the same session. In order to use the Session from an AsyncController you probably have to declare it as read-only using the SessionState attribute. I have not found an “official” explanation for that yet although I’m sure that there is, and the best I found so far was this, this and this blog post. If anyone finds a more documented or official blog from MS guys about this, please comment.

Last credits

Little Richard gets the credit for this blog post’s title.

 
2 Comments

Posted by on 19/03/2012 in Software Development

 

Tags: , , , , , , , ,

ASP.NET MVC – RadioButtonList and a Code Nugget issue with Generics

I’ve been reading about a RadioButtonList that used to exist in MVC Futures but was removed from the release. There are different solutions in the forums for this, suggesting various implementations. I decided to combine some of the ideas into an extension method, which creates a radio button list with LABEL FORs. It also checks the selected OPTION, and provides a wrapping div with css class that can be easily used. This looks like this:

  • Lines 24-27 & 38-41 contain a wrapping div, in case a css class for a container was specified.
  • Lines 30-35 is where the important stuff resides: iterate over the items of the dictionary (line 18), and create radio buttons with corresponding LABEL FORs.

Although this was sufficient, I decided to take this one step further and create another extension method especially for enum types. This method creates the dictionary out of an enum, and the label’s text out of a local resource file (using LocalResX which was demonstrated some time ago here). This is how it looks:


Now all I had to do was call the new extension method from the View, or so I thought. This was my code (note that Visual Studio failed to color the generic part and the rest of the arguments):

Much to my surprise, I received the following compilation error:

CS1502: The best overloaded method match for ‘System.Web.WebPages.WebPageExecutingBase.Write(System.Web.WebPages.HelperResult)’ has some invalid arguments“.

Say what??

After some experimenting, I replaced the generic <T> with an argument of Type in the extension method, removed the <DayOfWeek> from my View and replaced it with a “typeof(DayOfWeek)” – it solved the problem. But hey, what if I did prefer to use generics? Why did the View fail to compile when I placed the generic on my extension method?

What I had done was to compare the resulting compilation of a successful non-generic implementation (using Reflector), and the failed compilation source code (from the Compilation Error page, simply click on the “Show Complete Compilation Source” to view the source code), and I noticed what had happened here:

What happened was that the View failed to recognize the generic call to the extension method, and assumed that RadioButtonList was a property, or a “HelperResult”, as the compiler error states. Check it out in the screenshot above – Html.RadioButtonList should have been called like a method with parentheses! After that I understood that the fact that Visual Studio did not cope and color the generic call in the View wasn’t a designer coloring bug as I initially thought, but rather what seems to be like a Razor bug.

I still wanted to solve this and use generics instead of passing a “typeof” argument. So what I had to do was recall the Razor Code nuggets vs. Code blocks post from a while back on how to replace the call to Write( ), performed by using a Code nugget (@), with a Code block. I made the changes:

Now I received another compilation error, but it was a whole lot better and simply stated that the result of the RadioButtonList<T> extension method is an MvcHtmlString, whereas Html.Raw expects a string. Well, I’m not sure if MS should have provided an implicit conversion method from string to MvcHtmlString and vice versa, and I wasn’t sure I wanted to do it myself, so I had to choose between calling MvcHtmlString’s ToHtmlString( ) method from the View, or from the extension method and return a string instead. I chose the latter, because I wanted to View’s code to remain cleaner, especially if this method will be reused. So, one more time:

Now the View compiled successfully. Checking the assembly with Reflector showed what I expected:

As you can see, now the code calls the RadioButtonList<T> extension method as expected. The resulting string is sent to Html.Raw and from there to the Write(…) method (which was auto-generated by Razor as a result of using ‘@’).

Although this was worked around, I still expect that Razor will support calling generic methods using a Code nugget and not only via a Code block. It’s certainly possible that I’m missing something here, and sure, the workaround isn’t too bad, but it’s just one of those things which make you feel like it’s a “breach” that wasn’t taken care of, and it also was time consuming. I also wonder why MS dropped the RadioButtonList method that was said to exist back in the previews. I guess that it’s written somewhere on the web…

 
2 Comments

Posted by on 12/06/2011 in Software Development

 

Tags: , , , , , ,

MVC and posting data using Html.BeginForm and Url Routing

We all have pages which represent “fill in” data forms. Quite common is a user’s details form: what’s your first name, what’s your last name, email, date of birth etc. This can be coded in various ways, but I thought that this would be a good way to get to know ASP.NET MVC’s Html.BeginForm( ). While there’s also an Ajax.BeginForm(), I think that the two may differ mainly in the desired behavior after you have completed posting and saving the form data. For example, if you’d like to redirect your user to some other view, or display an entirely new View altogether, you might prefer using Html.BeginForm( ). However, you may want to simply display an informatory “Saved successfully” message, and in that case you’d probably consider using Ajax.BeginForm( ) or simply jQuery’s post.

The thing is that Routing could make this a little tricky (as it was in my case). If a certain Route led to a Controller and resulted in a View with a “fill in” details form, the generated html Form’s Action attribute is going to be that exact route which you originally used. So how on earth are you supposed to save your data, if the same route was used to originally render your details in the first place? Sounds confusing? I also thought so till I figured it out. Lets clarify this issue with a real world example. Suppose your website allows users to view and edit their personal profile. Your route could be like so:

Users would be able to use: http://<server or site name>/profile/myUsername to view and edit their profile. Our server side code residing in the AccountController is the following:

Note that the controller has a LoadProfile action method (which corresponds to the route action shown earlier), and a SaveProfile action method. In order to have the form data posted to SaveProfile, we need to provide some arguments to Html.BeginForm( ):

Basically, this works. The View renders fine, the submit button posts the data to SaveProfile as expected and everything seems great. But, I’m only missing one thing: I don’t have the original username from which the Form originally rendered. In order words, I have no idea at this time to which user the filled in data relates to. This was available from the Route url when the profile was loaded, but it’s unavailable now, when Html.BeginForm( ) uses custom data for posting. I thought that this would be easy to accomplish, because the Html.BeginForm( ) has overloads which accept routing data, but it turned out that when I provided those, other Routes I have in my application got prioritized and this gets ugly, because it means that I’ll have to provide more routes or route constraints in order for this to work. And this was just one form in my app, and it doesn’t make sense that I’ll have to do this for all the forms I’ll develop.

This led me to a different question altogether: Why should I explicitly supply BeginForm( ) with an action or controller in the first place? How come that in MVC’s templates there aren’t such arguments when calling Html.BeginForm( ), and yet when posting data, the correct action is invoked? I noticed that if I provided no arguments to Html.BeginForm( ), the default action was a “profile/{username}” route, just like what I used for loading the user’s profile. I was puzzled over this, because I didn’t understand how MVC was supposed to differentiate between loading a profile and saving a profile, as the Route used for both operations is identical. I looked up MVC’s template and found an example for ChangePassword. Turns out that there are a couple of ChangePassword( ) overloads. The first overload received no arguments (for “loading” the form), but the second overload received a Model with the data (“saving” the form). So how does the route knows which method should be invoked?

The answer lies in an [HttpPost] attribute which is placed over the “saving” action method. The route is quite clever and the action type (either GET or POST) is used to differentiate between actions of the same name. This makes sense, because usually a GET operation is to be used for loading a form, and a POST operation is usually used to posting and saving a form. I went ahead and tried it: I removed the arguments from Html.BeginForm( ), changed LoadProfile and SaveProfile action methods simply to “Profile“, added [HttpPost] to the Profile action method which performs the saving operation, and changed the route accordingly. Here’s how this looks:

If we use two action methods by the same name without [HttpPost] on one of them, the run-time throws a “The current request for action ‘Profile’ on controller type ‘AccountController’ is ambiguous between the following action methods” exception.

Now I could use the RouteData collection for retrieving the user name, as well as other form fields which were sent over as arguments.

 
4 Comments

Posted by on 09/05/2011 in Software Development

 

Tags: , , , , , ,

ASP.NET MVC Partial View and Ajax “real world” example

If you would like this sample code, right click here and “save as” to download. Then rename to a zip file and open.

In my previous post I have discussed and demonstrated how you can easily use jQuery and a ASP.NET MVC’s Partial View to accomplish an UpdatePanel-like solution. In this post I’d like to demonstrate a “real world” usage of this technique.

I wanted a cool looking Login dialog to popup on request when a user hits a simple “Log On” button, without having to refresh the entire page or redirecting the client to a Login page. In other words, there is no Login page, just a Login dialog. Naturally, I wanted this Log On button to be available across all the pages in the site. This could be easily be implemented using a layout (“Master Page”). But it’s more generic and nice to use a PartialView, to represent that button. More over, the basic code for this already exists in the MVC application template. Simply create a new MVC application and see for yourself. So there’s nothing new so far. However, the code for the login dialog is something new which is required and here I had basically 2 options:

  1. I could render the login dialog as a hidden dialog (“display:none”) in the Partial View (or layout). This is possible, will save a round trip to the server when the user requests to login, but is also quite “ugly” as it is inefficient to render a hidden dialog every time.
  2. I could have an UpdatePanel like implementation. Using a placeholder div, I could request another PartialView from the server on demand. The html rendered will be then “injected” into the placeholder div. I figure that this is way more efficient than the first option and can be considered, well, “nice”.

I decided to go with option 2. It felt more cool and correct, and also provided me with a great opportunity to practice this technique. Here’s the basics:

  1. We’ll create (or rather re-use MVC’s template code) a Partial View to represent a Log On/Log Off button. This will be rendered from the layout onto all pages. This view will also contain a place holder div, which will be injected with the log-in dialog.
  2. We’ll create a Partial View for the login dialog. This is basically a simple div which wraps the username/password textboxes. This will not be rendered anywhere at design time.
  3. We’ll use jQuery’s ‘load’ method to perform an Ajax call to the server, and return the Partial View of the log-in dialog. The dialog’s html will be injected into the place holder described in stage 1.
  4. We’ll create server side code to support the logon/logoff scenarios.

“Strategy”: The login button’s partial view is going to have a wrapping div, which will change according to the whether a user is logged in or not. This will be rendered at first according to the authenticity state, but will change at run-time according to the user’s operations. This will be described in 4 stages below.

Stage 1: Login button (Partial View). I reused MVC’s template code to do this. The entire code is wrapped with a div (‘divLoginButton’), whose contents will dynamically change according to Log on/log off operations performed by the user.

  • Line 1 is the wrapping div.
  • Line 2 is the server side code which decides whether a Log On or Log Off button will be rendered from the server.
  • Lines 4-9 represents a Log Off button. The user is logged in, authenticated, and has not requested to logoff (line 2 makes that decision).
  • Line 7 contains an Ajax call to actually perform the log off, and to replace the div’s entire content with a new state. This really resembles a Web Form’s UpdatePanel’s behavior, only cleaner and more efficient.
  • Lines 13-28 represent a situation that the user is not authenticated and a Log On button is displayed.
  • In line 17 we query whether the login dialog has already rendered from the server. This can happen if the user has clicked the Log On button, the dialog has rendered from the server (line 19), but has not logged in (e.g. clicked the Cancel button of the dialog). In this case, there’s no point in reloading the dialog from the server, so we reset the username/password fields (line 22) and reopen the dialog (line 25).
  • Lines 29-30 is the place holder for the login dialog.

Stage 2: Login dialog (Partial View). I created the new LoginDialog.cshtml PartialView file. This looks like this:

  • Lines 1-13 represent the “dialog”. This is just a basic div with username/password textboxes. This will be displayed as a modal dialog using jQuery UI’s Dialog. Because the dialog is set to autoopen, this will be automatically opened when rendered for the first time.
  • Lines 15-43 contains the JavaScript which will display the window as a dialog. If you’d rather have the JavaScript in a different JS file because you believe that rendering a JavaScript ajax response from the server is a bad thing, it’s also possible.
  • Line 23 indicates a POST ajax call. POST is done for security as I’d rather have the username/password (lines 25/26) not sent in the query string. The Ajax call is for the Login action method in the Home Controller.
  • Line 32 is executed when the result of the Login method is “Success”. This is what does the trick of replacing the “Log On” button with a “Log Off”, similar to the signout process discussed in Stage 1 above. It is possible to return the PartialView directly from the Login action (line 23), but I wanted to render a Success boolean in order to have more control, especially in case the Login fails.

Stage 3: Server side code to support the Log On / Log Off situations.

The comments are probably sufficient, but just in case:

  • Lines 15-18 return the Login Dialog partial view.
  • Lines 21-26 supports a Log Off scenario. Line 23 performs the actual Sign Out. Line 24 instructs the LoginButton partial view that although the user is still authenticated at this point, a Log On button should be rendered and not a Log Off button.
  • Lines 30-33 return a Log On or Log Off button, depending on the authenticity state of the user. Basically this is used after a successful login operation, when we would like to render a Log Off button.
  • Lines 36-42 represents a Login process. Line 38 should be replaced with actual Membership user login validation check. If true, line 40 sets the authentication cookie. Line 41 returns if a successful login was performed. As you can see, in this example the login is always a success.

Stage 4: Render the Login button in the layout (“Master Page”), so it’s visible throughout all the pages.

  • Line 11 represents the Login Button partial view (Log On / Log Off button).
  • Lines 5 and 8 are jQuery UI (required for the modal dialog).

Here’s how it looks. At first, the page is loaded and the Login button is rendered as a Log On button.

Now we click the Log On button. jQuery’s load method performs an Ajax request to the server, and the Login Dialog Partial View is rendered back. Because the JavaScript code which creates the dialog has an autoopen set to true, it automatically opens:

Now we type-in our credentials and click Login. A POST Ajax call to the server performs credential validation and returns a JSON with Success, meaning that the Login went ok and the user has logged in. Now another Ajax call takes place to “refresh” the state of the Login Button to that of a Log Off button. This looks like this:

Finally, when we click the Log Off button, another “refresh” takes place as the server’s LogOff button returns an updated Login Button.

That’s about it. As stated above, you could take the JavaScripts to a different JS file if you feel bad about rendering back JavaScript, or if you think that it’s more efficient either because the network load is reduced or because the JS file will be cached by the browser. It’s also possible to render both a Log On and a Log Off buttons at once and toggle their visibility on the client side, settling just for Ajax calls only to perform the credential validation and to set the cookies. In either case, this isn’t the point of this blog post. The point is to show multiple examples of Partial Views used as Web Forms Update Panels, using jQuery.

 
124 Comments

Posted by on 26/04/2011 in Software Development

 

Tags: , , , , ,

ASP.NET MVC – PartialView with Ajax

In this post I will briefly discuss how to use a PartialView either as a Web Form’s “UserControl” or as an “UpdatePanel”. You can click on the links to navigate accordingly, or just read on. UPDATE: If you’d rather have a “real world” example, you can read this post: https://evolpin.wordpress.com/2011/04/26/asp-net-mvc-partial-view-and-ajax-real-world-example/.

I’ve wanted to use a PartialView for quite some time now. A PartialView provides two functionalities which aren’t necessarily overlapping although have much in common. In comparison with Web Forms, a PartialView is a kind of a UserControl, but it also provides a kind of UpdatePanel.

What’s great about a PartialView is that it’s very straight forward – you simply place your HTML and/or JavaScript in a separate View file, probably placed in your Shared views folder so it can be used easily across views. Then you can either use it as a control, by placing Html.Partial(…) calls on your View as desired, or you can render it in run-time as a response to an Ajax call.

UserControl like implementation:

Let’s go quickly over the first usage, that of a “UserControl”: we right-click on the Shared folder to add a new View, give it a name, and select the “Create as a partial view” checkbox:

Our solution explorer looks as follows (Index.cshtml will be using the newly created MyPartialView.cshtml):

MyPartialView contains a simple dummy html place holder which will display a “My View” header; whereas Index.cshtml in this example will now include 2 references to MyPartialView:

1: <table border='1'> 
2:     <tr>
3:         <td>
4:             @Html.Partial("MyPartialView")
5:         </td>
6:         <td>
7:             @Html.Partial("MyPartialView")
8:         </td>
9:     </tr>
10: </table>

That’s about it, and this is how it looks:

One more thing worth mentioning, is that the ViewData dictionary which can be populated in the Controller, is available both to the View and to it’s Partial Views.

Ajax and html injection – “UpdatePanel”:

As I mentioned earlier, Partial Views can also provide a functionality resembling Web Form’s UpdatePanel. Those familiar with UpdatePanel usually either appreciate the (relatively) ease of use, or despise it for being so heavy and inefficient. Almost an Ajax “wannabe”. Personally, I think that UpdatePanel has its place in Ajax side by side with PageMethods/WebMethods. I consider it the better alternative for rendering a “mass” of html onto the client, especially when paging or sorting grids. In MVC, a PartialView could perform this exact functionality, and could prove to be the better solution for rendering plenty of html to the client.

Basically there are 4 steps to achieve this:

  1. Create a PartialView.
  2. Create a place holder html control.
  3. Use jQuery’s load method to fetch the partial view from the server and inject it into the place holder.
  4. Create a server side Action in a Controller that will return the partial view.

Here’s a quick example how this can be done. We’ll use the same partial view created earlier (i.e. MyPartialView.cshtml). So now we have to prepare a place holder div, and use jQuery to load and inject the response:

1: <a href='javascript:getView();'>Get Partial View</a>
2: <script type="text/javascript">
3:     function getView() {
4:         $('#divResult').load("@Url.Action("GetView" , "Home" )");
5:     }
6: </script>
7: <div id='divResult'>
8: </div>
  • Line 1 is a simple anchor which will invoke the JavaScript containing jQuery’s load.
  • Line 4 is the simple one-line code which performs an ajax call to the server’s GetView action in the Home Controller (will be done shortly), and injects the result.
  • Line 7-8 is where the result will be injected to.

And now for the server side – pretty self-explanatory:

1: public ActionResult GetView()
2: {
3:    return PartialView("MyPartialView");
4: }

When we run the sample, prior to the Ajax call this looks like this:

After clicking the link, jQuery’s load method performs the Ajax call as expected, and the partial view’s HTML is injected into the place holder. All this can be viewed in the picture below:

  1. The load method performs a GET operation to the server’s GetView.
  2. Response is returned with html.
  3. jQuery injects the result in the place holder div.
  4. The result is rendered in the browser.

That’s it! No doubt this is real simple to achieve. From here on, the possibilities are quite remarkable. You see, it turns out that when jQuery injects the code, it is also able to inject JavaScript. This means that you can actually render not only html, but JavaScript code as well. Naturally you can argue if this is a good thing or not, but it just gives you a hint on how extensible this can be.

As usual, credits are in order. This great post summarizes different jQuery Ajax approaches with ASP.NET MVC.

BTW: If you ask yourself why you should use jQuery instead of Microsoft Client libraries, I guess you should relate to Microsoft’s statements about “throwing its weight behind jQuery”. You can read about this in Stephen Walther’s blog. Stephen’s conclusion says it all: “Our plan is to focus on jQuery as the primary technology for building client-side Ajax applications moving forward. We want to adapt Microsoft technologies to work great with jQuery and we want to contribute features to jQuery that will make the web better for everyone. We are very excited to be working with the jQuery core team.” Although MVC 3 comes with Microsoft Ajax client scripts, it also includes jQuery and I guess that we’ll see more and more of jQuery in Microsoft’s VS templates.

 
22 Comments

Posted by on 12/04/2011 in Software Development

 

Tags: , , , ,

ASP.NET MVC Routing

Url Routing is a cool feature that MVC depends upon. In this video, Scott Hanselman refers to the url routing as the “unsung hero” of MVC. He also demonstrated a Url Routing Debugger which will be discussed here. While I’m sure that there are quite a few things to url routing, in this post I’ll focus on what is probably a typical use of Url Routing.

Quite simply, in MVC the Url Routing’s job is to get you to the desired controller and invoke the correct method (action). Routing is performed in the Global.asax with a certain default provided by MVC templates. When you open a new ASP.NET MVC 3 project, Global.asax has a RegisterRoutes method which looks like this:

1: public static void RegisterRoutes(RouteCollection routes)
2: {
3:     routes.IgnoreRoute("{resource}.axd/{*pathInfo}" );
4:
5:     routes.MapRoute(
6:         "Default" , // Route name 
7:         "{controller}/{action}/{id}", // URL with parameters 
8:         new  { controller = "Home", action = "Index", id = UrlParameter .Optional } // Parameter defaults 
9:     );
10: }

This represents the basics. The MapRoute method presented by default consists of a “route name” (which can be anything), a url pattern (that’s the important stuff) and defaults. The url specified as the default basically means that any url in the form of http://<server>/controller/action/id will be understood as the controller to redirect to, the method to invoke and a parameter to that action. For example, a url of http://<server>/scores/list/1 will be interpreted as “go to the scoresController class, run the ‘list’ method with an id of 1”. The defaults argument in this case represents a situation where some of the url’s items are missing. So, having a url of http://<server&gt;, http://<server>/home, http://<server>/home/index or http://<server>/home/index/1 will all go to home controller and invoke the index method. The route uses the defaults to make up for missing url parameters. On the other hand, http://<server>/scores or http://<server>/home/edit will result at this stage in a 404 “resource cannot be found”, because there’s no scores controller, and no edit method in home controller (as long as we don’t add them, of course). One final thing regarding the default route: as long as you require only the most basic routing of http://<server>/controller/action and optional id, this route will be sufficient for your requests.

Adding additional routes means that you have custom route requirements which should be handled. These would probably be custom Urls to handle, which should direct the user to the different controllers and actions. In order to ensure that you’ve configured your routes correctly, it’s best to familiarize yourself with the Routing Debugger. In short, what this assembly does, is to render information summarizing the routes configured and how each url you test is being handled by those routes. In order to use the debugger, just download it from the blog above, extract it and reference the RouteDebugger.dll. After that you enter a single line of code in Application_Start (Line 8 below):

1: protected void Application_Start()
2: {
3:     AreaRegistration.RegisterAllAreas();
4:
5:     RegisterGlobalFilters(GlobalFilters.Filters);
6:     RegisterRoutes(RouteTable.Routes);
7:
8:     RouteDebugger.RewriteRoutesForTesting(RouteTable.Routes);
9: }

Any url typed in will now be reflected in the rendered html, with a “true”/”false” indication as to which route handles it. This makes it so much easier to understand routing. The picture below is a part of the information rendered concerning the routing for a default url (‘/’). It’s quite clear that the first row ignores the url, and that the second row of the table is the first route which corresponds to the url (and it is the route that will be invoked in this case). The last route is added automatically and will “catchall” the routes.

Now we can add our custom routes. For example, if we wish the user to be able to enter the following url: http://<server>/scores/list/123, this can be done like so (lines 5-9):

1: public static void  RegisterRoutes(RouteCollection  routes)
2: {
3:     routes.IgnoreRoute("{resource}.axd/{*pathInfo}" );
4:
5:     routes.MapRoute(
6:         "scores" ,
7:         "scores/list/{id}" ,
8:         new { controller = "Scores" , action = "List"  }
9:     );
10:
11:     routes.MapRoute(
12:         "Default" , // Route name 
13:         "{controller}/{action}/{id}" , // URL with parameters 
14:         new { controller = "Home" , action = "Index" , id = UrlParameter .Optional } // Parameter defaults 
15:     );
16: }

It’s important to notice that as our custom route refers to a hard coded controller (“scores”) and action (“list”), we had to supply the controller and action parameters in Line 8, which will instruct the route which controller and action will be invoked.

The route debugger will show:


Because our custom route was placed above the default route, we can see in the debugger that row 2 will be the first to capture our Url. This means that there’s an importance to the order routes are being set. Routes preceding other routes will take precedence even if they all answer to the same Url.

When you’re done with the route debugger, simply comment out the line and recompile in order to proceed with the development.

As for the Url’s arguments (e.g. “id”), the controller’s action can either handle these via method arguments, or by using the RouteData.Values dictionary, but you can’t have both at the same time or you’ll get a AmbiguousMatchException (“The current request for action … on controller type … is ambiguous between the following action methods”):

1: public ActionResult List(int id)
2: {
3:     // code here ... 
4:
5:     return View();
6: }

 

1: public ActionResult List()
2: {
3:     int id = Convert.ToInt32(RouteData.Values["id"]);
4:
5:     // code here ... 
6:
7:     return View();
8: }

 

One more thing I think is worth mentioning is handling “greedy routes” and constraints. As you can easily observe, routes can easily become “greedy”, which means that they can pick up Urls that you basically intended for them to skip, in order for a different route to handle them. For example, the default route is quite greedy, as almost any url you enter will be picked up by it (whether or not you actually have a controller and action to handle them). You may also come across situations that you’d like the user to have several Urls which are very similar to each other, but they should be handled by different controllers or actions. For example, a Url can easily have an argument of a textual type and an integer type. So you might want different controllers or actions to handle them according to their data types. In all these cases you have the option of contraining a route using regular expressions. By constraining a route, routes will become less greedy and can be skipped over. As an example, lets assume that the Urls need to differ so that one of the parameters can be either a string or an integer, but with different controllers handling each one.

1: routes.MapRoute( // http://<server>/scores/3 
2:     "int scores" ,
3:     "scores/{id}" ,
4:     new { controller = "Scores" , action = "IntegerAction"  },
5:     new { id = @"\d+" }
6: );
7:
8: routes.MapRoute( // http://<server>/scores/a2 
9:     "text scores" ,
10:     "scores/{id}" ,
11:     new { controller = "Scores" , action = "TextualAction"  },
12:     new { id = "[A-Za-z].+" }
13: );

In lines 1 & 8 you can see examples of the Urls being handled. Note that we may omit line 12 and have the second route “greedier”, because we know that the first route will handle integers anyhow. Naturally, you can have different controllers assigned to handle each route.

Finally, if you insist on having actions (i.e. methods) of the same name with different overloads to handle the routes, you can place a single route to handle both integers and strings, and differentiate between the overloads using attributes, as shown here. I’m not sure why this is better than having constraints on your routes, but it’s always good to know your alternatives.

 
4 Comments

Posted by on 27/03/2011 in Software Development

 

Tags: , , ,

ASP.NET MVC Ajax using jQuery – Quick Start sample

Ajax is heavily used over the past few years to provide a great UI to the web site. In ASP.NET Web Forms there are several alternatives and my preferred choice is ASP.NET Ajax from Microsoft. In this post I’m excluding Partial Rendering (a.k.a. UpdatePanels), and I’m focusing on implementing a kind of PageMethods  / WebMethods solution in MVC. Partial Rendering is good for some cases (although many would disagree one way or another), but this is a “different discussion”.

Back to WebMethods: What I really like about them, is that the infrastructure lets you enjoy Ajax easily. In short, JavaScript proxy classes are generated for the WebMethods/PageMethods, and they easily used with JavaScript callback functions. JSON objects are handled completely automatically from and to the server.

In ASP.NET MVC things are different. No ScriptManager is there to provide the client proxies and I was expecting lots of work. However, to my surprise, Ajax in MVC was quite easy to perform using jQuery. Credits are in order: you can read a summary of the different methods available for Ajax here. The difference between this post and the referenced post, is that this post is designated to provide a quick start to performing PageMethod-like implementation of Ajax in MVC, and will not cover each and every possibility and case in which a more through reading is required.

Assuming you have an updated jQuery which supports Ajax, basically there are just 2 things to take care of in order to accomplish a successful Ajax implementation:

  1. jQuery client code which performs an Ajax request.
  2. Server-side method which will handle that request.

Starting at the Server-side, here’s a sample code (no [WebMethod] attribute is required):

1: public ActionResult GetGreeting(string name)
2: {
3:     return Content("Hello " + name);
4: }

Note that in Line 3, Content returns plain text response to the client. There are other alternatives such as Json(…), which will return, well, Json.

On the client:

1: <script type="text/javascript" src="../../Scripts/jquery-1.4.4.min.js"></script>
2: <script type="text/javascript">
3: function go() {
4:     $.get("@Url.Action("GetGreeting")" ,
5:         {
6:             name: "Joe"
7:         }, function (data){
8:             alert(data);
9:         }
10:     );
11: }
12: </script>
  • Lines 4-10 represents a simple GET Ajax call from the client, and a callback function upon success.
  • Line 4 specifies the ‘$.get’ for a GET operation (can be substituted for ‘post’ if required).
  • Also in line 4 you can see the server side code which renders an appropriate url for reaching the GetGreeting method. The Action method allows to specify a different controller than the View’s default (as assumed in this sample), and it is also possible to specify Route values.
  • Lines 5-7 represents the data sent to the server. The data is a map of keys and values. The keys have to match the server side argument names.
  • Lines 7-9 represent a callback function in the case of success (failure will be discussed below).

Basically, you can create a new MVC project, copy-paste the code sections to a Controller and a View, set the routing in the global.asax, and it’s supposed to work:

jQuery has different Ajax alternatives. These can be viewed in the documentation. Although this sample accomplishes the minimum required for a successful Ajax operation, one last thing that you might want to consider adding is error handling. There are several methods that error handling can be accomplished (especially if you decide to use $.ajax). One way to handle error handling is as follows:

1: $(document).ready(function (){ 
2:     $("#log" ).ajaxError(function (e, xhr, settings, exception) {
3:         $(this ).text(xhr.statusText);
4:     });
5: });
  • Line 1 isn’t really mandatory if you’re certain that #log has been loaded by the time ajaxError is called. You can also bind the ajaxError to $(document).
  • Line 3 simply injects the status of the error as text within #log (naturally, there are other properties that you can query and display).

Assuming that you want to send arrays to the server, this is a little ‘trick’ in jQuery 1.4 and above, as the default serialization of jQuery has changed. So, assuming that you add an int[] age array to your server side method, your client code should look something like this:

1: function go() {
2:     $.get("@Url.Action("GetGreeting")" ,
3:         $.param({
4:                     name: "Joe" , 
5:                     age: [50,30]
6:         }, true ),
7:         function (data){
8:             alert(data);
9:         }
10:     );
11: }

Line 3 uses jQuery’s param, which is what performs the serialization. The ‘true’ in line 6 specifies that you would like to use the traditional method (which serializes it so that MVC gets it correctly).

You can read more about sending arrays ‘traditionally’ here.

 
8 Comments

Posted by on 15/03/2011 in Software Development

 

Tags: , , , ,