18 January 2008

In the trenches with the ExtJS Grid and ASP.Net

Yesterday I successfully got ExtJS to retrieve data via an ASP.Net web service and wanted to outline the steps here for future reference.

Before getting started, I want to mention that my client runs ASP.Net 2.0 and have only consented to using the standard ASP.Net Ajax download from Microsoft on their servers. No other server software is allowed for this project.

Special thanks to amackay11 and his blog posting on how to consume XML. That posting is invaluable.

Server Side - C# / ASMX / ASP.net

The server side is relatively straightforward. There are a few requirements for coding the web services.

The ASMX code-behind service classes should have the WebService (added automatically by Visual Studio) and WebServiceBinding attributes,with the BasicProfile1_1 as the conforming WSI Profile.

[WebService(Namespace = http://tempuri.org/)]
[WebServiceBinding(ConformsTo=WsiProfiles.BasicProfile1_1)]

The ASMX methods need to be coded with the [WebMethod] attribute (again, this is standard service coding).

[WebMethod]
public XmlDocument getEmployees() {...}

One thing to notice is that the return value is an XmlDocument. .Net makes it easy to return fully formatted XmlDocuments. I recommend using DataSets for return data structures because it is easy to add tables and combine all the data calls into one message from the server to the client.

[WebMethod]
public XmlDocument getEmployees() {
// Create a new data set. The name of the dataset will be the
// opening and closing tag of the return document
DataSet ds = new DataSet("EmployeeSet");
string cmd = "SELECT * FROM tblEmployee";
SqlDataAdapter da = new SqlDataAdapter(cmd, cn());
// Fill the employee table
da.Fill(ds, "Employee");
//Total count from the table for paging purposes
DataTable count = new GetRecordCount("tblEmployee");
// Add the new table to the data set
ds.Tables.Add(count);
// Create and return the data set
XmlDocument doc = new XmlDocument();
doc.LoadXml(ds.GetXml());
return doc;
}

The previous sample code demonstrates how easy C# makes it to publish the XML for client consumption. An ADO.Net dataset is a nice flexible container and if your page has multiple data consumers on the page, the DataSet.Tables.Add() method makes it easy to throw one more structure into the mix before sending data to the client.

The previous code will then return an XML document.

<?xml version="1.0" encoding="utf-8"?>
<EmployeeSet>
<Employee>
<Id>1</Id>
<FirstName>Rob</FirstName>
<LastName>Livingston</LastName>
<Email>fred@yahoo.net</Email>
</Employee>
<Employee>
<Id>2</Id>
<FirstName>Chris</FirstName>
<LastName>Salad</LastName>
<Email>chris@salad.com</Email>
</Employee>
<Employee>
<Id>3</Id>
<FirstName>Adam</FirstName>
<LastName>Funk</LastName>
<Email>adam@funk.com</Email>
</Employee>
<Employee>
<Id>4</Id>
<FirstName>Steve</FirstName>
<LastName>Larsen</LastName>
<Email>larsenr@google.net</Email>
</Employee>
<records>
<count>4</count>
</records>
</EmployeeSet>

Notice the straightforward data structure and how the record count is appended neatly to the end of the XML document.

Client Side / JavaScript / HTML / Ext JS

The client side can be tricky to the uninitiated, especially the JavaScript. ExtJs requires two JavaScript includes and one CSS include in the header. You will also need to include your JavaScript file.

<head runat="server">
<title>Employee Edit Grid</title>
<script src="ext-2.0/adapter/ext/ext-base.js" type="text/javascript"></script>
<script src="ext-2.0/ext-all.js" type="text/javascript"></script>
<script src="JavaScript/Employee.js"></script>
<link rel="stylesheet" type="text/css" href="ext-2.0/resources/css/ext-all.css" />
</head>

One disadvantage of using XML is that verbosity of the server/client message. That being said, one advantage of not using JSON in an ASPX is that it requires 2 additional JavaScript includes (which are generated at run time), which makes the compiler complain (in Visual Studio 2005 at least). I mention that here because the includes can sometimes create headaches for the new developer.

The pattern for developing a grid in Ext JS is as follows:

  • Create a column model object which defines how the columns will be formatted and rendered in the grid
  • Create a record object which defines the data structure
  • Create an XMLReader object to consume the XML Web Service. The XML reader uses the record object to create the final record structure.
  • Create an HttpProxy object to connect to the data source.
  • Create the DataStore object that delivers the data to the data grid. The data store uses an HttpProxy (or some other connection) as well as an XMLReader (or some other DataReader) object as arguments.
  • Create the grid which takes a DataStore and ColumnModel as constructor arguments.

Although the steps are fairly complicated, I am amazed at how little JavaScript is actually required to get data to the page.

The biggest 'gotcha' of the entire process is configuring the HttpProxy object. The main question I had was, how do you consume the service?

Again, .Net makes this easy. Point the URL to the ASMX file / services. The proxy takes a parameters object if the service takes arguments.

I successfully configured a proxy object as listed in the example below.

var proxy = new Ext.data.HttpProxy({
url: 'Services.asmx/getEmployees',
method: 'POST'
});

10 January 2008

Struggling with ExtJS and ASP.Net

I am struggling with ExtJS and ASP.Net 2.0 working together. Today I spent the entire day trying to get a simple grid working. After working most of the day, I finally got it to work. Somehow the joy was gone...hoping to work more with this tool

Following is the methods I used to get a simple unformatted grid up and working.

XML/ASPX
Due to corporate constraints at my current employer, I am forced to use XML and cannot take advantage of the latest JSON technology. That meant that the grid data source has got to be XML.

Exposing XML in ASP.Net is not well documented and not well understood. In fact, I even came across a Jesse Liberty posting asking how to do something similar (I think). (Hat's off to Jesse Liberty - he writes great books - but I have no idea what he is talking about in that post.)

Creating a raw XML page from an ASPX file turns out to not be difficult. Write code to do the following in the Page_Load event:
  • Create a DataSet
  • Connect to the database and fill a table in the dataset via a DataAdapter
  • Create an XmlTextWriter and populate the constructor with the Response.OutputStream and Encoding.UTF8 arguments
  • Call the XmlTextWriter.WriteStartDocument() method
  • Use the data table.WriteXML method, using the XMLTextWriter as the single argument
  • Call the XmlTextWriter.WriteEndDocument() method
The markup also requires two tasks:
  • Clear the page of all markup except for the page directive at the top
  • Add the ContentType attribute to the directive, specifying "text/xml"
The above was done for testing purposes. I think the recommended method for exposing XML is via a Web Service. ExtJS's data reader will (theoretically) read almost XML source. I can definitely vouch that they use a complex XML example on their website for consuming XML.

ExtJS Sample code
The JavaScript code in the example leaves a lot to be desired. You want to look at the one here. The difference is that the second example uses the Ext.data.HttpProxy object. This turns out to be a non-trivial difference. Your code will not be able to read the data without it.

Finally, do yourself a favor and create a record object to pass the data when using the reader to read the data structure. I'm not sure what they are doing in the example - but hopefully I'll learn. Creating a record object will make your life easier.