Before I get into it I would like to reiterate
some of my personal development objectives of late:
1. Don't do ANY UI manipulation in any of my server side API's. The sole
purpose of any API within the applications I build is to deal with business
layer logic and the data related to it. Ideally speaking I would want my API
to return structured data which is easily transformed into a format for the
client application using the API (e.g. JSON). I have had experiences within
another development team in the recent past where the API returned HTML with
the data and to say that this is a mess is understating the obvious - if you
think about it quickly then you can understand the impact of one style or
layout change will have on this approach. It also blurs your application in
terms of its concerns and makes testing a problem. So ideally I dont want
any UI logic in any of my API's.
2. The second objective I have is that all my UI for web applications must
be handled with client-side scripts. Client side includes both static HTML,
CSS and JavaScript, and in this instance I specifically refer to JavaScript
and the handling of my API's data using JSON, for which I use jQuery. The
REST (:D) of this article is dedicated to the AJAX options available in an
ASP.NET application.
Dealing with AJAX in an ASP.NET Application
Developing ASP.NET applications gives you two
"frameworks" or "architectures" to work with:
-
ASP.NET Webforms
-
ASP.NET MVC
Notice that each architecture or framework
uses the ASP.NET runtime which in turn runs on the .NET framework, and part
of the .NET framework is the Common Language Runtime (CLR). People often
think ASP.NET automatically refers to webforms. The difference between the
architectures lies both in how it was designed and who it was designed for.
Webforms was designed for Windows Forms developers working within the Visual
Studio drag-and-drop environment and aimed to provide an abstraction of
Windows Forms for the web. With webforms you could simply drag and drop
controls onto a design surface and assign properties to the controls. The
problem with webforms was that it required state management and to deal with
the state management viewstate was created. Basically state management
refers to a controls ability to retain its "value state" across postbacks.
So if I created a simple label and set its text to "hello world" viewstate
is used to retain that text value throughout the life of the rendered page.
Webforms also introduced the concept of the Page Life Cycle, which exposed
certain events at certain points of the page's rendering process. The
problem with viewstate is that the viewstate is inserted into your HTML
pages which causes the page to bloat - so there is no clean markup.
Viewstate totally goes against the grain of how the web works - being
stateless.
ASP.NET MVC addresses some of the issues
associated with webforms by using a mature and well known architectural
pattern - Model-View-Controller, as used in Ruby-On-Rails. ASP.NET MVC does
not use the page lifecycle for a start and it embraces the web's
statelessness instead of fighting it. The result is that you have no
ViewState and this means that there is no HTML bloat and you also have
complete control over your HTML.
There are a couple of ways to consume AJAX
requests in ASP.NET but they fall into two categories:
With my latest development effort I started
out by using Page Methods in an ASP.NET Webform application. Why ASP.NET
webforms you may ask? Well I wanted to focus on the business value and I
just started out with Webforms without concerning myself too much with the
technical side of things. Page methods implement a REST-like architecture
and simply requires that you add a WebMethod attribute in your code-behind's
CS file like this:
[WebMethod]
public static Dictionary<DATETIME, List<MonthReport>> GetLastSixMonthReport()
You could then access the web method through
jQuery like this (notice the Default.aspx/GetImportsLastSixMonths):
$.ajax({
type: "POST",
url: "Default.aspx/GetImportsLastSixMonths",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
var dict = msg.d;
var html = '';
$("#importsData").empty();
html += dict;
$("#importsData").append(html);
}
});
The main issue I have with this approach was
that if I wanted to create a new web project I had to re-create the web
methods - which is not ideal. So if I wanted to move this project over to a
new MVC app I would have to recreate the methods. Based on this I decided to
create a separate WCF project that could host all my methods and deliver
them in a REST-JSON way. To get WCF to deliver JSON in a REST fashion you
need to do two important things:
-
Configure
it
-
Add the
appropriate Interface attributes
Configuring a WCF service for JSON requires
that you add an endpoint address to the service itself like this:
<ENDPOINT name="RESTEndpoint" contract="IMyInterface" binding="webHttpBinding" behaviorConfiguration=
"AjaxBehaviour" address="ajaxEndpoint" />
You also need to add an endPointBehavior like
this:
<BEHAVIOR name="AjaxBehaviour">
<WEBHTTP />
</BEHAVIOR>
/ENDPOINTBEHAVIORS>
In your service behaviours you need to set
httpGetEnabled to true as well. I added this in my service class:
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
In service contract I added the WebInvoke
attribute to each method, like this:
[OperationContract]
[WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
ProductCollectionView[] GetProductCollectionViews();
Once I set this up I could access the JSON-enabled
endpoint: http://localhost/LRB2CServiceLayer_v1/LRB2c.svc/ajaxEndpoint/GetProductCollectionViews
and I would see the JSON. Notice that the JSON comes with a MethodNameResult
as opposed to the "d" from the page methods. Consuming it uses a similar
approach to the jQuery for page methods, except that you use a GET (which is
a little dodgy):
$.ajax({
type: "GET",
url: "http://localhost/LRB2CServiceLayer_v1/LRB2c.svc/ajaxEndpoint/GetProductCollectionViews",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
var dict = msg["GetProductCollectionViewsResult"];
var html = '';
$("#importsData").empty();
html += dict;
$("#importsData").append(html);
}
});
I decided to convert the WCF service to a
class library (DLL) instead because I had all kinds of issues with XSS
because I ran the WCF service as a separate web application. The idea was
that a WCF service was easily shared between web apps. I basically combined
the class library with a MVC web app instead. A class library can just as
easily be shared among multiple projects or web sites. The JSON that MVC
returns is different to WCF and Webforms - it just returns the object, no
indexer/key such as "d". Getting MVC to return JSON is pretty straight
forward:
[HttpPost]
public JsonResult GetGetProductCollectionViews()
{
}
Of the three methods/technologies I described
I like the ASP.NET MVC approach because: