Blog Archives

Use ASP.NET’s HttpHandler to bridge the cross-domain gap

When you’re developing client-side applications, a problem you’ll almost inevitably have to deal with is how to work with services that reside outside your website’s domain. Though many modern APIs do support JSONP, which is a clever workaround to somewhat mitigate the cross-domain problem, JSONP has its own problems.

Worse, if you encounter an API with no JSONP support, the cross-domain barrier can quickly become a formidable one. CORS is slowly becoming a viable alternative, but it requires that the remote service support it via special HTTP headers and browser support for CORS is still not ubiquitous.

Until CORS is more broadly supported, an alternative solution is to bounce cross-domain requests through the web server that hosts your website. In ASP.NET, the best tool for implementing that sort of middleman endpoint is the HttpHandler.

In this post, I’ll show you how to create an HttpHandler to service cross-domain requests, how to use jQuery to communicate with the handler, and an example of one improvement that this approach makes possible.

An example remote API

To focus on an example that’s already familiar to many, I’m going to use Twitter. Twitter’s API does support JSONP, which is a viable alternative for consuming it across domains. In fact, the Twitter status that you see in my sidebar to the right was retrieved from Twitter’s API via JSONP.

However, not every service supports JSONP, its third-party script injection mechanism is sometimes problematic, and using JSONP robs us of niceties like local caching. So, for the sake of a good example, let’s find a way to use the Twitter API on the client-side without resorting to JSONP.

Specifically, I’m interested in querying the service for my last few status updates. The Twitter API request to accomplish that looks like this:

Twitter will respond to that with a JSON array of objects representing my (or your) last 20 tweets, which is exactly what we’re after.

The best tool for the job: HttpHandler

If you’re accustomed to using ASP.NET’s page methods and ScriptServices to facilitate communication between client and server, those tools begin to look like a hammer that matches every JSON-shaped nail in sight. However, when simply relaying an external API’s JSON through to the client, they often add unnecessary overhead and complexity.

Rather, a lower-level tool is more appropriate in this case.

HttpHandlers are one of ASP.NET’s most under-utilized tools. They’re simple to implement and allow you to handle requests closer to the metal than WebForms pages or MVC controller actions.

One place in particular where HttpHandlers shine is where you would otherwise consider writing Response.Write statements in a WebForms page’s code-behind. This anti-pattern of using ASPX’s code-behind to get closer to the metal looks similar to approaches that you’ll see on some other platforms, such as PHP, but is not equivalent.

Unfortunately, even if you don’t use WebForms controls or ASPX markup at all, executing that low-level code from an ASPX page’s code-behind requires that every request filter through the full page life cycle. That means even the simplest request still has to percolate all the way from PreInit to Unload, adding needless overhead.

Instead, the HttpHandler is where you should write that sort of code that ultimately boils down to Response.Write calls.

Choosing the right handler type

A tricky issue when you’re writing your first HttpHandler is that Visual Studio presents you with two templates, “ASP.NET Handler” and “Generic Handler”:

The add item dialog presents two choices of HttpHandler templates

Both are similar, but the “ASP.NET Handler” template’s approach requires modifying your web.config to configure which URL your handler accepts requests at. Mucking around in the web.config isn’t terribly difficult, but it’s extra friction which makes the process less approachable.

In the spirit of keeping things simple, let’s stick with the more traditionally file-based “Generic Handler”.

Getting started with your first HttpHandler

After choosing that template, specifying a name, and adding the new file to your site, you’ll end up with a bit of boilerplate code that includes this method:

public void ProcessRequest(HttpContext context) {
  context.Response.ContentType = "text/plain";
  context.Response.Write("Hello World");
}

If you start the site up in Visual Studio and then request your newly-created HttpHandler in a browser, Handler1.ashx if you accept the default name, you will see “Hello World” as you might expect.

That’s not very impressive yet, but the response you saw made its way to your browser without touching WebForms’ page life cycle or filtering through ASP.NET MVC’s routing engine and action filters. While those things are worthwhile niceties for the majority of your application, they’re unwanted overhead when all you need is to efficiently relay some content through the server.

Bouncing a request to Twitter through the HttpHandler

To adapt an HttpHandler for relaying requests to the Twitter API, we can use .NET’s handy WebClient class to make the request to Twitter’s API, and then return the result back through as the handler’s response:

public void ProcessRequest(HttpContext context) {
  WebClient twitter = new WebClient();
 
  // The base URL for Twitter API requests.
  string baseUrl = "http://api.twitter.com/1/";
 
  // The specific API call that we're interested in.
  string request = "statuses/user_timeline.json?id=Encosia";
 
  // Make a request to the API and capture its result.
  string response = twitter.DownloadString(baseUrl + request);
 
  // Set the content-type so that libraries like jQuery can 
  //  automatically parse the result.
  context.Response.ContentType = "application/json";
 
  // Relay the API response back down to the client.
  context.Response.Write(response);
}

That code simply makes an HTTP request to the Twitter API and blindly bounces the result back through as the HttpHandler’s response. For the time being, everything is hard-coded, but we’ll improve on that soon enough.

Using the handler proxy on the client-side

With our web server doing the heavy lifting, using this server-side proxy to make a remote request is trivial:

$.getJSON('TwitterProxy.ashx', function(tweets) {
  // Call a magical function that does all the presentational work.
  displayTweets(tweets);
});

The jQuery code here is actually identical what you’d use when requesting the API via JSONP. Whether that response is truly being fulfilled by the specified URL or it’s being relayed through our HttpHandler, it’s all the same to the jQuery code on the client-side.

As you’ll see when we add caching, this can easily be exploited for good.

Mixing things up with QueryString parameters

The hard-coded approach works well enough, but what if we wanted to be able to query any Twitter account’s recent updates instead of being limited to just that boring Encosia character?

Since HttpHandlers receive an instance of the current HttpContext as the parameter to their ProcessRequest method, it’s easy to access QueryString parameters and react accordingly. For example, this would allow us to request any Twitter account’s timeline by via an id parameter on the QueryString:

public void ProcessRequest(HttpContext context) {
  WebClient twitter = new WebClient();
 
  string baseUrl = "http://api.twitter.com/1/";
 
  // Extract the desired account ID from the QueryString.
  string id = context.Request.QueryString["id"];
 
  // Make a request to the API for the specified id.
  string request = "statuses/user_timeline.json?id=" + id;
 
  // Same as before, from here on out:
  string response = twitter.DownloadString(baseUrl + request);
 
  context.Response.ContentType = "application/json";
  context.Response.Write(response);
}

Now it works exactly the same way as before, but we can choose which Twitter account’s timeline is requested. For example, this URL would request Scott Guthrie‘s latest tweets:

TwitterProxy.ashx?id=ScottGu

Supplying parameters with $.getJSON

To pass this new parameter in from the client-side, you could handcraft the entire URL including the appropriate QueryString. Even better though, $.getJSON has an optional “data” argument that accepts a JavaScript object and converts it to QueryString parameters:

$.getJSON('TwitterProxy.ashx', { id: 'ScottGu' }, function(tweets) {
  displayTweets(tweets);
});

jQuery will automatically URLEncode the parameters you specify in the “data” argument and properly assemble them into the final URL to be requested:

Screenshot of the HttpHandler request generated by the jQuery code above.

Which is exactly what we need it to do.

Using a configuration object like this is cleaner than manually concatenating a string together and makes it easier to vary the parameter at runtime.

Improving performance with server-side caching

An advantage the HttpHandler proxy has over CORS and JSONP is that you can perform any arbitrary server-side processing that you wish, both before and after the remote service repsonds. A great way to take advantage of that is adding a server-side caching layer.

Server-side caching will reduce how often requests actually trigger API calls and can significantly improve performance for requests that are already cached. A caching middleman like this is especially valuable when dealing with rate-limited APIs like Twitter’s.

Let’s say that we wanted to cache Twitter responses for up to five minutes, for example:

public void ProcessRequest(HttpContext context) {
  // This will be the case whether there's a cache hit or not.
  context.Response.ContentType = "application/json";
 
  // Check to see if the twitter status is already cached,
  //   then retrieve and return the cached value if so.
  // 8/3/11: Updated with more robust test, thanks to ctolkien.
  object tweetsCache = context.Cache["tweets-" + id];
 
  if (tweetsCache != null) {
    string cachedTweets = tweetsCache.ToString();
 
    context.Response.Write(cachedTweets);
 
    // We're done here.
    return;
  }
 
  WebClient twitter = new WebClient();
 
  // Move along; nothing to see here. The concatenation is just
  //  to avoid horizontal scrolling within the meager 492
  //  pixels I have to work with here.
  string url = "http://api.twitter.com/1/statuses/" +
               "user_timeline.json?id=Encosia";
 
  string tweets = twitter.DownloadString(url);
 
  // This monstrosity essentially just caches the WebClient result
  //  with a maximum lifetime of 5 minutes from now.
  // If you don't care about the expiration, this can be a simple
  //  context.Cache["tweets"] = tweets; instead.
  context.Cache.Add("tweets", tweets,
    null, DateTime.Now.AddMinutes(5),
    System.Web.Caching.Cache.NoSlidingExpiration,
    System.Web.Caching.CacheItemPriority.Normal,
    null);
 
  context.Response.Write(tweets);
}

Adding the intermediate cache results in a tremendous performance improvement after the first request:

Screenshot of an initial uncached request to Twitter and then the subsequent, cached requests

With the server able to immediately serve requests within the five minute caching window, subsequent $.getJSON requests are an order of magnitude faster!

Perhaps even more importantly in the case of Twitter, these four refreshes only counted as one API call against my hourly rate-limit.

Conclusion

Using HttpHandlers as server-side proxies turns out to be a simple way to solve the pesky cross-domain restrictions that we’ve all run into from time to time. All said and done, using an HttpHandler to proxy third-party requests takes few lines of code, but offers nearly unlimited flexibility.

In addition to the obvious benefit of getting around the cross-domain restriction, bouncing requests through your own server potentially has a range of other benefits, including:

  • Error handling – This approach not only passes unhandled exceptions on the WebClient request back through to the client-side, but it also gives you the ability to enhance the error handling with your own sanity checks and constraints.
  • Caching – As shown in this post’s final example, you can very easily interject your own caching layer for requests passing through the HttpHandler proxy. That’s especially useful when working against rate limited or potentially slow/flaky APIs (like Twitter’s).
  • Security – When you’re accustomed to server-side programming, the revealing nature of client-side JavaScript can be unnerving. Learning to appropriately partition sensitive algorithms and data between client and server is key to mitigating that issue. Along those lines, moving the remote request to code running on your server is one way to keep sensitive information like API keys and passwords safely hidden from view-source and client-side developer tools.
  • Reliability – One of JSONP’s less obvious drawbacks is the fact that it relies on injecting a third-party script. However, your users may be using something like NoScript to purposely block third-party scripts, effectively shutting down your ability to use JSONP. Even if you prefer JSONP in most cases, a local server-side proxy can be helpful as a fallback in case of unexpected JSONP failures.

That’s not to say that there’s no downsides to this approach. When you’re using an HttpHandler proxy, it’s important to keep in mind that it can be slower since you’re making a series of two connections instead of a single, direct one. You also lose the ability to request content with the user’s third-party cookies attached to the request, which is helpful in some cases.

Overall, using server-side proxies is a very useful item to have in your toolbox. I hope this post has served to introduce you to the approach and/or given you better insight into how you can use HttpHandlers to your advantage.

Get the source

If you’d like to browse through a complete working example of what’s been covered in this post, take a look at the companion project at GitHub. Or, if you’d like to download the entire project and run it in Visual Studio to see it in action yourself, grab the ZIP archive.

HttpHandler-Proxy on GitHubHttpHandler-Proxy.zip

Related posts:

  1. AJAX, file downloads, and IFRAMEs
  2. The easiest way to break ASP.NET AJAX pages
  3. Why ASP.NET AJAX UpdatePanels are dangerous

You’ve been reading Use ASP.NET’s HttpHandler to bridge the cross-domain gap, originally posted at Encosia. I hope you enjoyed it, and thanks for reading.

If you’ve got any feedback, please click through and leave a comment; I’d love to hear from you. You can click here to jump directly to the comment section of this post.

Use ASP.NET’s HttpHandler to bridge the cross-domain gap

When you’re developing client-side applications, a problem you’ll almost inevitably have to deal with is how to work with services that reside outside your website’s domain. Though many modern APIs do support JSONP, which is a clever workaround to somewhat mitigate the cross-domain problem, JSONP has its own problems.

Worse, if you encounter an API with no JSONP support, the cross-domain barrier can quickly become a formidable one. CORS is slowly becoming a viable alternative, but it requires that the remote service support it via special HTTP headers and browser support for CORS is still not ubiquitous.

Until CORS is more broadly supported, an alternative solution is to bounce cross-domain requests through the web server that hosts your website. In ASP.NET, the best tool for implementing that sort of middleman endpoint is the HttpHandler.

In this post, I’ll show you how to create an HttpHandler to service cross-domain requests, how to use jQuery to communicate with the handler, and an example of one improvement that this approach makes possible.

An example remote API

To focus on an example that’s already familiar to many, I’m going to use Twitter. Twitter’s API does support JSONP, which is a viable alternative for consuming it across domains. In fact, the Twitter status that you see in my sidebar to the right was retrieved from Twitter’s API via JSONP.

However, not every service supports JSONP, its third-party script injection mechanism is sometimes problematic, and using JSONP robs us of niceties like local caching. So, for the sake of a good example, let’s find a way to use the Twitter API on the client-side without resorting to JSONP.

Specifically, I’m interested in querying the service for my last few status updates. The Twitter API request to accomplish that looks like this:

Twitter will respond to that with a JSON array of objects representing my (or your) last 20 tweets, which is exactly what we’re after.

The best tool for the job: HttpHandler

If you’re accustomed to using ASP.NET’s page methods and ScriptServices to facilitate communication between client and server, those tools begin to look like a hammer that matches every JSON-shaped nail in sight. However, when simply relaying an external API’s JSON through to the client, they often add unnecessary overhead and complexity.

Rather, a lower-level tool is more appropriate in this case.

HttpHandlers are one of ASP.NET’s most under-utilized tools. They’re simple to implement and allow you to handle requests closer to the metal than WebForms pages or MVC controller actions.

One place in particular where HttpHandlers shine is where you would otherwise consider writing Response.Write statements in a WebForms page’s code-behind. This anti-pattern of using ASPX’s code-behind to get closer to the metal looks similar to approaches that you’ll see on some other platforms, such as PHP, but is not equivalent.

Unfortunately, even if you don’t use WebForms controls or ASPX markup at all, executing that low-level code from an ASPX page’s code-behind requires that every request filter through the full page life cycle. That means even the simplest request still has to percolate all the way from PreInit to Unload, adding needless overhead.

Instead, the HttpHandler is where you should write that sort of code that ultimately boils down to Response.Write calls.

Choosing the right handler type

A tricky issue when you’re writing your first HttpHandler is that Visual Studio presents you with two templates, “ASP.NET Handler” and “Generic Handler”:

The add item dialog presents two choices of HttpHandler templates

Both are similar, but the “ASP.NET Handler” template’s approach requires modifying your web.config to configure which URL your handler accepts requests at. Mucking around in the web.config isn’t terribly difficult, but it’s extra friction which makes the process less approachable.

In the spirit of keeping things simple, let’s stick with the more traditionally file-based “Generic Handler”.

Getting started with your first HttpHandler

After choosing that template, specifying a name, and adding the new file to your site, you’ll end up with a bit of boilerplate code that includes this method:

public void ProcessRequest(HttpContext context) {
  context.Response.ContentType = "text/plain";
  context.Response.Write("Hello World");
}

If you start the site up in Visual Studio and then request your newly-created HttpHandler in a browser, Handler1.ashx if you accept the default name, you will see “Hello World” as you might expect.

That’s not very impressive yet, but the response you saw made its way to your browser without touching WebForms’ page life cycle or filtering through ASP.NET MVC’s routing engine and action filters. While those things are worthwhile niceties for the majority of your application, they’re unwanted overhead when all you need is to efficiently relay some content through the server.

Bouncing a request to Twitter through the HttpHandler

To adapt an HttpHandler for relaying requests to the Twitter API, we can use .NET’s handy WebClient class to make the request to Twitter’s API, and then return the result back through as the handler’s response:

public void ProcessRequest(HttpContext context) {
  WebClient twitter = new WebClient();
 
  // The base URL for Twitter API requests.
  string baseUrl = "http://api.twitter.com/1/";
 
  // The specific API call that we're interested in.
  string request = "statuses/user_timeline.json?id=Encosia";
 
  // Make a request to the API and capture its result.
  string response = twitter.DownloadString(baseUrl + request);
 
  // Set the content-type so that libraries like jQuery can 
  //  automatically parse the result.
  context.Response.ContentType = "application/json";
 
  // Relay the API response back down to the client.
  context.Response.Write(response);
}

That code simply makes an HTTP request to the Twitter API and blindly bounces the result back through as the HttpHandler’s response. For the time being, everything is hard-coded, but we’ll improve on that soon enough.

Using the handler proxy on the client-side

With our web server doing the heavy lifting, using this server-side proxy to make a remote request is trivial:

$.getJSON('TwitterProxy.ashx', function(tweets) {
  // Call a magical function that does all the presentational work.
  displayTweets(tweets);
});

The jQuery code here is actually identical what you’d use when requesting the API via JSONP. Whether that response is truly being fulfilled by the specified URL or it’s being relayed through our HttpHandler, it’s all the same to the jQuery code on the client-side.

As you’ll see when we add caching, this can easily be exploited for good.

Mixing things up with QueryString parameters

The hard-coded approach works well enough, but what if we wanted to be able to query any Twitter account’s recent updates instead of being limited to just that boring Encosia character?

Since HttpHandlers receive an instance of the current HttpContext as the parameter to their ProcessRequest method, it’s easy to access QueryString parameters and react accordingly. For example, this would allow us to request any Twitter account’s timeline by via an id parameter on the QueryString:

public void ProcessRequest(HttpContext context) {
  WebClient twitter = new WebClient();
 
  string baseUrl = "http://api.twitter.com/1/";
 
  // Extract the desired account ID from the QueryString.
  string id = context.Request.QueryString["id"];
 
  // Make a request to the API for the specified id.
  string request = "statuses/user_timeline.json?id=" + id;
 
  // Same as before, from here on out:
  string response = twitter.DownloadString(baseUrl + request);
 
  context.Response.ContentType = "application/json";
  context.Response.Write(response);
}

Now it works exactly the same way as before, but we can choose which Twitter account’s timeline is requested. For example, this URL would request Scott Guthrie‘s latest tweets:

TwitterProxy.ashx?id=ScottGu

Supplying parameters with $.getJSON

To pass this new parameter in from the client-side, you could handcraft the entire URL including the appropriate QueryString. Even better though, $.getJSON has an optional “data” argument that accepts a JavaScript object and converts it to QueryString parameters:

$.getJSON('TwitterProxy.ashx', { id: 'ScottGu' }, function(tweets) {
  displayTweets(tweets);
});

jQuery will automatically URLEncode the parameters you specify in the “data” argument and properly assemble them into the final URL to be requested:

Screenshot of the HttpHandler request generated by the jQuery code above.

Which is exactly what we need it to do.

Using a configuration object like this is cleaner than manually concatenating a string together and makes it easier to vary the parameter at runtime.

Improving performance with server-side caching

An advantage the HttpHandler proxy has over CORS and JSONP is that you can perform any arbitrary server-side processing that you wish, both before and after the remote service repsonds. A great way to take advantage of that is adding a server-side caching layer.

Server-side caching will reduce how often requests actually trigger API calls and can significantly improve performance for requests that are already cached. A caching middleman like this is especially valuable when dealing with rate-limited APIs like Twitter’s.

Let’s say that we wanted to cache Twitter responses for up to five minutes, for example:

public void ProcessRequest(HttpContext context) {
  // This will be the case whether there's a cache hit or not.
  context.Response.ContentType = "application/json";
 
  // Check to see if the twitter status is already cached,
  //   then retrieve and return the cached value if so.
  // 8/3/11: Updated with more robust test, thanks to ctolkien.
  object tweetsCache = context.Cache["tweets-" + id];
 
  if (tweetsCache != null) {
    string cachedTweets = tweetsCache.ToString();
 
    context.Response.Write(cachedTweets);
 
    // We're done here.
    return;
  }
 
  WebClient twitter = new WebClient();
 
  // Move along; nothing to see here. The concatenation is just
  //  to avoid horizontal scrolling within the meager 492
  //  pixels I have to work with here.
  string url = "http://api.twitter.com/1/statuses/" +
               "user_timeline.json?id=Encosia";
 
  string tweets = twitter.DownloadString(url);
 
  // This monstrosity essentially just caches the WebClient result
  //  with a maximum lifetime of 5 minutes from now.
  // If you don't care about the expiration, this can be a simple
  //  context.Cache["tweets"] = tweets; instead.
  context.Cache.Add("tweets", tweets,
    null, DateTime.Now.AddMinutes(5),
    System.Web.Caching.Cache.NoSlidingExpiration,
    System.Web.Caching.CacheItemPriority.Normal,
    null);
 
  context.Response.Write(tweets);
}

Adding the intermediate cache results in a tremendous performance improvement after the first request:

Screenshot of an initial uncached request to Twitter and then the subsequent, cached requests

With the server able to immediately serve requests within the five minute caching window, subsequent $.getJSON requests are an order of magnitude faster!

Perhaps even more importantly in the case of Twitter, these four refreshes only counted as one API call against my hourly rate-limit.

Conclusion

Using HttpHandlers as server-side proxies turns out to be a simple way to solve the pesky cross-domain restrictions that we’ve all run into from time to time. All said and done, using an HttpHandler to proxy third-party requests takes few lines of code, but offers nearly unlimited flexibility.

In addition to the obvious benefit of getting around the cross-domain restriction, bouncing requests through your own server potentially has a range of other benefits, including:

  • Error handling – This approach not only passes unhandled exceptions on the WebClient request back through to the client-side, but it also gives you the ability to enhance the error handling with your own sanity checks and constraints.
  • Caching – As shown in this post’s final example, you can very easily interject your own caching layer for requests passing through the HttpHandler proxy. That’s especially useful when working against rate limited or potentially slow/flaky APIs (like Twitter’s).
  • Security – When you’re accustomed to server-side programming, the revealing nature of client-side JavaScript can be unnerving. Learning to appropriately partition sensitive algorithms and data between client and server is key to mitigating that issue. Along those lines, moving the remote request to code running on your server is one way to keep sensitive information like API keys and passwords safely hidden from view-source and client-side developer tools.
  • Reliability – One of JSONP’s less obvious drawbacks is the fact that it relies on injecting a third-party script. However, your users may be using something like NoScript to purposely block third-party scripts, effectively shutting down your ability to use JSONP. Even if you prefer JSONP in most cases, a local server-side proxy can be helpful as a fallback in case of unexpected JSONP failures.

That’s not to say that there’s no downsides to this approach. When you’re using an HttpHandler proxy, it’s important to keep in mind that it can be slower since you’re making a series of two connections instead of a single, direct one. You also lose the ability to request content with the user’s third-party cookies attached to the request, which is helpful in some cases.

Overall, using server-side proxies is a very useful item to have in your toolbox. I hope this post has served to introduce you to the approach and/or given you better insight into how you can use HttpHandlers to your advantage.

Get the source

If you’d like to browse through a complete working example of what’s been covered in this post, take a look at the companion project at GitHub. Or, if you’d like to download the entire project and run it in Visual Studio to see it in action yourself, grab the ZIP archive.

HttpHandler-Proxy on GitHubHttpHandler-Proxy.zip

Related posts:

  1. Save yourself some typing when you call ASP.NET services
  2. 3 mistakes to avoid when using jQuery with ASP.NET AJAX
  3. jQuery 1.5?s AJAX rewrite and ASP.NET services: All is well

You’ve been reading Use ASP.NET’s HttpHandler to bridge the cross-domain gap, originally posted at Encosia. I hope you enjoyed it, and thanks for reading.

If you’ve got any feedback, please click through and leave a comment; I’d love to hear from you. You can click here to jump directly to the comment section of this post.

Inline AJAX DropDown and Text Editing with Asp.Net MVC and jQuery

including how to use a database to populate the dropdown


First thing is first, you will need to download
jQuery
and the
Jeditable
plugin (I prefer to refer to it as the Jedi-Table!).
Be sure to put these references in your View (or Masterpage).
Next, you have to set up a view on which to use an inline edit.
I find that I often want to use this approach on tables of information.
For this View, I will set it to use an IEnumerable of an Item I have called ‘ItemOwner’ (this is arbitrary and does not really matter).
It will be a simple table that lists the Name and the Country of the owner, both of which will be editable inline.
Here is the Index in my ExampleController.cs:

myDataContext db = new myDataContext();
public ActionResult Index()
{
    // get the info for the 'Countries' dropdown:
    ViewData["countries"] = db.Countries
        .Select(x => new SelectListItem()
        {
            Text = x.Name,
            Value = x.Id.ToString()
        }).ToJson();

    // get the 'ItemOwners' I am interested in:
    var owners = db.ItemOwners.Take(3);

    return View(owners);
}

As you can see there, I am also pulling the countries from the database and throwing them into the ViewState – we will get to this later.
Since the Country is actually a foreign key relation, the value is set to an integer which is the identity field in the database.
It is also using a .ToJson() extension which takes a IEnumerable<SelectListItem> and
puts it into a simple JSON string that I use which is here:

public static string
    ToJson(this IEnumerable<SelectListItem> slis)
{
    string output = "{";
    if (slis != null)
    {
        for (int i = 0; i < slis.Count(); i++)
        {
            output += " '" + slis.Skip(i)
            .First().Value + "': '" +
            slis.Skip(i).First().Text + "'" +
            (i == slis.Count() - 1 ? " " : ",");
        }
    }
    return output += "}";
}

There is probably a better way to do that… but I don’t know it?!

I am also pulling 3 ItemOwners from the database, I know this is silly, but it just an example.
Here is how I am displaying them in the view:

<table>
    <thead>
        <tr>
            <th>Name</th>
            <th>Country</th>
        </tr>
    </thead>
    <tbody>
        <% foreach(var owner in Model) { %>
        <tr>
            <td><%= owner.Name %></td>
            <td><%= owner.Country.Abbreviation %></td>
        </tr>
        <% } %>
    </tbody>
</table>

Now that there is a simple table we want to make it a bit more interactive.
Since we aregoing to make all of these fields editable, we need to add in a way to distinguish exactly what they are.
To do that, we will need two things: the id of the item they are editing, and the type of inline editing we will be doing (i.e. dropdown or text input).
So to do that, let’s add in a few css classes and an identifieng ID:

<td id="name<%= owner.Id %>" class="editable text">
    <%= owner.Name %></td>
<td id="ctry<%= owner.Id %>" class="editable dropdown">
    <%= owner.Country.Abbreviation %></td>


And now add a little css to make them appear to be clickable:

td.editable:hover
{ cursor:pointer; background-color:Orange; }

Now they all look like you can click on them, so we can move on to making the click actually do something.



This is where the jQuery comes in, and it is very simple.
I have made these ‘helper’ methods in Javascript to make all of my inline calls centrally controllable, I keep this in my sites script folder so if I change one inline edit, I change them all; it also makes for more readable Javascript on each page.

