Practical ASP.NET

Integrating AJAX and a Client-Side Grid in ASP.NET MVC

Peter completes his series on integrating AJAX and a client-side control by implementing it in ASP.NET MVC. And he draws some conclusions on client-side development in ASP.NET, ASP.NET MVC, and in the world at large.

This column completes a discussion from in an earlier column where I suggested that if, in ASP.NET MVC, you want a grid, you should use a client-side grid that interacts with Web services. In that column and the following ones, I've implemented the ExtJs grid in "traditional" ASP.NET with asmx files and with WCF services (See JavaScript Controls with WCF and ASP.NET). To swap those technologies in and out, I had to make minor changes to my client-side code (one line) and server-side code (integrating with WCF).

In porting the application to ASP.NET MVC, many of the changes are mechanical. After creating an ASP.NET MVC application, I recreated my Entity Framework model (still the easiest way to generate my business objects) for the Northwind database. I put the class file with my data transfer object (CustomerDTO) in the Models folder. I then added the ExtJs files to my application, putting whole of the ExtJs resources and adapter folders to my project's Contents and Scripts folders. I also included the base jQuery library and put my own code in a script file:

<link href="../../Content/ExtJs/resources/css/ext-all.css" 
      rel="stylesheet" type="text/css" />
<script src="../../Scripts/ExtJs/adapter/ext/ext-base.js"
        type="text/javascript"></script>
<script src="../../Scripts/ExtJs/ext-all.js"
        type="text/javascript"></script>
<script src="../../Scripts/jquery-1.4.1.min.js" 
 type="text/javascript"></script>
<script src="../../Scripts/Index.js"
 type="text/javascript"></script>

I added my two buttons to the form on the Index.aspx page called from HomeController. So far, no real changes other than using jQuery to attach my events to my buttons:

$(function () {
	$("#btnGetCustomers").bind("click", function (e) {
		return getCustomers();
	});
	$("#btnSaveCustomers").bind("click", function (e) {
		return saveCustomers();
	});

	}
);

Those changes were all discretionary. But my Web service methods, rather than going in separate files, are now part of the HomeController that handles my view. Changes were definitely required here to make it work. For instance, in the method that returned customer object, I had to explicitly specify the root for my array of JSON object (before, this just defaulted to "d"):

Public Function GetCustomers() As ActionResult

  Dim nw As New northwndEntities
  Dim res = New With {
            .d = From cust As Customer
                  In nw.Customers
                  Select New CustomerDTO With {
                      .ContactName = cust.ContactName, 
                      .CustomerId = cust.CustomerID}
                   }
  Return Json(res)

End Function

The method that accepts the JSON objects coming back from the client needed more extensive changes -- I couldn't get the results returned in a parameter to the method. Instead, I had to assemble the JSON string from the Request object's InputStream, strip out some unnecessary characters and then use the JSON serializer to convert the result into my data transfer object (the update code didn't change). I turned the conversion code into a generic method that I can use in any subsequent application:

Public Function UpdateCustomer(ByVal d As Object) As ActionResult
   Using nw As New northwndEntities
        Dim cDTOs As CustomerDTO()
       cDTOs = ConvertJSON2DotNet(Of CustomerDTO())()
        For Each cDTO As CustomerDTO In cDTOs
            UpdateACustomer(nw, cDTO)
       Next
        nw.SaveChanges()
   End Using
   Return View("Index")
End Function

Function ConvertJSON2DotNet(Of T)() As T
   Dim Json As New StringBuilder
   For ing As Integer = 0 To Request.ContentLength - 1
     Json.Append(Convert.ToChar(Request.InputStream.ReadByte()))
   Next
   Dim ser As New System.Web.Script.Serialization.JavaScriptSerializer()
   Dim js As New JavaScriptSerializer
   Json.Remove(Request.ContentLength - 1, 1)
   Json.Remove(0, 5)
   Return js.Deserialize(Of T)(Json.ToString)
End Function

I then had to change the URLs that my client-side code used to point to my Web service methods:

proxyCustomer = new Ext.data.HttpProxy({
        api: {
            read: "/Home/GetCustomers",
            update: "/Home/UpdateCustomer"
        },
        method: "POST"
    });

And with those changes, my grid displayed customers and let me do updates. The download for this week's column has the working versions of all three projects: The original using ASMX files, the second iteration using WCF, and this version using ASP.NET MVC.

One of the claims for ASP.NET MVC is that it's a better platform for JavaScript than "traditional" ASP.NET. Personally, I'm not getting that. As far as writing or debugging JavaScript code goes, I find ASP.NET and ASP.NET MVC virtually interchangeable. For this application, it was easier to use WCF than MVC Action methods. I'm not suggesting that ASP.NET MVC isn't a great technology -- I am saying that I don't see the JavaScript benefits, compared to the other options. And I realize that this one application does not a development platform make.

On the other hand, I remain excited about the power of the JavaScript and Web services paradigm. There's no doubt that using a client-side grid is more work for the developer than using a GridView and, thanks to the nature of JavaScript, harder to debug (misspell the name of a property? Not a problem: JavaScript just adds the property). We also desperately need a JavaScript MVC programming infrastructure on the client where we're creating applications whose architecture we'd sneer at on the server.

But, for me, the benefits of the AJAX paradigm in terms of responsiveness, scalability, reusability, and integration of services far out way those costs.

Anyway, that's enough client-side programming for a couple of columns, at least. For the next few columns "real" ASP.NET stuff: the listbox, Crystal Reports vs. SSRS, and back to encrypting the web.config. Then it's client-side programming with the new jQuery additions.

About the Author

Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.

comments powered by Disqus

Featured

Subscribe on YouTube