Tuesday, 4 November 2014

Retrieve JSON data from MVC Controllers in ASP.NET MVC

Using unobtrusive AJAX in your MVC web applications can boost system’s performance. We have seen in previous post how to use unobtrusive AJAX to retrieve only partial views instead of full page requests, in ASP.NET MVC Framework. While being a good approach to use Ajax in order to retrieve only partial views, you may have noticed that your controllers send back your data requested along with the HTML fragments. Remember? (screenshot from previous post)

ajaxunobtrusive4
In order to overcome this, we can request only the specific object data we want and let the client’s browser render the respective HTML fragments. The requested data will have to be in JavaScript Object Notation (JSON) format, which is a language-independent way of expressing data. We won’t create a new project but instead, we will continue to add code in the previous post. If you haven’t read it yet, please take a look at it or just make sure you download the project we had created. Open the solution in Visual Studio and change the ProductController.cs file to the following.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
 
using MVCUnobtrusiveAjax.Models;
 
namespace MVCUnobtrusiveAjax.Controllers
{
    public class ProductController : Controller
    {
        private Product[] products = {
                                         new Product {
                                             ProductId = 1, Name = "Audi A3",
                                             Description = "New Audi A3", Category = Category.Car,
                                             Price = 25000
                                         },
                                         new Product {
                                             ProductId = 2, Name = "VW Golf",
                                             Description = "New VW Golf", Category = Category.Car,
                                             Price = 22000
                                         },
                                         new Product {
                                             ProductId = 3, Name = "Boing 747",
                                             Description = "The new Boing airplane", Category = Category.Airplane,
                                             Price = 2000000
                                         },
                                         new Product {
                                             ProductId = 4, Name = "Boing 747",
                                             Description = "The new Boing airplane", Category = Category.Airplane,
                                             Price = 2000000
                                         },
                                         new Product {
                                             ProductId = 5, Name = "Yamaha 250",
                                             Description = "Yamaha's new motorcycle", Category = Category.Motorcycle,
                                             Price = 5000
                                         },
                                         new Product {
                                             ProductId = 6, Name = "honda 750",
                                             Description = "Honda's new motorcycle", Category = Category.Motorcycle,
                                             Price = 7000
                                         }
 
                                     };
 
        public ActionResult Index()
        {
            return View();
        }
 
        private IEnumerable<Product> GetData(string selectedCategory)
        {
            IEnumerable<Product> data = products;
            if (selectedCategory != "All")
            {
                Category selected = (Category)Enum.Parse(typeof(Category), selectedCategory);
                data = products.Where(p => p.Category == selected);
            }
            return data;
        }
 
        public JsonResult GetProductDataJson(string selectedCategory = "All")
        {
            IEnumerable<Product> data = GetData(selectedCategory);
            return Json(data, JsonRequestBehavior.AllowGet);
        }
        public PartialViewResult GetProductData(string selectedCategory = "All")
        {
            return PartialView(GetData(selectedCategory ));
        }
 
        public ActionResult GetProducts(string selectedCategory = "All")
        {
            return View((object)selectedCategory);
        }
 
    }
}
We have created a GetData private method to get Product objects based on a selected category, passed as parameter to that function. The most important action method we added is the GetProductDataJsonmethod, which returns a type of JsonResult object, something that tells the view engine to return JSON data to the client. Pay attention to this line of code:
1
return Json(data, JsonRequestBehavior.AllowGet);
You need to tell the MVC Framework to respond to GET requests, cause by default JSON data will only be sent in response to POST requests. The GetProductData action method renders partial view results, in the way we have seen in previous post.
Last thing we need to do, is to change the way the onSuccess Ajax call event works. Change theGetProducts.cshtml file as follows.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
@using MVCUnobtrusiveAjax.Models
@model string
@{
    ViewBag.Title = "Get Products";
    AjaxOptions ajaxOptions = new AjaxOptions
    {
        UpdateTargetId = "productsTable"
    };
}
 
<script type="text/javascript">
    function processData(data) {
        var target = $("#productsTable");
        target.empty();
        for (var i = 0; i < data.length; i++) {
            var product = data[i];
            target.append("<tr><td>" + product.ProductId + "</td><td>"
            + product.Name + "</td><td>" + product.Description + "</td><td>"
            + product.Category + "</td><td>" + product.Price + "</td></tr>");
        }
    }
</script>
 
<h2>Get Products</h2>
 
<div id="loadingProducts" style="background-color: cadetblue; display: none">
    <p>Loading Products...</p>
</div>
 
<table style="background-color: lightcoral">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Description</th>
            <th>Category</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody id="productsTable">
        @Html.Action("GetProductData", new { selectedCategory = Model })
    </tbody>
</table>
<hr />
 
@using (Ajax.BeginForm(ajaxOptions))
{
    <div>
        @Html.DropDownList("selectedCategory", new SelectList(
            new[] { "All" }.Concat(Enum.GetNames(typeof(Category)))))
        <button type="submit">Submit</button>
    </div>
}
 
<div>
    @foreach (string category in Enum.GetNames(typeof(Category)))
    {
        <div class="ajaxLink">
            @Ajax.ActionLink(category, "GetProducts",
                new { selectedCategory = category },
                new AjaxOptions {
                Url = Url.Action("GetProductDataJson", new {selectedCategory = category}),
                OnSuccess = "processData"
                })
        </div>
    }
</div>
We added a script function processData to fill the productTable table as long as the JSON data have been retrieved. We bind this JavaScript method only in the Ajax ActionLinks in lines 56-66 through theOnSuccess = “processData” declaration. Line 41 will render the partial view through the GetProductDataaction method when you press the Submit button. So in the same page, we use two different ways to retrieve data with AJAX. One that renders partial views and another that returns JSON data that have to be manipulated by a script on client’s side. Build your application and run it. I need to show you something interesting. Select Car and click the “Submit” button. This will render the partial view and will display all Car objects. The category enum field has been rendered correctly.
ajaxjson_1
Now try to retrieve Car objects or other if you want, but clicking one of the links this time. I have clicked the Car link. Take a look at the Category field now and how JSON data have been retrieved.
ajaxjson_2
This problem occurs due to JSON’s default Encoding. To solve the problem, you need to tell the action method that returns the JSON data, exactly what type of object the client expects to get. Change theGetProductDataJson action method in the ProductController as follow.
1
2
3
4
5
6
7
8
9
10
11
public JsonResult GetProductDataJson(string selectedCategory = "All")
        {
                var data = GetData(selectedCategory).Select(p => new {
                ProductId = p.ProductId,
                Name = p.Name,
                Description = p.Description,
                Price = p.Price,
                Category = Enum.GetName(typeof(Category), p.Category)
                });
            return Json(data, JsonRequestBehavior.AllowGet);
        }
Build and run your solution again. Click an AJAX link like you did before.
ajaxjson_3
That’s it, we have shown how to get and manipulate JSON data retrieved from your MVC controllers. When it comes to JSON another concept may popup in your mind: MVC WebApi. We are going to see how WebApi approach works in a later post. You can download the project we created in this post from here. I hope you enjoyed the post.

No comments:

Post a Comment

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...