ASP.NET WebForms And Ajax Go Together Like Oil And Water
In the past few months, I've seen some of the pretty ugly ways in which ASP.NET WebForms works with Ajax.
I've seen the Microsoft Ajax Toolkit which is just embarrassing. Once again, Microsoft tries to lock you in to their stuff rather than the industry standard (jQuery/Prototype) and also provides limited functionality in the form of Ajax web controls and other proprietary stuff. Very nice, but we're big boys now. We don't need the coddling and MS telling us to use their stuff and everything will be OK.
I've seen using a .NET web service and having your Ajax requests call it to get the data they need. It's better than the Microsoft Ajax Toolkit, but it still leaves something to be desired. As far as I can tell, you still have to reference the web service in your page with an <asp:ScriptManager> tag and it also seems like you're making a poor technology choice by building out a web service just to get some data back to your system without the full post back.
Slightly better, but still crummy, is marking methods in your code-behind with the [WebMethod] attribute and making them static so you can get at them in aspx/ascx pages via ajax calls. This is nice because now you can start to use jQuery instead of relying on Microsoft's Ajax implementation, but I see two problems with it. First, the methods have to be static and attributed as WebMethods. The static methods don't let you use instance variables of the class without a lot of ugly and odd workarounds. Second - as is the case with a lot of WebForms code, since it's code-behinds you either have your Ajax methods duplicated across code-behinds or you have different WebMethods scattered in different code-behinds which is pretty messy. It's the same sort of spaghetti code and coupling of responsibilities that a lot of people see as a big problem with the WebForm/code-behind model.
Plus - with all these solutions, I'm pretty sure you need to use a third-party (or write your own) solution to serialize your returned objects as JSON.
So what's the solution?
ASP.NET MVC Works Cleanly With Ajax Out Of The Box
Finally, with ASP.NET MVC, jQuery and Ajax are finally given the attention they deserve. When you create a new ASP.NET MVC project in Visual Studio, it creates a Scripts folder with jquery.js already in it! But their support for jQuery and Ajax goes way beyond that.
I'm not going to get too into the nitty gritty details on ASP.NET MVC - if you want that, there are plenty of resources on the web. But on a high level, the things that make Ajax with ASP.NET MVC so nice are:
- URLs are just routes to resources, in this case a controller and an action. Your URL is not pointing directly to a physical ASPX file. This means you can just point your Ajax request to a controller action and have access to whatever data the controller action returns when its done processing. And since the URL points to the function where the data is coming from, you're less likely to have duplicated code. No matter where you need the same data, you can always just point to that controller action as a URL.
- ASP.NET MVC comes with a JSON serializer. You simply return a JsonResult from your controller action and the objects are converted to JSON for you. This means that you also don't have to mark your methods as WebMethods, or make them static or anything like that. They're just regular methods that return JSON and they're easily called via the controller/action URL.
Here's an insanely simple example to show just how simplified the code can be:
First, the javascript:
1: <script type="text/javascript">
2:
3: $(document).ready(function() {
4: $('#ajaxBtn').click(function() {
5: $.ajax({
6: type: 'POST',
7: url: '/Home/GetFakeObjects',
8: success: function(data) { updateDocument(data) },
9: error: updateDocument
10: });
11: });
12: });
13:
14: function updateDocument(data) {
15: $.each(data, function(key, value) {
16: $('#results').append('<li>' + value +'</li>');
17: });
18: }
19:
20: </script>
And now, the ASP.NET Controller and Action:
1: [HandleError]
2: public class HomeController : Controller
3: {
4: public JsonResult GetFakeObjects()
5: {
6: var returnedObjects = new List<string>();
7: returnedObjects.Add("Dan Donahue");
8: returnedObjects.Add("Somebody Else");
9: returnedObjects.Add("Another Person");
10:
11: return Json(returnedObjects);
12: }
13: }
I don't think the code needs much explanation if you've played with jQuery and Ajax before, but as you can see in the javascript, the url that we're posting to via Ajax is "Home/GetFakeObjects" which ASP.NET MVC routes to new HomeController().GetFakeObjects() and that method returns a JsonResult with that list of people's names. This data is then available in the successMethod of the ajax request. Simple as cake.
But My App Isn't Built With ASP.NET MVC
Never fear... it doesn't have to be. You can actually mix ASP.NET MVC with ASP.NET WebForms in the same project. This is great if you want to start moving your project to ASP.NET MVC piece by piece, or if you want to just take advantage of the Ajax benefits that I described above without converting your entire web app to ASP.NET MVC.
Hit the links below for information on mixing the two technologies in your app.
http://www.hanselman.com/blog/PlugInHybridsASPNETWebFormsAndASPMVCAndASPNETDynamicDataSideBySide.aspx
http://www.packtpub.com/article/mixing-asp.net-webforms-and-asp.net-mvc
Wrap Up
There is only so much finagling you should put up with to solve a problem. This is especially true in code when "finagling" typically means using hacks or generally degrading the quality of the code you're writing in order to work around a problem. When that happens, sometimes it's best to just look into bringing in a better technology that has already solved the problem nicely, rather than desperately looking for the next "quick fix" which will ultimately cause more problems down the line that will need additional "quick fixes". As the Pragmatic Programmer says... quick fixes are quick sand.
So if you have a WebForms app that you're jumping through hoops to add jQuery too, maybe bringing in ASP.NET MVC to, at the very least, handle the Ajax portions, is a good alternative.