function InlineDropdown(collectionToDropDown, ajaxAddress, dropDownDataSet) {
    collectionToDropDown.editable(ajaxAddress,
    {
        data: dropDownDataSet,
        type: 'select',
        indicator: 'saving...',
        tooltip: 'click to edit...',
        submit: 'Save',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextbox(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress,
    {
        indicator: 'saving...',
        tooltip: 'click to edit...',
        style: 'inherit',
        placeholder: 'click to edit'
    });
}

function InlineTextarea(collectionToInline, ajaxAddress) {
    collectionToInline.editable(ajaxAddress,
    {
        type        : 'textarea',
        rows        : 4,
        indicator   : 'saving...',
        tooltip     : 'click to edit...',
        style       : 'inherit',
        submit      : 'Save',
        onblur      : 'ignore',
        placeholder : 'click to edit'
    });
}

Obviously you can read all about the options on the Jeditable
page, but this is how I set them.
Also notice I have a InineTextarea included as well for a textarea which is not covered here but works the exact same.

Now the jQuery calls are almost trivial:

InlineTextbox(
    $('td.editable.text'),
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>"
);

InlineDropdown(
    $('td.editable.dropdown'),
    "<%= Url.Content("~/Ajax/ItemOwner.ashx") %>",
    <%= ViewData["countries"].ToString() %>
);

What that is doing is sending the POST requests to the specified address.
The POST contains a few things:

  • id – the id of the element that sent the request
  • value – the new value passed by the element

We are also passing more information there – remember that we passed both the type of field to edit and the id of the ItemOwner to edit, ie [name837] which emans we want to edit the Name field of ItemOwner 837.
So we simply set up an ashx handler (which we specified above) to do the dirty work:

public void ProcessRequest(HttpContext context)
{
    string newValue;
    try
    {
        myDataContext db = new myDataContext();
        string elementId = context.Request.Form["id"];

        // since we made the first 4 of the id the 'field' whic to edit
        // we can just pull the first 4 letters for use in our switch:
        string fieldToEdit = elementId.Substring(0, 4);

        //now take anything after those 4 and it is the Id:
        int idToEdit = Convert.ToInt32(elementId.Remove(0, 4));

        // the value is simply a string:
        newValue = context.Request.Form["value"].Trim();

        // now that we have the id, get the ItemOwner from the db
        ItemOwner owner = db.ItemOwners.FirstOrDefault(x => x.Id == idToEdit);

        // after all is said and done, we will return newValue to the user so the field
        // looks as if the change has taken place (which it has)

        // using the field we pulled above, decide what to do:
        switch (fieldToEdit)
        {
            // name is easy
            case "name": owner.Name = newValue; break;

            // since the country is an integer foreign key, we need to Convert.ToInt32:
            case "ctry":
                owner.CountryId = Convert.ToInt32(newValue);
                // now that we have recorded the value, we want to return the text to
                // the user and not the id value which would make no sense
                newValue = db.Countries.FirstOrDefault(x => x.Id == owner.CountryId).Abbreviation;
                break;
            // if it wasn't caught, something is wrong:
            default: throw new Exception("invalid fieldToEdit passed");
        }

        db.SubmitChanges(); // save it
    }
    // now if an exceptions were reported, the user can see what happened
    // this also inform the user nothing was saved
    // you could easily make this not reported to the user and logged elsewhere
    catch (Exception ex)
    { newValue = "Error: " + ex.Message + " [nothing written to db]"; }

    //now return what you want in the element:
    context.Response.Write(newValue);
}

And that is all it takes.

ASMX ScriptService mistake – Invalid JSON primitive

One group of searches that consistently brings traffic here is variations on the error: Invalid JSON primitive. Unfortunately, the post that Google sends that traffic to doesn’t address the issue until somewhere within its 150+ comments.

Today, the topic gets its own post.

If you’ve worked with ASMX ScriptServices or Page Methods without ASP.NET AJAX’s client-side proxy (e.g. using jQuery or pure XMLHttpRequest code), you’ve may have seen this cryptic error yourself. Or, perhaps you’ve just arrived here due to seeing it for the first time.

Either way, you may be surprised to learn that the most common reason for this error is that you’ve lied to ASP.NET during your AJAX request.

It all begins with the Content-Type

HTTP’s Content-Type header is a fundamental aspect of communication between browsers and servers, yet often remains hidden from us in day-to-day development. The Content-Type header allows an HTTP connection to describe the format of its contents, using Internet media types (also known as MIME types). A few common ones that you’ve probably seen before are text/html, image/png, and the more topical application/json.

Without the flexible negotiation process content types provide, your users’ browsers and your version of IIS would have to both be “ASMX Compatible” and “JSON Compatible” in order for ScriptServices to function. What a nightmare that would be! The IE6 difficulties we face today would pale in comparison.

Further, Content-Type negotiation is part of what allows a single URL, such as WebService.asmx, to represent data in more than one format (e.g. XML and JSON in ASMX’s case).

The benefits of Content-Type negotiation are well worth a bit of occasional hassle.

Okay, but why does that matter?

When your browser sends a POST request, the W3C’s recommendation is that it should default to using a Content-Type of application/x-www-form-urlencoded. The HTML 4.01 spec describes that serialization scheme:

This is the default content type. Forms submitted with this content type must be encoded as follows:

  1. [Omitted for brevity; not relevant to this post.]
  2. The control names/values are listed in the order they appear in the document. The name is separated from the value by ‘=’ and name/value pairs are separated from each other by ‘&’.

For an example of what that means, consider this simple form:

<form method="post">
  <label>First Name</label>
  <input id="FirstName" value="Dave" name="FirstName" />
 
  <label>Last Name</label>
  <input id="LastName" value="Ward" name="LastName" />
</form>

When the preceding form is submitted with URL encoded serialization, the request’s POST data will look like this:

Firebug screenshot showing the URLEncoded POST data

That standardized serialization format allows a server-side backend like ASP.NET to decipher a form submission’s contents and give you access to each key/value pair. Regardless of what sort of browser submits a form to the server, the Content-Type facilitates a predictable conversion from POST data to server-side collection.

In other words, the Content-Type corresponds to a serialization scheme.

What does that have to do with JSON Primitives?

Understanding Content-Type negotiation and how it relates to serialization is important due to its role in coaxing JSON out of ASMX ScriptServices. Specifically, the fact that you must set a Content-Type of application/json on the request means you’re instructing ASP.NET to interpret your input parameters as JSON serialized data.

However, the W3C’s mandate of URL encoding by default means that most AJAX libraries default to that serialization scheme. Similarly, AJAX tutorials targeting endpoints other than ASMX ScriptServices (including even ASP.NET MVC examples) will describe sending URL encoded data to the server.

In other words, when you’re working with a client-side object like this:

var Person = { FirstName: 'Dave',
               LastName:  'Ward' }

The default serialization scheme makes it easy to inadvertently transmit that data to the server as a URL encoded string:

FirstName=Dave&LastName=Ward

Again, remember that a Content-Type of application/json is a requirement when working with ASMX ScriptServices. By setting that Content-Type on the request, you’ve committed to sending JSON serialized parameters, and a URL encoded string is far from valid JSON.

In fact, it’s invalid JSON (primitive?), hence the cryptic error message.

Instead of the URL encoded string above, you must be sure to send a JSON string:

{'FirstName':'Dave','LastName':'Ward'}

Whether you’re using XMLHttpRequest directly or a JavaScript library that abstracts the details, getting your request’s serialization wrong is the root of the invalid JSON primitive error. However, a more specific issue tends to be the leading cause of this happening.

When good JavaScript libraries go bad

The most common source of this error stems from a subtlety of using jQuery’s $.ajax() method to call ASMX ScriptServices. Cobbling together snippets of code from the documentation, platform agnostic tutorials, and even posts here on my site, it’s easy to end up with something like this:

// WRONG!
$.ajax({
  type: 'POST',
  contentType: 'application/json',
  dataType: 'json',
  url: 'WebService.asmx/Hello',
  data: { FirstName: "Dave", LastName: "Ward" }
});

Notice the JavaScript object literal being supplied to $.ajax()’s data parameter. That appears vaguely correct, but will result in the invalid JSON primitive error.

Why? jQuery serializes $.ajax()’s data parameter using the URL encoded scheme, regardless of what Content-Type is specified. Even though the contentType parameter clearly specifies JSON serialization, this URL encoded string is what jQuery will send to the server:

FirstName=Dave&LastName=Ward

That obviously isn’t valid JSON!

The solution is as simple as two single-quotes:

// RIGHT
$.ajax({
  type: 'POST',
  contentType: 'application/json',
  dataType: 'json',
  url: 'WebService.asmx/Hello',
  data: '{ FirstName: "Dave", LastName: "Ward" }'
});

Did you spot the difference?

Instead of a JavaScript object literal, the data parameter is a JSON string now. The difference is subtle, but helpful to understand. Since it’s a string, jQuery won’t attempt to perform any further transformation, and the JSON string will be unimpeded as it is passed to the ASMX ScriptService.

It doesn’t have to be this way

The problem is trivial once you’re aware of the underlying issue, but there’s not a great reason I can see why things need to be this way in the first place. Either half of this equation could easily provide a remedy.

jQuery – I believe the most correct solution would be $.ajax() attempting to honor the serialization scheme indicated by its contentType parameter. In the case of application/json fixing this could be easy as testing for JSON.stringify and using it if available, to avoid adding any complexity/size to jQuery core.

That would leave it our responsibility to reference a copy of json2.js in older browsers, but that convention wouldn’t be much of a burden. We generally do that anyway when the client-side objects get complex.

Microsoft – It’s absolutely correct that the framework throws an error when you lie to it about what you’re sending. However, a bit of leniency could potentially save thousands of hours spent troubleshooting this problem (if my search traffic is any indication of its prevalence).

Is there any reason that the ScriptHandlerFactory can’t intelligently differentiate between between JSON and URL encoded inputs? If the first non-whitespace character of the request isn’t an opening curly brace, why not attempt to deserialize it as URL encoded before throwing an invalid JSON primitive error?

###

Originally posted at Encosia. If you’re reading this elsewhere, come on over and see the original.

ASMX ScriptService mistake – Invalid JSON primitive

ASMX ScriptService mistakes: Installation and configuration

Continuing my series of posts about ASMX services and JSON, in this post I’m going to cover two common mistakes that plague the process of getting a project’s first ASMX ScriptService working: Installing System.Web.Extensions into the GAC and configuring your web.config.

System.Web.Extensions (aka ASP.NET AJAX)

The ability for ASMX services to return raw JSON is made possible by two key features originally added by the ASP.NET AJAX Extensions v1.0:

  • JavaScriptSerializerThe JavaScriptSerializer class is the actual workhorse that translates back and forth between JSON strings and .NET CLR objects. Though less powerful than WCF’s DataContractJsonSerializer and third-party libraries like Json.NET, JavaScriptSerializer is likely all you’ll ever need for simple AJAX callbacks.
  • ScriptHandlerFactory – There are several more classes behind the scenes*, but the ScriptHandlerFactory is the tip of the iceberg that you’ll need to remember during configuration. Redirecting ASMX requests through this HttpHandler is what coordinates the pairing of ScriptService with JavaScriptSerializer to provide automatic JSON handling.

Though both of these classes appear in the System.Web.Script namespace, they actually reside in ASP.NET AJAX’s System.Web.Extensions assembly. That has different implications depending on which version of ASP.NET your site targets:

  • 1.x – No support for ScriptServices. A custom HttpHandler coupled with a third party library like Json.NET is your best bet (if anyone has a good tutorial on doing this under 1.x, let me know so that I can link to it).
  • 2.0 – ScriptServices are available in ASP.NET 2.0 with the installation of the ASP.NET AJAX Extensions v1.0.
    • That means that the ASP.NET AJAX installer needs to be run on the server that hosts your site, not just on your local development machine.
    • For some of a ScriptService’s features to work in medium trust (i.e. shared hosting), the System.Web.Extensions assembly needs to be in your server’s global assembly cache (GAC). Don’t waste your time trying to make it work in your site’s /bin directory; insist that the extensions be properly installed on the server.
  • 3.5+ – As of .NET 3.5, System.Web.Extensions ships with the framework. No additional assemblies need be installed.

* If you’re interested in the internals, I highly recommend downloading the ASP.NET AJAX Extensions v1.0 source and taking a look at ScriptHandlerFactory, RestHandlerFactory, and RestHandler. Though the classes have changed slightly since v1.0, they are still very similar.

Rerouting the ASMX handler via web.config

With the System.Web.Extensions assembly installed in the GAC, the remaining configuration step is an element in your site’s web.config. To take advantage of the ScriptService functionality, ASP.NET must be instructed to reroute ASMX requests through the ScriptHandlerFactory instead of ASP.NET’s standard ASMX handler.

This step is often unnecessary. The project templates in ASP.NET 3.5+ include all the necessary configuration elements, and ASP.NET 2.0 sites created with the “AJAX Enabled” templates are also pre-configured correctly.

However, if you find yourself unable to coax JSON out of an ASMX ScriptService, verifying your web.config is one of the best first steps in troubleshooting the issue. Whether due to a web.config generated by an older project template, accidental modification, or other issues, missing the httpHandlers web.config setting is a very common pitfall.

What should appear varies slightly depending on which version of ASP.NET your project targets. Regardless of your framework version, the config elements should be added to the <httpHandlers> section and are the only elements necessary. The variety of other config items required for the UpdatePanel and ScriptManager aren’t crucial to the ScriptService functionality.

ASP.NET 2.0 (with the ASP.NET AJAX Extensions installed)

<configuration>
  <system.web>
    <httphandlers>
      <remove path="*.asmx" verb="*" />
      <add path="*.asmx" verb="*" Culture=neutral, validate="false"
           type="System.Web.Script.Services.ScriptHandlerFactory, 
                 System.Web.Extensions, Version=1.0.61025.0,
                 PublicKeyToken=31bf3856ad364e35" />
    </httphandlers>
  </system.web>
</configuration>

ASP.NET 3.5

<configuration>
  <system.web>
    <httphandlers>
      <remove path="*.asmx" verb="*" />
      <add path="*.asmx" verb="*" Culture=neutral, validate="false"
           type="System.Web.Script.Services.ScriptHandlerFactory, 
                 System.Web.Extensions, Version=3.5.0.0,
                 PublicKeyToken=31bf3856ad364e35" />
    </httphandlers>
  </system.web>
</configuration>

ASP.NET 4

Thankfully, ASP.NET 4 has taken steps to reverse the trend of ever-enlarging baseline web.config files. By moving common configuration items such as the ScriptService’s HttpHandler to the default machine.config, each individual site need not include those configuration elements in their specific web.config files.

Unless you go out of your way to manually remove their HttpHandler, ASMX ScriptServices will work automatically in any ASP.NET 4 site.

###

Originally posted at Encosia. If you’re reading this elsewhere, come on over and see the original.

ASMX ScriptService mistakes: Installation and configuration

ASMX and JSON – Common mistakes and misconceptions

While we were recording episode 5 of Mastering jQuery, I found myself running down a lengthy list of misconceptions and potential pitfalls when it comes to using ASMX services for AJAX callbacks. After years of fielding questions revolving around that topic, I suppose I’ve developed a decent handle on the issues most often encountered.

To preemptively surface some of that commonly requested information, I’m going to publish a series of relatively short posts, each describing one mistake or misconception that I’ve seen come up frequently.

To get started, I want to cover one of the most fundamental of these misconceptions: That ASMX services can’t return JSON.

Misconception: ASMX services are limited to XML

One of the most stubbornly persistent misconceptions about ASMX services is the rumor that they are limited to returning XML. With that notion mind, many developers understandably avoid them for client-side AJAX callbacks. When every byte counts, raw JSON is always preferable to the bloat of XML.

However, the introduction of ASP.NET AJAX removed that XML limitation.

In any ASP.NET 2.0+ AJAX enabled site, one of ASP.NET AJAX’s additions is something called the ScriptService. When a ScriptService is called in the correct manner, it automatically returns its result serialized as JSON instead of XML.

In fact, these ASMX ScriptServices even accept their parameters as JSON.

The ASP.NET AJAX “ScriptService”

If you’ve created an ASMX service in the past few years, you’ve probably seen this blurb at the beginning of the default template:

// To allow this Web Service to be called from script, 
//   using ASP.NET AJAX, uncomment the following line. 
// [System.Web.Script.Services.ScriptService] 
public class WebService : System.Web.Services.WebService {

Since it never explicitly mentions JSON and implies a tight coupling with ASP.NET AJAX, it’s easy to understand why the ScriptService’s true power sometimes goes unnoticed. Thankfully, that attribute does much more than simply expose ASP.NET AJAX specific functionality.

In fact, the ScriptService attribute enables all of an ASMX service’s methods to respond with raw JSON if they are requested correctly. For example, these ScriptServices can easily send and receive JSON in conjunction with a third party library, without a ScriptManager or MicrosoftAjax.js anywhere to be seen.

Two simple requirements

As I alluded to earlier, the one stipulation is that these ScriptServices only return JSON serialized results if they are requested properly. Otherwise, even a service marked with the attribute will return XML instead of JSON. I can only assume that’s part of the reason for the misconception that ASMX services cannot respond with JSON.

Scott Guthrie has a great post on the specific requirements for coercing JSON out of ScriptServices. To summarize that, requests to the service methods must meet two requirements:

  • Content-Type – The HTTP request must declare a content-type of application/json. This informs the ScriptService that it will receive its parameters as JSON and that it should respond in kind.
  • HTTP Method – By default, the HTTP request must be a POST request. It is possible to circumvent this requirement, but it is advisable to stick with HTTP POST requests when dealing with JSON.

That’s it.

As long as those two requirements are satisfied, anything from low-level XMLHttpRequest code, to third-party libraries like jQuery, to ASP.NET AJAX itself can easily retrieve JSON serialized data from ASMX services.

###

Originally posted at Encosia. If you’re reading this elsewhere, come on over and see the original.

ASMX and JSON – Common mistakes and misconceptions

Mastering jQuery now available at TekPub

Mastering jQuery

If you haven’t been following the progress of Rob Conery and James Avery’s new venture, TekPub, you’ve been missing out on some great instructional videos. I especially like that they trend slightly Alt.NET, giving you more balanced information than is sometimes available from “official” .NET screencasts.

For the past few weeks, I’ve been working with James to record a series of episodes for TekPub myself: Mastering jQuery.

Mastering jQuery walks through the basics of using jQuery, the revolutionary JavaScript framework that makes writing client-side code fun and easy, and then dives into the details of writing AJAX enabled ASP.NET MVC and ASP.NET Web Forms applications. We will also cover popular plugins and extending jQuery in future episodes.

Today, the first video in that series is available: Getting Started with jQuery.

In this episode we cover the basics of getting started with jQuery. We start with a basic HTML page and show how to include jQuery, how to write your first code, and explain all of the moving pieces and how they work.

If you’ve been following my site and working with jQuery already, the first episode may sound elementary, but there’s going to be something for everyone before the series is finished. By the third episode, we’re already into topics like making AJAX calls to MVC controller actions and progressively enhancing an entry form with the jQuery form plugin.

I hope you’ll head over to TekPub, and have a look for yourself.

###

Originally posted at Encosia. If you’re reading this elsewhere, come on over and see the original.

Mastering jQuery now available at TekPub

Emulate ASP.NET validation groups with jQuery validation

In my most recent post, I demonstrated a workaround to allow using the jQuery validation plugin with WebForms pages. The basic idea was to trigger validation only on submissions that occurred within a single logical form, instead of catching submissions anywhere on WebForms’ all-encompassing physical form.

This approach worked fine for a single logical form, but wasn’t robust enough when handling validation for multiple logical forms on a single page. Additionally, it did not properly handle the enter key, allowing users to (perhaps accidentally) slip past validation if they simply hit the enter key within a TextBox.

In this post, we will continue by refining the solution from last time. So, if you haven’t read the previous post, familiarize yourself with it first. Specifically, this post will cover how to implement an analogue of WebForms’ ValidationGroup, use that to independently validate multiple form regions, handle the enter key, and refactor the final solution to minimize duplicated code.

ValidationGroups

In WebForms, we have the concept of a ValidationGroup to mitigate the issues that come with wrapping the entire page in a single form element. Whether right or wrong in principle, this scheme does a pretty good job of keeping the ASP.NET Validation controls from getting their wires crossed on complex forms.

However, using ASP.NET’s ValidationGroups requires that you use the WebForms validation controls, which generates quite a bit of cruft in your markup and injects two additional script references on your page.

An example of some of the client-side code the ASP.NET Validators generates

If you’re like me, trying to trend away from client-heavy WebForms pages these side-effects are prohibitive.

Emulating Validation Groups

Though its implementation renders a bit messy on the client-side, the WebForms paradigm of a ValidationGroup is exactly what we need for segregating our physical form element into logical forms. In fact, I’m going to use the same nomenclature in this example (ValidationGroup and CausesValidation).

Using CSS classes as flags is a great way to emulate that concept in plain (X)HTML markup. Especially when using jQuery, CSS “flags” are a great way to tag elements with arbitrary attributes, that are easy to find with simple DOM selectors later. Taking the form shown in my previous post and tagging its fieldsets with a validationGroup class, we end up with this markup:

<fieldset class="validationGroup">
  <legend>Returning customer?  Login here</legend>
 
  <!-- Username and Password labels and inputs here -->
</fieldset>

Not a very large change, but it allows us to keep these logical forms separate, both when performing validation and when initially setting up their validation triggers.

Creating a CausesValidation counterpart

ValidationGroups may control the organization of logical forms, but it’s the controls marked with the CausesValidation property that drive validation of those forms. In similar fashion, we need a way to indicate which elements should trigger our own emulation of WebForms’ grouped validation.

Sticking with the same naming scheme and CSS flagging technique, it makes sense to tag our Button controls with a .causesValidation class:

<fieldset class="validationGroup">
  <legend>Returning customer?  Login here</legend>
 
  <!-- Username and Password labels and inputs here -->
 
  <asp:Button runat="server" ID="Login" Text="Login"
              CssClass="causesValidation" />
</fieldset>

Now we just need to wire up functionality to make those causesValidation flags actually do something.

Acting on the validationGroup flag

With the markup modified to allow selective targeting of the validation groups, the next step is implementing validation functionality that leverages that targeting. Using jQuery’s powerful CSS-based selectors, that isn’t difficult:

$(document).ready(function () {
  $("#form1").validate({ onsubmit: false });
 
  // Search for controls marked with the causesValidation flag 
  //  that are contained anywhere within elements marked as 
  //  validationGroups, and wire their click event up.
  $('.validationGroup .causesValidation').click(function (evt) {
    // Ascend from the button that triggered this click event 
    //  until we find a container element flagged with 
    //  .validationGroup and store a reference to that element.
    var $group = $(this).parents('.validationGroup');
 
    var isValid = true;
 
    // Descending from that .validationGroup element, find any input
    //  elements within it, iterate over them, and run validation on 
    //  each of them.
    $group.find(':input').each(function (i, item) {
      if (!$(item).valid())
        isValid = false;
    });
 
    if (!isValid)
      evt.preventDefault();
  });
});

Note: For more explanation of any uncommented code above, be sure to see the previous post in this series. Those parts are explained in detail there.

This sets up a click event handler on any element flagged with the causesValidation class; the two Button controls in our case. When those raise click events, we start at the triggering element and use the parents() traversal method to search upward for the nearest parent flagged as a validationGroup.

In this example, that will find a reference to the fieldset which contains the Button control that triggers the click event (e.g. if the user clicks the Login Button, then $group will store a reference to the first fieldset element).

With that reference to the the logical form requiring validation, jQuery’s find() traversal method allows us to select a set of all the input elements within just that region of the page. Note that this will also include the Button control that triggered the event, but since the valid() method returns true for elements that don’t have validation rules configured, this doesn’t cause a problem.

From there, it’s straightforward to iterate over the appropriate input elements and validate each independently, using the valid() trick covered in the last post.

Handling the enter key

At this point, everything works pretty well, so long as the user clicks on the Button controls to submit the logical forms. Unfortunately, things fall apart if the user triggers form submission by pressing enter in one of the form fields.

One way to fix that would be to handle the form’s onsubmit event, determine if an element flagged with the causesValidation class triggered the submission, and then run through our validation first. That’s perfectly valid, but I avoid that because it tends to clash with other functionality that handles the event; the jQuery form plugin for example.

The alternative that I prefer is to handle a validated field’s onkeydown event. That way, if the element does need to trigger validation, it can do so early, and get out of the way quickly otherwise.

Using jQuery’s cross-browser normalized event object, testing for the enter key is not difficult at all. When handling keyboard related events, one property of that object is keyCode. This property will contain the ASCII character code of the key which triggered the event. In the case of the enter key, that keyCode is 13.

That in mind, this is a first iteration of adding enter key handling to our existing validation code:

// Select any input[type=text] elements within a validation group
//  and attach keydown handlers to all of them.
$('.validationGroup :text').keydown(function (evt) {
  // Only execute validation if the key pressed was enter.
  if (evt.keyCode == 13) {
    // Validation code goes here.
  }
});

Whether the form is submitted by clicking a button or hitting the enter key within one of our validation groups’ text fields, the appropriate inputs will be validated, error messages displayed if necessary, and submission will only continue if the form is valid.

Refactoring to eliminate duplication

After adding the keydown handler, everything works great, but it’s no good to have that validation code duplicated for both the click and keydown handlers. By passing around a reference to the jQuery event object, we can reuse the same validation code for both event types and make the code much more concise:

$(document).ready(function () {
  // Initialize validation on the entire ASP.NET form.
  $("#form1").validate({
    // This prevents validation from running on every
    //  form submission by default.
    onsubmit: false
  });
 
  // Search for controls marked with the causesValidation flag 
  //  that are contained anywhere within elements marked as 
  //  validationGroups, and wire their click event up.
  $('.validationGroup .causesValidation').click(ValidateAndSubmit);
 
  // Select any input[type=text] elements within a validation group
  //  and attach keydown handlers to all of them.
  $('.validationGroup :text').keydown(function (evt) {
    // Only execute validation if the key pressed was enter.
    if (evt.keyCode == 13) {
      ValidateAndSubmit(evt);
    }
  });
});
 
function ValidateAndSubmit(evt) {
  // Ascend from the button that triggered this click event 
  //  until we find a container element flagged with 
  //  .validationGroup and store a reference to that element.
  var $group = $(evt.currentTarget).parents('.validationGroup');
 
  var isValid = true;
 
  // Descending from that .validationGroup element, find any input
  //  elements within it, iterate over them, and run validation on 
  //  each of them.
  $group.find(':input').each(function (i, item) {
    if (!$(item).valid())
      isValid = false;
  });
 
  // If any fields failed validation, prevent the button's click 
  //  event from triggering form submission.
  if (!isValid)
    evt.preventDefault();
}

First, the validation code is refactored into a separate function: Validate.

Since it needs the ability to conditionally call preventDefault in order to stop form submission, the function accepts the event handlers’ jQuery event object as a parameter.

In fact, because $(this) is a reasonable place to begin the parents() traversal for either event that may call the method, very little refactoring is necessary.

The one thing that may seem strange is that the Validate function is being passed as a click handler without any parameters. The reason that this works is because the Validate function is defined with the same signature that jQuery expects. Because of that alignment, Validate will automatically be provided with the same event object that we’ve been using in anonymous callback functions thus far.

Calculated readability

Note that I attached keydown handlers to all of the text inputs within a validation group, regardless of whether or not they are actually validated fields. Similarly, you may have noticed that the click handler finds every input element within its validation group, even if those inputs aren’t marked for validation. This may seem like an oversight, but it’s an intended readability compromise.

You could modify the selector to be more precise, selecting only fields flagged with validation classes (e.g. required, email, number, etc). However, this gets messy when you consider the wide variety of classes that are valid for tagging elements with jQuery validation functionality.

Rather than be precisely specific, I rely on the fact that jQuery validation’s valid() method returns true for elements which are not configured for validation. So, even if we do end up checking the validation status of a few irrelevant input fields, it won’t adversely impact the outcome of the validation process.

There are performance penalties to performing validation on these unnecessary elements, but it is negligible for a reasonably sized form. The ancillary inputs would have to number in the thousands before the penalty were noticeable, at which no one will probably ever successfully complete it anyway!

Conclusion

There are even more enhancements to be had, but I think this brings the solution to a point that it’s useful. With multiple logical forms handled and the perennially pesky enter key tamed, the majority of use cases should be covered.

The most troublesome issue still remaining is that care should be taken to avoid nesting container elements with the validationGroup class on them. Otherwise, the Validate() function will search “too high” and possibly hinge validation on input fields that are not intended. It’s an edge case (fixable if necessary), but something to keep in mind.

Another edge case is that, unlike the ASP.NET Validators, these validation groups can’t overlap. For my own use, this has never been an issue. I’m curious if that’s a real-world problem for any of you.

Finally, an entirely different approach well worth considering is John Rummell’s xVal for Webforms. Using Data Annotations to specify validation rules is gaining a lot of popularity, so it’s worth investigating options like this one. At the minimum, it will help you be more familiar with how validation is handled in ASP.NET MVC.

Hope that helps. Be sure to take a look at the source download to see everything pulled together and one extra usability feature that I didn’t have time to cover.

Source

Download WebForms-jq-validation-p2.zip

###

Originally posted at Encosia. If you’re reading this elsewhere, come on over and see the original.

Emulate ASP.NET validation groups with jQuery validation

Using jQuery validation with ASP.NET WebForms

Validation Sticker

You’ve probably noticed that Jörn Zaefferer’s jQuery validation plugin has been gaining momentum in the ASP.NET community lately. Between Microsoft’s implied endorsement via ASP.NET MVC 2.0 integration and the plugin’s recent inclusion on the Microsoft AJAX CDN, adoption is only increasing. Unfortunately for those who don’t or can’t use ASP.NET MVC yet, using the validation plugin within WebForms applications can be tricky.

Because the WebForms Postback model requires that the entire page be contained within a single form element, form submissions that shouldn’t trigger validation are likely. ASP.NET’s built-in validation controls solve this with ValidationGroups and the CausesValidation property, but that doesn’t help if you’d prefer to use the jQuery validation plugin.

However, there are a couple relatively easy workarounds that make it possible to use the jQuery validation plugin on WebForms pages, without re-architecting the page or its forms. In this post, I’ll show you why the WebForms page structure is a problem, how to make jQuery validation work with it, and an example of implementing those workarounds.

Note: I want to preface this by saying that you should never rely entirely on client-side validation. The jQuery validation plugin can be a great replacement for the client-side part of the ASP.NET Validators, but it is not a complete replacement on its own. Use responsibly!

<form> over function

When it comes to using jQuery validation, the trouble with WebForms is that it requires all of the ASP.NET controls on a page to be contained within a single form element. That doesn’t lead to any problems in simple demos, but things are more complicated when it comes to real-world pages. They often require multiple logical forms on the same page, and that’s where the problems start.

For example, consider the common scenario of having both a login form and a customer information form on the same page. We’ve probably all seen something like this before:

<form id="form1" runat="server">
  <fieldset>
    <legend>Returning customer?  Login here</legend>
 
    <label for="Username">Email:</label>
    <asp:TextBox runat="server" ID="Username" />
 
    <label for="Password">Password:</label>
    <asp:TextBox runat="server" ID="Password" TextMode="Password" />
 
    <asp:Button runat="server" ID="Login" Text="Login" />
  </fieldset>
 
  <fieldset id="BillingInfo">
    <legend>New customer?  Provide the following</legend>
 
    <label for="FirstName">First Name:</label>
    <asp:TextBox runat="server" ID="FirstName" CssClass="required" />
 
    <label for="LastName">Last Name:</label>
    <asp:TextBox runat="server" ID="LastName" CssClass="required" />
 
    <label for="Address">Address:</label>
    <asp:TextBox runat="server" ID="Address" CssClass="required" />
 
    <label for="City">City:</label>
    <asp:TextBox runat="server" ID="City" CssClass="required" />
 
    <label for="State">State:</label>
    <asp:TextBox runat="server" ID="State" CssClass="required" />
 
    <label for="Zip">Zip:</label>
    <asp:TextBox runat="server" ID="Zip" CssClass="required" />
 
    <asp:Button runat="server" ID="Order" Text="Submit Order" />
  </fieldset>
</form>

In most web frameworks, you would divide both logical forms into separate form elements, but WebForms requires both to remain joined within its single form element. This means that clicking either of the Button controls will submit both logical forms together.

Once applied to a form through its default usage, the jQuery validation plugin will attempt to validate all of the elements on that form any time it is submitted. That automation is usually handy, but it means users trying to submit our login form will be denied due to validation failing on the unrelated fields below.

Since using separate form elements containing WebForms controls isn’t realistic, we need to tackle this on the client-side and find a way to make jQuery validation more WebForms-friendly.

Taming jQuery validation

To remedy this problem, we first need to prevent the jQuery validation plugin from automatically triggering on every form submission. The initializer’s onsubmit property allows us to do just that:

$(document).ready(function() {
  // Initialize validation on the entire ASP.NET form
  $("#form1").validate({
    // This prevents validation from running on every
    //  form submission by default.
    onsubmit: false
  });
});

That fixes our problem of the login form triggering unwanted validation in the form below, but it creates another issue. Now, neither of the forms will validate when submitted.

Taking control with on-demand validation

Instead of relying on the plugin to automatically validate form submissions, you may also use a less widely known method for triggering the validation on-demand. When added to a page, one of the new methods that jQuery validation exposes on the jQuery object is valid().

When valid() is called on the jQuery object returned from selecting a “validated” form element, it will trigger validation on every field within the form and return a Boolean value indicating whether or not the form is valid.

$(document).ready(function() {
  $("#form1").validate({
    onsubmit: false
  });
 
  $("#Order").click(function(evt) {
    // Validate the form and retain the result.
    var isValid = $("#form1").valid();
 
    // If the form didn't validate, prevent the
    //  form submission.
    if (!isValid)
      evt.preventDefault();
  });
});

At first glance, this code might look incomplete to you. We care about more than just preventing form submissions when the form fails validation; we must also indicate the validation errors to the user.

Fortunately, the valid() method has the very useful side effect of displaying the plugin’s configured validation errors for any fields it finds to fail validation.

From the user’s perspective, this implementation is the same as the original one using the default usage. This method just happens to also have the added benefit of actually allowing returning users to log in.

To be continued…

This solution is a good start, but has (at least) two flaws.

First, it doesn’t handle keyboard triggered form submissions. What happens if the user hits the enter key in one of the TextBoxes?

Second, what if we want to also validate the login form? If validation rules are added to that form’s fields, we’ll have exactly the opposite problem as what we started with. Valid submissions in the lower form will be prevented by validation failures on the upper form.

In my next post, I’ll show you how to easily solve both of these remaining issues. So, be sure to stay tuned via RSS, email, or twitter.

Download the Source

Download WebForms-jq-validation.zip

###

Originally posted at Encosia. If you’re reading this elsewhere, come on over and see the original.

Using jQuery validation with ASP.NET WebForms

Simplify calling ASP.NET AJAX services from jQuery

As jQuery’s popularity in the .NET community has risen over the past year, one recurring theme I’ve seen is the desire to refactor away the details of using it to call ASP.NET AJAX services. Whether through helper function or specialized jQuery plugin, I’ve seen numerous methods proposed and/or in use.

Personally, the syntax never bothered me. The contentType parameter is ugly, but I have a Visual Studio code snippet for the $.ajax call and rarely think about it.

That came to an end earlier this year, when I started using dataFilter. I needed to isolate my code from the “.d” issue, and wanted to take advantage of browser-native JSON parsing in Firefox 3.5 and IE8, which required a bulky dataFilter.

Repeating that entire callback function in every $.ajax call was not acceptable. So, I was happy to learn that jQuery provides an excellent solution for consolidating settings to be used in multiple instances of $.ajax.

In this post, I’ll show you how to use that consolidation feature, and exactly how I am now using that to more simply call ASP.NET AJAX services with jQuery.

Configuring $.ajax’s default settings

Rather than wrapping the $.ajax call in a plugin or helper function, jQuery provides a built-in solution that I think is a better alternative:  $.ajaxSetup.

$.ajaxSetup accepts an array of settings that allows you to supply defaults for any of the parameters that you would set in an $.ajax call. Settings like contentType, type, and dataFilter are all fair game, for example.

Using this function, it’s easy to set jQuery’s $.ajax defaults to match the refined settings that we worked out together last year:

$.ajaxSetup({
  type: "POST",
  contentType: "application/json; charset=utf-8",
  data: "{}"
});

Because parameters to $.ajax override these defaults, presetting “data” to an empty JSON string is safe. Any $.ajax call that does specify a data parameter will function as expected, since the default will be ignored.

The particular issue caused by forgetting the empty data parameter can be difficult to track down, and only shows up after you’ve deployed your application to IIS. So, having the default as a safety net is recommended.

Adding JSON parsing improvements

Because $.ajaxSetup also supports setting a dataFilter, adding the “.d” isolation and browser-native JSON parsing from my last two posts is easy:

$.ajaxSetup({
  type: "POST",
  contentType: "application/json; charset=utf-8",
  data: "{}",
  dataFilter: function(data) {
    var msg;
 
    if (typeof (JSON) !== 'undefined' &&
        typeof (JSON.parse) === 'function')
      msg = JSON.parse(data);
    else
      msg = eval('(' + data + ')');
 
    if (msg.hasOwnProperty('d'))
      return msg.d;
    else
      return msg;
  }
});

This dataFilter processing is actually what pushed me to start using $.ajaxSetup in all of my own projects. It was one thing to accept multiple contentType and method declarations, but repeating the dataFilter for every $.ajax call was more than I could handle.

Putting it to work

With the ASP.NET AJAX defaults set in $.ajaxSetup, all that’s required to call a “ScriptService” or page method is the URL and a success callback:

$.ajax({
  url: "HelloWorld.asmx/Hello",
  success: function(msg) {
    console.log(msg);
  }
});

In fact, even the success callback is optional. For example, if you were periodically pinging a “heartbeat” service to keep the user’s session alive, $.ajax would only need the service’s URI.

This more concise syntax makes your service calls far more readable, especially for developers who aren’t familiar with the content-type required by ASP.NET AJAX.

Caution: Sometimes it works too well

While this is a handy way to simplify calls to ASP.NET AJAX services, do understand that $.ajaxSetup applies to all of jQuery’s AJAX derivatives. Setting the default HTTP method and content-type may also impact code and plugins that use jQuery’s built-in communication functionality (e.g. $.getJSON, $.post, etc).

For example, I often use jTemplates as a client-side templating solution. Because its processTemplateURL routine relies on $.ajax to retrieve remote template files, setting the ASP.NET AJAX content-type and POST method in $.ajaxSetup breaks that functionality of jTemplates.

Fixing that problem wasn’t difficult, but it also wasn’t immediately obvious what had caused the issue in the first place. In my experience using this technique, the undesirable side effects are rare enough that it’s not a serious concern, but do be aware of the potential.

Conclusion

I’ve been using this in production for several months now, with great results. Users have noticed the increased speed that came with browser-native JSON parsing, the “.d” isolation has reduced regression errors due to some code we run on both 2.0 and 3.5 servers, and it requires less effort on my part to do all that.

What do you think? Is this helpful?

Would a Visual Studio template with this rolled in be something you would use?

###

Originally posted at Encosia. If you’re reading this elsewhere, come on over and see the original.

Simplify calling ASP.NET AJAX services from jQuery

WP Like Button Plugin by Free WordPress Templates