Archive for the ‘ASP.NET’ Category

Performance tuning tricks for ASP.NET and IIS 7 – part 1

Wednesday, July 7th, 2010

In this first installment of performance tuning tricks for ASP.NET and IIS 7 we will look at some of the easy, yet powerful possibilities in the web.config file. By taking advantage of these few tricks we can increase the performance of any new or existing website without changing anything but the web.config file.

The following XML snippets must be placed in the <system.webServer> section of the web.config.

HTTP compression

You’ve always been able to perform HTTP compression in ASP.NET by using third-party libraries or own custom built ones. With IIS 7 you can now throw that away and utilize the build-in compression available from the web.config. Add the following line to enable HTTP compression:

<urlCompression doDynamicCompression="true" doStaticCompression="true" dynamicCompressionBeforeCache="true"/>

By default, only text based content types are compressed.

doDynamicCompression

Setting this attribute to true enables compression of dynamically generated content such as pages, views, handlers. There really aren’t any reasons not to enable this.

doStaticCompression

This attribute allows you to decide whether or not you want static files such as stylesheets and script files to be compressed. Images and other non-text content types will not be compressed by default. This is also something you want to enable.

dynamicCompressionBeforeCache

If you do output caching from within your ASP.NET website, you can tell IIS 7 to compress the output before putting it into cache. Only if you do some custom output caching you might run into issues with setting this to true. Try it and test it. If your website works with this enabled, then you definitely want to keep it enabled.

Tip

By default, only text based content types are compressed. That means if you send application/x-javascript as content type, you should change it to text/javascript. If you use some custom modules in your website, then you might experience conflicts with the IIS 7 compression feature.

Resources

Cache static files

To speed up the load time for the visitors, it is crucial that everything that can be cached by the browser IS cached by the browser. That includes static files such as images, stylesheets and script files. By letting the browser cache all these files means it doesn’t need to request them again for the duration of the cache period. That saves you and your visitors a lot of bandwidth and makes the page load faster. A well primed browser cache also triggers the load and DOMContentLoaded event sooner.

By adding this snippet to your web.config, all static files are cached in the browser for 1 year:

<staticContent>
     <clientCache cacheControlMode="UseMaxAge" cacheControlMaxAge="365.00:00:00"/>
</staticContent>

This setting sets the expiration date of the file one year in the future. It does that by setting an HTTP header that instruct the browser to add the file to its internal cache. If you hit F5 or ctrl-F5, the browser will request the files no matter what the expiration is set to.

A major problem with client-side caching is if your static files change before the cache expires. Then the visitor with the old version in the cache won’t see the new file until she clears the browser cache or hit F5. Therefore, this setting must be used with caution and probably with a shorter expiration time. In part 2 of this series I’ll address this problem and provide a simple solution to it.

Tip

Make sure that user sensitive information isn't cached on the browser. It will then be available by anyone else using the same browser.

Resources

Using an iPhone with the Visual Studio development server

Thursday, June 10th, 2010

Testing an ASP.NET site on an iPhone Developing iPhone-optimized portions of an ASP.NET website presents a challenge. More specifically, it’s testing your creations that can be difficult.

Apple’s iPhone emulator only runs on Macs and the Windows-based alternatives don’t emulate mobile Safari well. That leaves us using an actual device as the only high-fidelity option for testing. That’s not all bad; especially when it comes to a touch-driven interface, testing with the real thing is preferable.

Unfortunately, the ASP.NET Development Server bundled with Visual Studio is severely restricted when it comes to testing externally. In fact, it could hardly be more restrictive – it refuses all external connections, even if those connections originate from the same local subnet.

In this post, I’m going to show you one way I’ve found to circumvent that restriction, how to configure your iPhone to take advantage of that, and how to connect to the development server once those steps are completed.

Note: This post specifically describes configuring an iPhone, but the same approach will work for any mobile device that supports using an HTTP proxy.

Fooling the ASP.NET Development Server

The fundamental problem is that Visual Studio’s ASP.NET Development Server actively refuses external connections. That’s a logical precaution if you’re in the business of selling web server operating systems, but it adds unnecessary friction to the legitimate endeavor of testing with mobile devices.

The solution that I stumbled onto uses a tool that you may already have installed: Fiddler. If you aren’t familiar with Fiddler, this recording of Eric Lawrence’s session at MIX10 is a great way to learn a lot about Fiddler in relatively little time.

The feature that we’re specifically interested in is its HTTP proxy server. Unlike the ASP.NET Development Server, Fiddler does not restrict connections from external devices. Even better, routing an external device’s connections through Fiddler is misdirection enough to fool the development server into accepting them.

Checking Fiddler’s proxy port

With Fiddler installed, the first step is to determine which port it’s running the proxy server on. On fresh installs, the default setting is port 8888.

If you’ve had Fiddler installed a while, it doesn’t hurt to double check the setting. You can do that in Fiddler by navigating to Tools > Fiddler Options, and selecting the Connections tab:

Finding the port that Fiddler's proxy server listens on

While you have that dialog open, also verify that the three checkboxes circled above are checked.

Finding your IP address

The next step is to determine your machine’s IP address on the local network. A quick way to do that is running ipconfig at the command prompt.

To open a command prompt, press Win + R, type cmd in the field, and hit enter.

Running cmd

At the command prompt that opens, type ipconfig and hit enter.

Finding the local IP address with ipconfig

What you’re looking for here is the IPv4 address for your machine’s primary network adapter. “Local Area Connection” is mine, so I need to use 192.168.1.119 to connect to my machine. A wireless connection is fine too, as long as it’s connected to the same access point that the iPhone is.

Find yours and make note of it for the next step.

Note: This must be an IP address that your iPhone can route to while connected via Wi-Fi. In most business and almost all residential networks, you won’t need to give this much thought. However, if you’re working within a more complex corporate network and can’t get your iPhone to connect to Fiddler’s proxy server, you may need help from a system administrator.

Configuring an iPhone to route through Fiddler

With your development machine’s IP address and Fiddler’s port number in hand, you’re ready to configure your iPhone to channel its network traffic through Fiddler’s proxy server.

To do that, open the settings app and tap the Wi-Fi option (below, left).

Navigating through the iPhone's settings

In the Wi-Fi Networks panel (above, right), you’ll see the wireless networks that your iPhone has detected in range. Tap the arrow at the right side of the Wi-Fi connection that you intend to use for testing.

Setting the iPhone's proxy settingsAt the very bottom of the panel that opens (left), find the HTTP Proxy setting and tap Manual (1) to enable the feature. In the fields that appear, enter your computer’s local IP address for the server (2), and the port that Fiddler is listening on for the… Port (3).

That’s it! Your iPhone is configured to route its traffic through an instance of Fiddler running on your development machine.

Starting the development server

Now that you have a conduit from your iPhone to the development server, it’s time to get the development server running by starting your site in Visual Studio. Anything that starts an instance of the development server will do (e.g. Start Without Debugging or View in Browser).

Make note of the URL displayed in your browser when Visual Studio displays your website. We’ll modify that slightly in the next step and use it to access the development server from Mobile Safari.

If the development server is already running, you can also determine its address by right-clicking its icon in the system tray and choosing “Show Details”. That will present you with a window that looks like this:

Finding the port and virtual root of your development server app

The “Root URL” address there is what you’ll need in the final step.

Accessing the development server from your device

Finally, we’re ready to start testing against the development server from the browser on a mobile device. The one minor issue remaining is that the exact URL advertised by the development server won’t work in this setup.

To make Fiddler happy, you need to append a trailing period to the hostname portion of the address. For instance, this “Root URL” advertised in the example above will not work without modification:

Wrong!

http://localhost:24833/WebSite1

To make it work, we simply need to append the trailing period to localhost:

http://localhost.:24833/WebSite1

That does look odd, but it works.

Fiddler also recognizes ipv4.fiddler as an alias for the localhost loopback, which is a little bit more intuitive. So, you could also access the same example with this address if you prefer:

http://ipv4.fiddler:24833/WebSite1

That’s it. You’re armed and ready to test with any external device on your local network now, so long as it supports routing its traffic through an HTTP proxy.

Conclusion

At first, this may seem like many steps and a lot of work. Don’t worry. Once you go through the motions a few times, you’ll find that it’s a breeze.

It’s especially smooth sailing in future repetitions, since your machine’s local IP probably won’t change often, and Fiddler’s proxy IP won’t change at all.

Of course, Fiddler isn’t the only utility that will work as an intermediary like this, but using Fiddler brings the great side-effect of providing HTTP traffic analysis while you’re testing. That added utility is welcome when you’re testing on a mobile device where the on-device development tools are basically nonexistent.

###

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



Using an iPhone with the Visual Studio development server

ASMX ScriptService mistake – Invalid JSON primitive

Monday, May 31st, 2010

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

Monday, March 8th, 2010

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

Wednesday, March 3rd, 2010

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