<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>zdima.net &#187; ASP.NET</title>
	<atom:link href="http://zdima.net/blog/archives/category/soft/dev/aspnet/feed" rel="self" type="application/rss+xml" />
	<link>http://zdima.net/blog</link>
	<description></description>
	<lastBuildDate>Mon, 30 Jan 2012 11:42:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Use ASP.NET’s HttpHandler to bridge the cross-domain gap</title>
		<link>http://zdima.net/blog/archives/16385</link>
		<comments>http://zdima.net/blog/archives/16385#comments</comments>
		<pubDate>Tue, 02 Aug 2011 14:59:25 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Contributors]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://www.zdima.net/blog/?guid=e32ab9baa8ad468282f750e1218ef94d</guid>
		<description><![CDATA[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 t...<p class="read-more"><a href="http://zdima.net/blog/archives/16385">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p>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.</p>
<p>Worse, if you encounter an API with no JSONP support, <strong>the cross-domain barrier can quickly become a formidable one</strong>. <a href="http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/">CORS</a> is slowly becoming a viable alternative, but it requires that the remote service support it via special HTTP headers and browser support for <a href="http://caniuse.com/#search=cors">CORS is still not ubiquitous</a>.</p>
<p>Until CORS is more broadly supported, an alternative solution is to bounce cross-domain requests through the web server that hosts your website. In <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a>, the best tool for implementing that sort of middleman endpoint is the <a href="http://msdn.microsoft.com/en-us/library/ms228090.aspx">HttpHandler</a>.</p>
<p>In this post, I’ll show you <strong>how to create an HttpHandler</strong> to service cross-domain requests, how to <strong>use jQuery to communicate with the handler</strong>, and <strong>an example of one improvement</strong> that this approach makes possible.</p>
<h3>An example remote API</h3>
<p>To focus on an example that’s already familiar to many, I’m going to use Twitter. Twitter’s API <em>does</em> 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.</p>
<p>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.</p>
<p>Specifically, I’m interested in querying the service for my last few status updates. The Twitter API request to accomplish that looks like this:</p>
<div>
<div>
<pre style="font-family:monospace"><a href="http://api.twitter.com/1/statuses/user_timeline.json?id=Encosia" class="autohyperlink" title="http://api.twitter.com/1/statuses/user_timeline.json?id=Encosia" target="_blank" rel="nofollow">api.twitter.com/1/statuses/user_timeline.json?id=Encosia</a></pre>
</div>
</div>
<p>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.</p>
<h3>The best tool for the job: HttpHandler</h3>
<p>If you’re accustomed to using <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a>’s <a href="http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/">page methods</a> and <a href="http://encosia.com/using-jquery-to-consume-aspnet-json-web-services/">ScriptServices</a> 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.</p>
<p>Rather, a lower-level tool is more appropriate in this case.</p>
<p><a href="http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.processrequest.aspx" rel="nofollow">HttpHandlers</a> are one of <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a>’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.</p>
<p>One place in particular where HttpHandlers shine is where you would otherwise consider writing <code>Response.Write</code> statements in a WebForms page’s code-behind. This anti-pattern of using ASPX’s code-behind to get closer to the metal <em>looks</em> similar to approaches that you’ll see on some other platforms, such as PHP, but is not equivalent.</p>
<p>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 <a href="http://msdn.microsoft.com/en-us/library/ms178472.aspx#lifecycle_events" rel="nofollow">all the way from PreInit to Unload</a>, adding needless overhead.</p>
<p>Instead, the HttpHandler is where you should write that sort of code that ultimately boils down to <code>Response.Write</code> calls.</p>
<h3>Choosing the right handler type</h3>
<p>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”:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2011/07/add-httphandler-dialog.png" rel="attachment"><img src="http://encosia.com/blog/wp-content/uploads/2011/07/add-httphandler-dialog.png" alt="The add item dialog presents two choices of HttpHandler templates" title="Add HttpHandler dialog" width="492" height="330"></a></p>
<p>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.</p>
<p>In the spirit of keeping things simple, let’s stick with the more traditionally file-based “Generic Handler”.</p>
<h3>Getting started with your first HttpHandler</h3>
<p>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:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;text/plain&quot;</span><span style="color:#008000">;</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span><span style="color:#666666">&quot;Hello World&quot;</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>If you start the site up in Visual Studio and then request your newly-created HttpHandler in a browser, <code>Handler1.ashx</code> if you accept the default name, you will see “Hello World” as you might expect.</p>
<p>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 <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<h3>Bouncing a request to Twitter through the HttpHandler</h3>
<p>To adapt an HttpHandler for relaying requests to the Twitter API, we can use <a href="http://msdn.microsoft.com/en-us/library/system.net.webclient.aspx" rel="nofollow">.NET’s handy WebClient class</a> to make the request to Twitter’s API, and then return the result back through as the handler’s response:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  WebClient twitter <span style="color:#008000">=</span> <span style="color:#008000">new</span> WebClient<span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// The base URL for Twitter API requests.</span>
  <span style="color:#ff0000">string</span> baseUrl <span style="color:#008000">=</span> <span style="color:#666666">&quot;http://api.twitter.com/1/&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// The specific API call that we're interested in.</span>
  <span style="color:#ff0000">string</span> request <span style="color:#008000">=</span> <span style="color:#666666">&quot;statuses/user_timeline.json?id=Encosia&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Make a request to the API and capture its result.</span>
  <span style="color:#ff0000">string</span> response <span style="color:#008000">=</span> twitter.<span style="color:#0000ff">DownloadString</span><span style="color:#000000">(</span>baseUrl <span style="color:#008000">+</span> request<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Set the content-type so that libraries like jQuery can </span>
  <span style="color:#008080;font-style:italic">//  automatically parse the result.</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;application/json&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Relay the API response back down to the client.</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>response<span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>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.</p>
<h4>Using the handler proxy on the client-side</h4>
<p>With our web server doing the heavy lifting, using this server-side proxy to make a remote request is trivial:</p>
<div>
<div>
<pre style="font-family:monospace">$.<span style="color:#660066">getJSON</span><span style="color:#009900">(</span><span style="color:#3366cc">'TwitterProxy.ashx'</span><span style="color:#339933">,</span> <span style="color:#003366;font-weight:bold">function</span><span style="color:#009900">(</span>tweets<span style="color:#009900">)</span> <span style="color:#009900">{</span>
  <span style="color:#006600;font-style:italic">// Call a magical function that does all the presentational work.</span>
  displayTweets<span style="color:#009900">(</span>tweets<span style="color:#009900">)</span><span style="color:#339933">;</span>
<span style="color:#009900">}</span><span style="color:#009900">)</span><span style="color:#339933">;</span></pre>
</div>
</div>
<p>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, <strong>it’s all the same to the jQuery code on the client-side</strong>.</p>
<p>As you’ll see when we add caching, this can easily be exploited for good.</p>
<h3>Mixing things up with QueryString parameters</h3>
<p>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 <a href="https://twitter.com/encosia">that boring Encosia character</a>?</p>
<p>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 <code>id</code> parameter on the QueryString:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  WebClient twitter <span style="color:#008000">=</span> <span style="color:#008000">new</span> WebClient<span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#ff0000">string</span> baseUrl <span style="color:#008000">=</span> <span style="color:#666666">&quot;http://api.twitter.com/1/&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Extract the desired account ID from the QueryString.</span>
  <span style="color:#ff0000">string</span> id <span style="color:#008000">=</span> context.<span style="color:#0000ff">Request</span>.<span style="color:#0000ff">QueryString</span><span style="color:#000000">[</span><span style="color:#666666">&quot;id&quot;</span><span style="color:#000000">]</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Make a request to the API for the specified id.</span>
  <span style="color:#ff0000">string</span> request <span style="color:#008000">=</span> <span style="color:#666666">&quot;statuses/user_timeline.json?id=&quot;</span> <span style="color:#008000">+</span> id<span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Same as before, from here on out:</span>
  <span style="color:#ff0000">string</span> response <span style="color:#008000">=</span> twitter.<span style="color:#0000ff">DownloadString</span><span style="color:#000000">(</span>baseUrl <span style="color:#008000">+</span> request<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;application/json&quot;</span><span style="color:#008000">;</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>response<span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>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 <a href="http://weblogs.asp.net/scottgu/">Scott Guthrie</a>‘s latest tweets:</p>
<div>
<div>
<pre style="font-family:monospace">TwitterProxy.ashx?id=ScottGu</pre>
</div>
</div>
<h4>Supplying parameters with $.getJSON</h4>
<p>To pass this new parameter in from the client-side, you could handcraft the entire URL including the appropriate QueryString. Even better though, <code>$.getJSON</code> has <a href="http://api.jquery.com/jQuery.getJSON/">an optional “data” argument</a> that accepts a JavaScript object and converts it to QueryString parameters:</p>
<div>
<div>
<pre style="font-family:monospace">$.<span style="color:#660066">getJSON</span><span style="color:#009900">(</span><span style="color:#3366cc">'TwitterProxy.ashx'</span><span style="color:#339933">,</span> <span style="color:#009900">{</span> id<span style="color:#339933">:</span> <span style="color:#3366cc">'ScottGu'</span> <span style="color:#009900">}</span><span style="color:#339933">,</span> <span style="color:#003366;font-weight:bold">function</span><span style="color:#009900">(</span>tweets<span style="color:#009900">)</span> <span style="color:#009900">{</span>
  displayTweets<span style="color:#009900">(</span>tweets<span style="color:#009900">)</span><span style="color:#339933">;</span>
<span style="color:#009900">}</span><span style="color:#009900">)</span><span style="color:#339933">;</span></pre>
</div>
</div>
<p>jQuery will automatically URLEncode the parameters you specify in the “data” argument and properly assemble them into the final URL to be requested:</p>
<p><img src="http://encosia.com/blog/wp-content/uploads/2011/08/request-in-firebug.png" alt="Screenshot of the HttpHandler request generated by the jQuery code above." title="HttpHandler request in Firebug" width="490" height="145" style="border:1px solid #333"></p>
<p>Which is exactly what we need it to do.</p>
<p>Using a configuration object like this is cleaner than manually concatenating a string together and makes it easier to vary the parameter at runtime.</p>
<h3>Improving performance with server-side caching</h3>
<p>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. <strong>A great way to take advantage of that is adding a server-side caching layer</strong>. </p>
<p>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.</p>
<p>Let’s say that we wanted to cache Twitter responses for up to five minutes, for example:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  <span style="color:#008080;font-style:italic">// This will be the case whether there's a cache hit or not.</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;application/json&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Check to see if the twitter status is already cached,</span>
  <span style="color:#008080;font-style:italic">//   then retrieve and return the cached value if so.</span>
  <span style="color:#008080;font-style:italic">// 8/3/11: Updated with more robust test, thanks to ctolkien.</span>
  <span style="color:#ff0000">object</span> tweetsCache <span style="color:#008000">=</span> context.<span style="color:#0000ff">Cache</span><span style="color:#000000">[</span><span style="color:#666666">&quot;tweets-&quot;</span> <span style="color:#008000">+</span> id<span style="color:#000000">]</span><span style="color:#008000">;</span>
 
  <span style="color:#0600ff">if</span> <span style="color:#000000">(</span>tweetsCache <span style="color:#008000">!=</span> <span style="color:#0600ff">null</span><span style="color:#000000">)</span> <span style="color:#000000">{</span>
    <span style="color:#ff0000">string</span> cachedTweets <span style="color:#008000">=</span> tweetsCache.<span style="color:#0000ff">ToString</span><span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
    context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>cachedTweets<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
    <span style="color:#008080;font-style:italic">// We're done here.</span>
    return<span style="color:#008000">;</span>
  <span style="color:#000000">}</span>
 
  WebClient twitter <span style="color:#008000">=</span> <span style="color:#008000">new</span> WebClient<span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Move along; nothing to see here. The concatenation is just</span>
  <span style="color:#008080;font-style:italic">//  to avoid horizontal scrolling within the meager 492</span>
  <span style="color:#008080;font-style:italic">//  pixels I have to work with here.</span>
  <span style="color:#ff0000">string</span> url <span style="color:#008000">=</span> <span style="color:#666666">&quot;http://api.twitter.com/1/statuses/&quot;</span> <span style="color:#008000">+</span>
               <span style="color:#666666">&quot;user_timeline.json?id=Encosia&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#ff0000">string</span> tweets <span style="color:#008000">=</span> twitter.<span style="color:#0000ff">DownloadString</span><span style="color:#000000">(</span>url<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// This monstrosity essentially just caches the WebClient result</span>
  <span style="color:#008080;font-style:italic">//  with a maximum lifetime of 5 minutes from now.</span>
  <span style="color:#008080;font-style:italic">// If you don't care about the expiration, this can be a simple</span>
  <span style="color:#008080;font-style:italic">//  context.Cache[&quot;tweets&quot;] = tweets; instead.</span>
  context.<span style="color:#0000ff">Cache</span>.<span style="color:#0000ff">Add</span><span style="color:#000000">(</span><span style="color:#666666">&quot;tweets&quot;</span>, tweets,
    <span style="color:#0600ff">null</span>, DateTime.<span style="color:#0000ff">Now</span>.<span style="color:#0000ff">AddMinutes</span><span style="color:#000000">(</span><span style="color:#ff0000">5</span><span style="color:#000000">)</span>,
    <span style="color:#000000">System.<span style="color:#0000ff">Web</span>.<span style="color:#0000ff">Caching</span></span>.<span style="color:#0000ff">Cache</span>.<span style="color:#0000ff">NoSlidingExpiration</span>,
    <span style="color:#000000">System.<span style="color:#0000ff">Web</span>.<span style="color:#0000ff">Caching</span></span>.<span style="color:#0000ff">CacheItemPriority</span>.<span style="color:#0000ff">Normal</span>,
    <span style="color:#0600ff">null</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>tweets<span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>Adding the intermediate cache results in a tremendous performance improvement after the first request:</p>
<p><img src="http://encosia.com/blog/wp-content/uploads/2011/08/cached-twitter-requests.png" style="border:1px solid #333" width="490" height="134" alt="Screenshot of an initial uncached request to Twitter and then the subsequent, cached requests"></p>
<p>With the server able to immediately serve requests within the five minute caching window, subsequent $.getJSON requests are an order of magnitude faster!</p>
<p>Perhaps even more importantly in the case of Twitter, these four refreshes only counted as one API call against my hourly rate-limit.</p>
<h3>Conclusion</h3>
<p>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.</p>
<p>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:</p>
<ul>
<li><strong>Error handling</strong> – 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.</li>
<li><strong>Caching</strong> – 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).</li>
<li><strong>Security</strong> – 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.</li>
<li><strong>Reliability</strong> – 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.</li>
</ul>
<p>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.</p>
<p>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.</p>
<h3>Get the source</h3>
<p>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.</p>
<p><a href="https://github.com/Encosia/Encosia-Samples-HttpHandler-Proxy/tree/AsPublished" style="width:220px;float:left;text-align:center">HttpHandler-Proxy on GitHub</a><a href="https://github.com/Encosia/Encosia-Samples-HttpHandler-Proxy/zipball/AsPublished" style="width:220px;float:right;text-align:center">HttpHandler-Proxy.zip</a></p>
<p>Related posts:
<ol>
<li><a href="http://encosia.com/save-yourself-some-typing-when-you-call-asp-net-services/" rel="bookmark" title="Save yourself some typing when you call ASP.NET services">Save yourself some typing when you call ASP.NET services</a></li>
<li><a href="http://encosia.com/3-mistakes-to-avoid-when-using-jquery-with-aspnet-ajax/" rel="bookmark" title="3 mistakes to avoid when using jQuery with ASP.NET AJAX">3 mistakes to avoid when using jQuery with ASP.NET AJAX</a></li>
<li><a href="http://encosia.com/jquery-1-5s-ajax-rewrite-and-asp-net-services-all-is-well/" rel="bookmark" title="jQuery 1.5?s AJAX rewrite and ASP.NET services: All is well">jQuery 1.5?s AJAX rewrite and ASP.NET services: All is well</a></li>
</ol>
<hr />
<p>You&#8217;ve been reading <a href="http://encosia.com/use-asp-nets-httphandler-to-bridge-the-cross-domain-gap/">Use ASP.NET’s HttpHandler to bridge the cross-domain gap</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>
<p>If you&#8217;ve got any feedback, please click through and leave a comment; I&#8217;d love to hear from you. You can <a href="http://encosia.com/use-asp-nets-httphandler-to-bridge-the-cross-domain-gap/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p>
<div>
<a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=YdLACsHJ79k:R7CRoXbOZxk:D7DqB2pKExk" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=YdLACsHJ79k:R7CRoXbOZxk:F7zBnMyn0Lo" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=YdLACsHJ79k:R7CRoXbOZxk:gIN9vFwOqvQ" border="0"></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/Encosia/~4/YdLACsHJ79k" height="1" width="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/16385/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use ASP.NET’s HttpHandler to bridge the cross-domain gap</title>
		<link>http://zdima.net/blog/archives/16723</link>
		<comments>http://zdima.net/blog/archives/16723#comments</comments>
		<pubDate>Tue, 02 Aug 2011 14:59:25 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?guid=e32ab9baa8ad468282f750e1218ef94d</guid>
		<description><![CDATA[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 t...<p class="read-more"><a href="http://zdima.net/blog/archives/16723">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p>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.</p>
<p>Worse, if you encounter an API with no JSONP support, <strong>the cross-domain barrier can quickly become a formidable one</strong>. <a href="http://hacks.mozilla.org/2009/07/cross-site-xmlhttprequest-with-cors/">CORS</a> is slowly becoming a viable alternative, but it requires that the remote service support it via special HTTP headers and browser support for <a href="http://caniuse.com/#search=cors">CORS is still not ubiquitous</a>.</p>
<p>Until CORS is more broadly supported, an alternative solution is to bounce cross-domain requests through the web server that hosts your website. In <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a>, the best tool for implementing that sort of middleman endpoint is the <a href="http://msdn.microsoft.com/en-us/library/ms228090.aspx">HttpHandler</a>.</p>
<p>In this post, I’ll show you <strong>how to create an HttpHandler</strong> to service cross-domain requests, how to <strong>use jQuery to communicate with the handler</strong>, and <strong>an example of one improvement</strong> that this approach makes possible.</p>
<h3>An example remote API</h3>
<p>To focus on an example that’s already familiar to many, I’m going to use Twitter. Twitter’s API <em>does</em> 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.</p>
<p>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.</p>
<p>Specifically, I’m interested in querying the service for my last few status updates. The Twitter API request to accomplish that looks like this:</p>
<div>
<div>
<pre style="font-family:monospace"><a href="http://api.twitter.com/1/statuses/user_timeline.json?id=Encosia" class="autohyperlink" title="http://api.twitter.com/1/statuses/user_timeline.json?id=Encosia" target="_blank" rel="nofollow">api.twitter.com/1/statuses/user_timeline.json?id=Encosia</a></pre>
</div>
</div>
<p>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.</p>
<h3>The best tool for the job: HttpHandler</h3>
<p>If you’re accustomed to using <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a>’s <a href="http://encosia.com/using-jquery-to-directly-call-aspnet-ajax-page-methods/">page methods</a> and <a href="http://encosia.com/using-jquery-to-consume-aspnet-json-web-services/">ScriptServices</a> 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.</p>
<p>Rather, a lower-level tool is more appropriate in this case.</p>
<p><a href="http://msdn.microsoft.com/en-us/library/system.web.ihttphandler.processrequest.aspx" rel="nofollow">HttpHandlers</a> are one of <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a>’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.</p>
<p>One place in particular where HttpHandlers shine is where you would otherwise consider writing <code>Response.Write</code> statements in a WebForms page’s code-behind. This anti-pattern of using ASPX’s code-behind to get closer to the metal <em>looks</em> similar to approaches that you’ll see on some other platforms, such as PHP, but is not equivalent.</p>
<p>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 <a href="http://msdn.microsoft.com/en-us/library/ms178472.aspx#lifecycle_events" rel="nofollow">all the way from PreInit to Unload</a>, adding needless overhead.</p>
<p>Instead, the HttpHandler is where you should write that sort of code that ultimately boils down to <code>Response.Write</code> calls.</p>
<h3>Choosing the right handler type</h3>
<p>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”:</p>
<p><a href="http://encosia.com/blog/wp-content/uploads/2011/07/add-httphandler-dialog.png" rel="attachment"><img src="http://encosia.com/blog/wp-content/uploads/2011/07/add-httphandler-dialog.png" alt="The add item dialog presents two choices of HttpHandler templates" title="Add HttpHandler dialog" width="492" height="330"></a></p>
<p>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.</p>
<p>In the spirit of keeping things simple, let’s stick with the more traditionally file-based “Generic Handler”.</p>
<h3>Getting started with your first HttpHandler</h3>
<p>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:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;text/plain&quot;</span><span style="color:#008000">;</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span><span style="color:#666666">&quot;Hello World&quot;</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>If you start the site up in Visual Studio and then request your newly-created HttpHandler in a browser, <code>Handler1.ashx</code> if you accept the default name, you will see “Hello World” as you might expect.</p>
<p>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 <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<h3>Bouncing a request to Twitter through the HttpHandler</h3>
<p>To adapt an HttpHandler for relaying requests to the Twitter API, we can use <a href="http://msdn.microsoft.com/en-us/library/system.net.webclient.aspx" rel="nofollow">.NET’s handy WebClient class</a> to make the request to Twitter’s API, and then return the result back through as the handler’s response:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  WebClient twitter <span style="color:#008000">=</span> <span style="color:#008000">new</span> WebClient<span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// The base URL for Twitter API requests.</span>
  <span style="color:#ff0000">string</span> baseUrl <span style="color:#008000">=</span> <span style="color:#666666">&quot;http://api.twitter.com/1/&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// The specific API call that we're interested in.</span>
  <span style="color:#ff0000">string</span> request <span style="color:#008000">=</span> <span style="color:#666666">&quot;statuses/user_timeline.json?id=Encosia&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Make a request to the API and capture its result.</span>
  <span style="color:#ff0000">string</span> response <span style="color:#008000">=</span> twitter.<span style="color:#0000ff">DownloadString</span><span style="color:#000000">(</span>baseUrl <span style="color:#008000">+</span> request<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Set the content-type so that libraries like jQuery can </span>
  <span style="color:#008080;font-style:italic">//  automatically parse the result.</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;application/json&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Relay the API response back down to the client.</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>response<span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>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.</p>
<h4>Using the handler proxy on the client-side</h4>
<p>With our web server doing the heavy lifting, using this server-side proxy to make a remote request is trivial:</p>
<div>
<div>
<pre style="font-family:monospace">$.<span style="color:#660066">getJSON</span><span style="color:#009900">(</span><span style="color:#3366cc">'TwitterProxy.ashx'</span><span style="color:#339933">,</span> <span style="color:#003366;font-weight:bold">function</span><span style="color:#009900">(</span>tweets<span style="color:#009900">)</span> <span style="color:#009900">{</span>
  <span style="color:#006600;font-style:italic">// Call a magical function that does all the presentational work.</span>
  displayTweets<span style="color:#009900">(</span>tweets<span style="color:#009900">)</span><span style="color:#339933">;</span>
<span style="color:#009900">}</span><span style="color:#009900">)</span><span style="color:#339933">;</span></pre>
</div>
</div>
<p>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, <strong>it’s all the same to the jQuery code on the client-side</strong>.</p>
<p>As you’ll see when we add caching, this can easily be exploited for good.</p>
<h3>Mixing things up with QueryString parameters</h3>
<p>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 <a href="https://twitter.com/encosia">that boring Encosia character</a>?</p>
<p>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 <code>id</code> parameter on the QueryString:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  WebClient twitter <span style="color:#008000">=</span> <span style="color:#008000">new</span> WebClient<span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#ff0000">string</span> baseUrl <span style="color:#008000">=</span> <span style="color:#666666">&quot;http://api.twitter.com/1/&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Extract the desired account ID from the QueryString.</span>
  <span style="color:#ff0000">string</span> id <span style="color:#008000">=</span> context.<span style="color:#0000ff">Request</span>.<span style="color:#0000ff">QueryString</span><span style="color:#000000">[</span><span style="color:#666666">&quot;id&quot;</span><span style="color:#000000">]</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Make a request to the API for the specified id.</span>
  <span style="color:#ff0000">string</span> request <span style="color:#008000">=</span> <span style="color:#666666">&quot;statuses/user_timeline.json?id=&quot;</span> <span style="color:#008000">+</span> id<span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Same as before, from here on out:</span>
  <span style="color:#ff0000">string</span> response <span style="color:#008000">=</span> twitter.<span style="color:#0000ff">DownloadString</span><span style="color:#000000">(</span>baseUrl <span style="color:#008000">+</span> request<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;application/json&quot;</span><span style="color:#008000">;</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>response<span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>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 <a href="http://weblogs.asp.net/scottgu/">Scott Guthrie</a>‘s latest tweets:</p>
<div>
<div>
<pre style="font-family:monospace">TwitterProxy.ashx?id=ScottGu</pre>
</div>
</div>
<h4>Supplying parameters with $.getJSON</h4>
<p>To pass this new parameter in from the client-side, you could handcraft the entire URL including the appropriate QueryString. Even better though, <code>$.getJSON</code> has <a href="http://api.jquery.com/jQuery.getJSON/">an optional “data” argument</a> that accepts a JavaScript object and converts it to QueryString parameters:</p>
<div>
<div>
<pre style="font-family:monospace">$.<span style="color:#660066">getJSON</span><span style="color:#009900">(</span><span style="color:#3366cc">'TwitterProxy.ashx'</span><span style="color:#339933">,</span> <span style="color:#009900">{</span> id<span style="color:#339933">:</span> <span style="color:#3366cc">'ScottGu'</span> <span style="color:#009900">}</span><span style="color:#339933">,</span> <span style="color:#003366;font-weight:bold">function</span><span style="color:#009900">(</span>tweets<span style="color:#009900">)</span> <span style="color:#009900">{</span>
  displayTweets<span style="color:#009900">(</span>tweets<span style="color:#009900">)</span><span style="color:#339933">;</span>
<span style="color:#009900">}</span><span style="color:#009900">)</span><span style="color:#339933">;</span></pre>
</div>
</div>
<p>jQuery will automatically URLEncode the parameters you specify in the “data” argument and properly assemble them into the final URL to be requested:</p>
<p><img src="http://encosia.com/blog/wp-content/uploads/2011/08/request-in-firebug.png" alt="Screenshot of the HttpHandler request generated by the jQuery code above." title="HttpHandler request in Firebug" width="490" height="145" style="border:1px solid #333"></p>
<p>Which is exactly what we need it to do.</p>
<p>Using a configuration object like this is cleaner than manually concatenating a string together and makes it easier to vary the parameter at runtime.</p>
<h3>Improving performance with server-side caching</h3>
<p>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. <strong>A great way to take advantage of that is adding a server-side caching layer</strong>. </p>
<p>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.</p>
<p>Let’s say that we wanted to cache Twitter responses for up to five minutes, for example:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#0600ff">public</span> <span style="color:#0600ff">void</span> ProcessRequest<span style="color:#000000">(</span>HttpContext context<span style="color:#000000">)</span> <span style="color:#000000">{</span>
  <span style="color:#008080;font-style:italic">// This will be the case whether there's a cache hit or not.</span>
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">ContentType</span> <span style="color:#008000">=</span> <span style="color:#666666">&quot;application/json&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Check to see if the twitter status is already cached,</span>
  <span style="color:#008080;font-style:italic">//   then retrieve and return the cached value if so.</span>
  <span style="color:#008080;font-style:italic">// 8/3/11: Updated with more robust test, thanks to ctolkien.</span>
  <span style="color:#ff0000">object</span> tweetsCache <span style="color:#008000">=</span> context.<span style="color:#0000ff">Cache</span><span style="color:#000000">[</span><span style="color:#666666">&quot;tweets-&quot;</span> <span style="color:#008000">+</span> id<span style="color:#000000">]</span><span style="color:#008000">;</span>
 
  <span style="color:#0600ff">if</span> <span style="color:#000000">(</span>tweetsCache <span style="color:#008000">!=</span> <span style="color:#0600ff">null</span><span style="color:#000000">)</span> <span style="color:#000000">{</span>
    <span style="color:#ff0000">string</span> cachedTweets <span style="color:#008000">=</span> tweetsCache.<span style="color:#0000ff">ToString</span><span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
    context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>cachedTweets<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
    <span style="color:#008080;font-style:italic">// We're done here.</span>
    return<span style="color:#008000">;</span>
  <span style="color:#000000">}</span>
 
  WebClient twitter <span style="color:#008000">=</span> <span style="color:#008000">new</span> WebClient<span style="color:#000000">(</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// Move along; nothing to see here. The concatenation is just</span>
  <span style="color:#008080;font-style:italic">//  to avoid horizontal scrolling within the meager 492</span>
  <span style="color:#008080;font-style:italic">//  pixels I have to work with here.</span>
  <span style="color:#ff0000">string</span> url <span style="color:#008000">=</span> <span style="color:#666666">&quot;http://api.twitter.com/1/statuses/&quot;</span> <span style="color:#008000">+</span>
               <span style="color:#666666">&quot;user_timeline.json?id=Encosia&quot;</span><span style="color:#008000">;</span>
 
  <span style="color:#ff0000">string</span> tweets <span style="color:#008000">=</span> twitter.<span style="color:#0000ff">DownloadString</span><span style="color:#000000">(</span>url<span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  <span style="color:#008080;font-style:italic">// This monstrosity essentially just caches the WebClient result</span>
  <span style="color:#008080;font-style:italic">//  with a maximum lifetime of 5 minutes from now.</span>
  <span style="color:#008080;font-style:italic">// If you don't care about the expiration, this can be a simple</span>
  <span style="color:#008080;font-style:italic">//  context.Cache[&quot;tweets&quot;] = tweets; instead.</span>
  context.<span style="color:#0000ff">Cache</span>.<span style="color:#0000ff">Add</span><span style="color:#000000">(</span><span style="color:#666666">&quot;tweets&quot;</span>, tweets,
    <span style="color:#0600ff">null</span>, DateTime.<span style="color:#0000ff">Now</span>.<span style="color:#0000ff">AddMinutes</span><span style="color:#000000">(</span><span style="color:#ff0000">5</span><span style="color:#000000">)</span>,
    <span style="color:#000000">System.<span style="color:#0000ff">Web</span>.<span style="color:#0000ff">Caching</span></span>.<span style="color:#0000ff">Cache</span>.<span style="color:#0000ff">NoSlidingExpiration</span>,
    <span style="color:#000000">System.<span style="color:#0000ff">Web</span>.<span style="color:#0000ff">Caching</span></span>.<span style="color:#0000ff">CacheItemPriority</span>.<span style="color:#0000ff">Normal</span>,
    <span style="color:#0600ff">null</span><span style="color:#000000">)</span><span style="color:#008000">;</span>
 
  context.<span style="color:#0000ff">Response</span>.<span style="color:#0000ff">Write</span><span style="color:#000000">(</span>tweets<span style="color:#000000">)</span><span style="color:#008000">;</span>
<span style="color:#000000">}</span></pre>
</div>
</div>
<p>Adding the intermediate cache results in a tremendous performance improvement after the first request:</p>
<p><img src="http://encosia.com/blog/wp-content/uploads/2011/08/cached-twitter-requests.png" style="border:1px solid #333" width="490" height="134" alt="Screenshot of an initial uncached request to Twitter and then the subsequent, cached requests"></p>
<p>With the server able to immediately serve requests within the five minute caching window, subsequent $.getJSON requests are an order of magnitude faster!</p>
<p>Perhaps even more importantly in the case of Twitter, these four refreshes only counted as one API call against my hourly rate-limit.</p>
<h3>Conclusion</h3>
<p>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.</p>
<p>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:</p>
<ul>
<li><strong>Error handling</strong> – 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.</li>
<li><strong>Caching</strong> – 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).</li>
<li><strong>Security</strong> – 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.</li>
<li><strong>Reliability</strong> – 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.</li>
</ul>
<p>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.</p>
<p>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.</p>
<h3>Get the source</h3>
<p>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.</p>
<p><a href="https://github.com/Encosia/Encosia-Samples-HttpHandler-Proxy/tree/AsPublished" style="width:220px;float:left;text-align:center">HttpHandler-Proxy on GitHub</a><a href="https://github.com/Encosia/Encosia-Samples-HttpHandler-Proxy/zipball/AsPublished" style="width:220px;float:right;text-align:center">HttpHandler-Proxy.zip</a></p>
<p>Related posts:
<ol>
<li><a href="http://encosia.com/ajax-file-downloads-and-iframes/" rel="bookmark" title="AJAX, file downloads, and IFRAMEs">AJAX, file downloads, and IFRAMEs</a></li>
<li><a href="http://encosia.com/the-easiest-way-to-break-aspnet-ajax-pages/" rel="bookmark" title="The easiest way to break ASP.NET AJAX pages">The easiest way to break ASP.NET AJAX pages</a></li>
<li><a href="http://encosia.com/why-aspnet-ajax-updatepanels-are-dangerous/" rel="bookmark" title="Why ASP.NET AJAX UpdatePanels are dangerous">Why ASP.NET AJAX UpdatePanels are dangerous</a></li>
</ol>
<hr />
<p>You&#8217;ve been reading <a href="http://encosia.com/use-asp-nets-httphandler-to-bridge-the-cross-domain-gap/">Use ASP.NET’s HttpHandler to bridge the cross-domain gap</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>
<p>If you&#8217;ve got any feedback, please click through and leave a comment; I&#8217;d love to hear from you. You can <a href="http://encosia.com/use-asp-nets-httphandler-to-bridge-the-cross-domain-gap/#post-commentblock">click here to jump directly to the comment section of this post</a>.</p>
<hr />
<p>You&#8217;ve been reading <a href="http://encosia.com/use-asp-nets-httphandler-to-bridge-the-cross-domain-gap/">Use ASP.NET’s HttpHandler to bridge the cross-domain gap</a>, originally posted at <a href="http://encosia.com">Encosia</a>.  I hope you enjoyed it, and thanks for reading.</p>
</p>
<div>
<a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=YdLACsHJ79k:R7CRoXbOZxk:D7DqB2pKExk" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=YdLACsHJ79k:R7CRoXbOZxk:F7zBnMyn0Lo" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=YdLACsHJ79k:R7CRoXbOZxk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=YdLACsHJ79k:R7CRoXbOZxk:gIN9vFwOqvQ" border="0"></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/Encosia/~4/YdLACsHJ79k" height="1" width="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/16723/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Prepare web.config for HTML5 and CSS3</title>
		<link>http://zdima.net/blog/archives/15590</link>
		<comments>http://zdima.net/blog/archives/15590#comments</comments>
		<pubDate>Thu, 02 Dec 2010 03:38:16 +0000</pubDate>
		<dc:creator>Mads Kristensen</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Contributors]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15590</guid>
		<description><![CDATA[HTML5 and CSS3 introduces some new file types that enables us to create even better websites. We are now able to embed video, audio and custom fonts natively to any web page. Some of these file types are relatively new and not supported by the IIS web ...<p class="read-more"><a href="http://zdima.net/blog/archives/15590">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p>HTML5 and CSS3 introduces some new file types that enables us to create even better websites. We are now able to embed video, audio and custom fonts natively to any web page. Some of these file types are relatively new and not supported by the IIS web server by default. It’s file types like .m4v, .webm and .woff.</p>
<p>When a request is made to the IIS for these unsupported file types, we are met with the following error message:</p>
<p><strong>HTTP Error 404.3 &#8211; Not Found</strong></p>
<p><strong>The page you are requesting cannot be served because of the extension configuration. If the page is a script, add a handler. If the file should be downloaded, add a MIME map.</strong></p>
<p>The problem is that the IIS doesn’t know how to serve these new files unless we tell it how. This can be easily done in the web.config’s &lt;system.webServer&gt; section by adding the following snippet:</p>
<pre><span>&lt;</span><span>staticContent</span><span>&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.mp4&quot;</span> <span>mimeType</span><span>=&quot;video/mp4&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.m4v&quot;</span> <span>mimeType</span><span>=&quot;video/m4v&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.ogg&quot;</span> <span>mimeType</span><span>=&quot;video/ogg&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.ogv&quot;</span> <span>mimeType</span><span>=&quot;video/ogg&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.webm&quot;</span> <span>mimeType</span><span>=&quot;video/webm&quot;</span> <span>/&gt;</span>

    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.oga&quot;</span> <span>mimeType</span><span>=&quot;audio/ogg&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.spx&quot;</span> <span>mimeType</span><span>=&quot;audio/ogg&quot;</span> <span>/&gt;</span>

    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.svg&quot;</span> <span>mimeType</span><span>=&quot;images/svg+xml&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.svgz&quot;</span> <span>mimeType</span><span>=&quot;images/svg+xml&quot;</span> <span>/&gt;</span>

    <span>&lt;</span><span>remove</span> <span>fileExtension</span><span>=&quot;.eot&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.eot&quot;</span> <span>mimeType</span><span>=&quot;application/vnd.ms-fontobject&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.otf&quot;</span> <span>mimeType</span><span>=&quot;font/otf&quot;</span> <span>/&gt;</span>
    <span>&lt;</span><span>mimeMap</span> <span>fileExtension</span><span>=&quot;.woff&quot;</span> <span>mimeType</span><span>=&quot;font/x-woff&quot;</span> <span>/&gt;</span>
<span>&lt;/</span><span>staticContent</span><span>&gt;</span></pre>
<p>The above snippet includes support for most video, audio and font file types used by HTML5 and CSS3. </p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15590/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Performance tuning tricks for ASP.NET and IIS 7 – part 2</title>
		<link>http://zdima.net/blog/archives/15313</link>
		<comments>http://zdima.net/blog/archives/15313#comments</comments>
		<pubDate>Sun, 15 Aug 2010 18:28:00 +0000</pubDate>
		<dc:creator>Mads Kristensen</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Contributors]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15313</guid>
		<description><![CDATA[In part 1 of this series, we looked at some tricks to optimize the performance of any website running in IIS 7 by only modifying the web.config. In this part we will focus on handling browser caching issues and optimize the number of JavaScript and CSS...<p class="read-more"><a href="http://zdima.net/blog/archives/15313">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p>In <a href="http://madskristensen.net/post/Performance-tuning-tricks-for-ASPNET-and-IIS-7-part-1.aspx">part 1 of this series</a>, we looked at some tricks to optimize the performance of any website running in IIS 7 by only modifying the web.config. In this part we will focus on handling browser caching issues and optimize the number of JavaScript and CSS files loaded from an <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> website.</p>
<p><strong>NB!</strong> All the code (a single .cs file of 125 lines) is included in the zip file at the bottom of this post.</p>
<h2>Browser caching</h2>
<p>In part 1, we looked at how it was possible to set an expiration header to any static file such as JavaScript and CSS files, so the browser would cache them for a long time and thereby optimize both for bandwidth and the number of requested files going from server to browser.</p>
<p>The problem with setting a browser cache expiration date of i.e. a JavaScript file to a year in the future becomes clear when you change the file before it expires in your visitor’s browsers. They simply won’t see the changes until they either clear their cache or hits F5 manually.</p>
<h3>Adding the version number</h3>
<p>The only viable way to maintain a far-in-the-future expiration date is to change the URL of the file when the file changes. So instead of including script files like so:</p>
<p>&lt;script type=&quot;text/javascript&quot; src=”/scripts/global.js&quot;&gt;&lt;/script&gt;</p>
<p>…we really want to get a version number included in the <em>src</em> attribute, like so:</p>
<p>&lt;script type=&quot;text/javascript&quot; src=/scripts/<strong>v_634174870689341736</strong>/global.js&quot;&gt;&lt;/script&gt;</p>
<p>The problem with this is that <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> doesn’t have any feature that will inject a version number, so we have to create that our selves. It is very simple to do so by looking at when the file was last changed and then retrieve the ticks from that date. In the zip file below you’ll find a method that does exactly that and it can be used like so:</p>
<p>&lt;script type=&quot;text/javascript&quot; src=&quot;&lt;%=BundleHelper.InsertFile(&quot;/scripts/global.js&quot;) %&gt;&quot;&gt;&lt;/script&gt;</p>
<p>The <em>BundleHelper.InsertFile</em> method is one you want to use for Stylesheets as well, like so:</p>
<p>&lt;link rel=&quot;Stylesheet&quot; href=&quot;&lt;%=BundleHelper.InsertFile(&quot;includes/style.css&quot;) %&gt;&quot; type=&quot;text/css&quot; /&gt;</p>
<p>Ok, now all our JavaScript and stylesheet references have the version number in the path. Next thing to look at is getting it working with the updated non-existing path.</p>
<h3>The HTTP handler</h3>
<p>To be able to serve the correct file even with the version number in the path, we need to register an HTTP handler in the web.config’s &lt;system.webServer&gt; section like so:</p>
<p>&lt;add name=&quot;ScriptBundler&quot; verb=&quot;GET,HEAD&quot; path=&quot;*.js&quot; type=&quot;FileBundleHandler&quot; /&gt;<br />&lt;add name=&quot;CssBundler&quot; verb=&quot;GET,HEAD&quot; path=&quot;*.css&quot; type=&quot;FileBundleHandler&quot; /&gt;</p>
<p>The handler we just registered is called <em>FileBundleHandler</em> and knows how to filter out the version number to find the right file. It supports both .css and .js files. The handler also makes sure to both output cache and browser cache correctly. Just add the <em>FileBundleHandler.cs</em> file from the zip file to your website and you are up and running.</p>
<p>Now the browser cache issue has been resolved by adding a version number to the path of the included file and by adding an HTTP handler that knows how to remove it again when serving the file.</p>
<h2>Bundle multiple files</h2>
<p>Another common website performance issue is that there are many JavaScript and CSS files included on a page. This scenario results in the browser have to download a lot of extra files and that all slows down the performance of a website. The solution to this is also very simple when you’ve first completed the above steps to register the HTTP handler in web.config and called the <em>BundleHelper.InsertFile</em> method when inserting JavaScript and CSS files.</p>
<h3>The folder structure convention</h3>
<p>There are many ways of bundling files into a single request, like <a rel="friend met" href="http://www.codethinked.com">Justin Etheredge</a>’s <a href="http://www.codethinked.com/post/2010/05/26/SquishIt-The-Friendly-ASPNET-JavaScript-and-CSS-Squisher.aspx">Squisher</a>. For this example I have chosen a convention based approach because that doesn’t require any code to implement.</p>
<p>Any given <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> website might have a folder structure similar to this:</p>
<p><img src="http://madskristensen.net/image.axd?picture=2010/8/folder-structure.png" alt=""></p>
<p>The folder convention supported in the <em>FileBundleHandler</em> lets you reference a folder instead of just a file. Both the HTTP handler and the <em>BundleHelper.InsertFile</em> understand when a folder is referenced and automatically bundles all the .js or .css files to a single response. So in order to bundle all the files in a given folder, simply reference the folder name and add the extension of the types of files you want bundled. Having the folder structure above, you can add a bundle like so:</p>
<p>&lt;script type=&quot;text/javascript&quot; src=&quot;&lt;%=BundleHelper.InsertFile(&quot;/scripts/common.js&quot;) %&gt;&quot;&gt;&lt;/script&gt;</p>
<p>Notice that the file <em>/scripts/common.js</em> doesn’t exist, but the folder <em>/scripts/common</em> does. By adding .js at the end, we tell the HTTP handler to look for all files with the same file extension – in this case .js files. It bundles all the files in alphabetical order and serve the as a single response. For security reasons, the HTTP handler will only serve .css and .js extensions.</p>
<h2>Minification</h2>
<p>Since we are now running all JavaScript and stylesheet files in bundles and through the HTTP handler, it makes sense to also look at the content of the files to optimize even further.</p>
<p>For this example I’m using the <a href="http://aspnet.codeplex.com/releases/view/40584">Microsoft Ajax Minifier</a> (MAM), which is a single .dll file capable of minifying both JavaScript and stylesheets. The MAM is my favorite JavaScript minifier since it not only removes whitespace, it also rewrites variable and function names and a lot of other things as well. For me it has proven a better choice than the <a href="http://developer.yahoo.com/yui/compressor/">YUI Compressor</a> and <a href="http://code.google.com/closure/compiler/">Google Closure Compiler</a>. The stylesheet minifier feature of MAM also looks very nice, but I have honestly never used it before except for this example.</p>
<p>Basically what MAM does is that it optimizes and removes unwanted whitespace from both JavaScript and stylesheets. The HTTP handler makes use of MAM for both single files and bundled ones, so you get full benefit no matter your scenario.</p>
<h2>Summary</h2>
<p>No matter if you use the website model, the web application model or <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> MVC you are now able to utilize the browser cache to the fullest. Furthermore, by bundling your files using the folder convention you can minimize the number of requests sent by the browser. Both JavaScript and stylesheet files are also minified and optimized for even smaller file sizes sent over the wire.</p>
<p>It&#8217;s worth noticing that the output caching respects file changes and therefore refreshes evertime changes are made to the JavaScript and CSS files tunnelled through this code.</p>
<p>Following the techniques in part 1 combined with this example will improve any website’s server-to-browser performance substantially.</p>
<h2>Implementation</h2>
<ol>
<li>Download the zip file below and place the <em>AjaxMin.dll</em> in your bin folder. </li>
<li>Then place the <em>FileBundleHandler.cs</em> in your <em>App_Code</em> folder if you use the website model – otherwise place it where ever it makes sense in your structure. </li>
<li>Now register the HTTP handler in your web.config under the &lt;system.webServer&gt; section like so:
<p>&lt;add name=&quot;ScriptBundler&quot; verb=&quot;GET,HEAD&quot; path=&quot;*.js&quot; type=&quot;FileBundleHandler&quot; /&gt;<br />&lt;add name=&quot;CssBundler&quot; verb=&quot;GET,HEAD&quot; path=&quot;*.css&quot; type=&quot;FileBundleHandler&quot; /&gt;</li>
<li>The last thing you need is to start using the <em>BundleHelper.InsertFile</em> method on your pages for both JavaScript and stylesheets like so:
<p>&lt;script type=&quot;text/javascript&quot; src=&quot;&lt;%=BundleHelper.InsertFile(&quot;/scripts/common.js&quot;) %&gt;&quot;&gt;&lt;/script&gt;<br />&lt;link rel=&quot;Stylesheet&quot; href=&quot;&lt;%=BundleHelper.InsertFile(&quot;styles/global.css&quot;) %&gt;&quot; type=&quot;text/css&quot; /&gt;</li>
</ol>
<h2>Download</h2>
<p><a href="http://madskristensen.net/file.axd?file=2010/8/FileBundler.zip">FileBundler.zip (89,95 kb)</a></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15313/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://madskristensen.net/file.axd?file=2010/8/FileBundler.zip" length="92106" type="application/octet-stream" />
		</item>
		<item>
		<title>ServerInfo &#8211; Easily scan a Machine/Server Farm for Information</title>
		<link>http://zdima.net/blog/archives/15249</link>
		<comments>http://zdima.net/blog/archives/15249#comments</comments>
		<pubDate>Wed, 28 Jul 2010 15:48:00 +0000</pubDate>
		<dc:creator>naspinski</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Contributors]]></category>
		<category><![CDATA[xml]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15249</guid>
		<description><![CDATA[new open-source project in Asp.Net MVC 2


More than once I have been asked what databases are on what server, if server X is running application Y or what websites server ABC is running.  These are are relatively simple things to accomplish, and there...<p class="read-more"><a href="http://zdima.net/blog/archives/15249">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<h2>new open-source project in <a href="http://Asp.Net" class="autohyperlink" title="http://Asp.Net" target="_blank" rel="nofollow">Asp.Net</a> MVC 2</h2>
<p><a href="http://serverinfo.codeplex.com/"><img src="http://i3.codeplex.com/Project/Download/FileDownload.aspx?ProjectName=serverinfo&amp;DownloadId=138799" style="width:480px"></a></p>
<p>More than once I have been asked what databases are on what server, if server X is running application Y or what websites server ABC is running.  These are are relatively simple things to accomplish, and there are tools available to get this information, but this is an extremely simple and portable solution &#8211; all the data is kept in xml, so there is no need to install a backend.</p>
<p>All that it is required to get all this information is to enter ip addresses and the user has the rights to scan the machines requested.</p>
<p>In addition, this can keep track of all of the owners of the machines and has a GUI for running <a href="javascript:void(0);">WMI Queries</a>, which is extremely powerful if you know how to use it.</p>
<p>This is written with <a href="http://Asp.Net" class="autohyperlink" title="http://Asp.Net" target="_blank" rel="nofollow">Asp.Net</a> MVC 2, C# and xml; it requires .Net 4.0 framework.  I will be updating this to MVC 3/Razor in the near future.</p>
<div>
            <a href="http://serverinfo.codeplex.com/" rel="enclosure">ServerInfo on CodePlex</a>
        </div>
<p><a href="http://feedads.g.doubleclick.net/~a/qe9IeRhNB_n9-zHIQLZbw5z4lUI/0/da"><img src="http://feedads.g.doubleclick.net/~a/qe9IeRhNB_n9-zHIQLZbw5z4lUI/0/di" border="0" ismap></a><br />
<a href="http://feedads.g.doubleclick.net/~a/qe9IeRhNB_n9-zHIQLZbw5z4lUI/1/da"><img src="http://feedads.g.doubleclick.net/~a/qe9IeRhNB_n9-zHIQLZbw5z4lUI/1/di" border="0" ismap></a></p>
<div>
<a href="http://feeds.feedburner.com/~ff/naspinski?a=iQuxCWmjmGk:4U_aXqNAfrM:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/naspinski?d=yIl2AUoC8zA" border="0"></a> <a href="http://feeds.feedburner.com/~ff/naspinski?a=iQuxCWmjmGk:4U_aXqNAfrM:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/naspinski?i=iQuxCWmjmGk:4U_aXqNAfrM:gIN9vFwOqvQ" border="0"></a> <a href="http://feeds.feedburner.com/~ff/naspinski?a=iQuxCWmjmGk:4U_aXqNAfrM:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/naspinski?i=iQuxCWmjmGk:4U_aXqNAfrM:F7zBnMyn0Lo" border="0"></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/naspinski/~4/iQuxCWmjmGk" height="1" width="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15249/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>using Server.MapPath() in an Generic Handler (.ashx)</title>
		<link>http://zdima.net/blog/archives/15222</link>
		<comments>http://zdima.net/blog/archives/15222#comments</comments>
		<pubDate>Thu, 22 Jul 2010 12:50:00 +0000</pubDate>
		<dc:creator>naspinski</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Contributors]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15222</guid>
		<description><![CDATA[if you need to get a local file path in your ashx
Instead of using:
Server.MapPath()
Simply use:
System.Web.HttpContext.Current.Server.MapPath()


  
<p class="read-more"><a href="http://zdima.net/blog/archives/15222">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<h2>if you need to get a local file path in your ashx</h2>
<p>Instead of using:</p>
<pre>Server.MapPath()</pre>
<p>
Simply use:</p>
<pre>System.Web.HttpContext.Current.Server.MapPath()</pre>
<p><a href="http://feedads.g.doubleclick.net/~a/VEEddDBAa24jrIdEcBBRsJ14fOI/0/da"><img src="http://feedads.g.doubleclick.net/~a/VEEddDBAa24jrIdEcBBRsJ14fOI/0/di" border="0" ismap></a><br />
<a href="http://feedads.g.doubleclick.net/~a/VEEddDBAa24jrIdEcBBRsJ14fOI/1/da"><img src="http://feedads.g.doubleclick.net/~a/VEEddDBAa24jrIdEcBBRsJ14fOI/1/di" border="0" ismap></a></p>
<div>
<a href="http://feeds.feedburner.com/~ff/naspinski?a=EF7lfUp6d1w:9ww-M0jLzuc:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/naspinski?d=yIl2AUoC8zA" border="0"></a> <a href="http://feeds.feedburner.com/~ff/naspinski?a=EF7lfUp6d1w:9ww-M0jLzuc:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/naspinski?i=EF7lfUp6d1w:9ww-M0jLzuc:gIN9vFwOqvQ" border="0"></a> <a href="http://feeds.feedburner.com/~ff/naspinski?a=EF7lfUp6d1w:9ww-M0jLzuc:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/naspinski?i=EF7lfUp6d1w:9ww-M0jLzuc:F7zBnMyn0Lo" border="0"></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/naspinski/~4/EF7lfUp6d1w" height="1" width="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15222/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Inline AJAX DropDown and Text Editing with Asp.Net MVC and jQuery</title>
		<link>http://zdima.net/blog/archives/15195</link>
		<comments>http://zdima.net/blog/archives/15195#comments</comments>
		<pubDate>Mon, 12 Jul 2010 09:31:00 +0000</pubDate>
		<dc:creator>naspinski</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Contributors]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15195</guid>
		<description><![CDATA[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).
N...<p class="read-more"><a href="http://zdima.net/blog/archives/15195">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<h2>including how to use a database to populate the dropdown</h2>
<p><img src="http://naspinski.net/image.axd?picture=clicked.JPG" alt=""><br />
First thing is first, you will need to download<br />
<a href="http://jquery.com/">jQuery</a><br />
and the<br />
<a href="http://www.appelsiini.net/projects/jeditable">Jeditable</a><br />
plugin (I prefer to refer to it as the Jedi-Table!).<br />
Be sure to put these references in your View (or Masterpage).<br />
Next, you have to set up a view on which to use an inline edit.<br />
I find that I often want to use this approach on tables of information.<br />
For this View, I will set it to use an IEnumerable of an Item I have called &#8216;ItemOwner&#8217; (this is arbitrary and does not really matter).<br />
It will be a simple table that lists the Name and the Country of the owner, both of which will be editable inline.<br />
Here is the Index in my ExampleController.cs:</p>
<pre>myDataContext db = new myDataContext();
public ActionResult Index()
{
    // get the info for the &#39;Countries&#39; dropdown:
    ViewData[&quot;countries&quot;] = db.Countries
        .Select(x =&gt; new SelectListItem()
        {
            Text = x.Name,
            Value = x.Id.ToString()
        }).ToJson();

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

    return View(owners);
}</pre>
<p>
As you can see there, I am also pulling the countries from the database and throwing them into the ViewState &#8211; we will get to this later.<br />
Since the Country is actually a foreign key relation, the value is set to an integer which is the identity field in the database.<br />
It is also using a .ToJson() extension which takes a IEnumerable&lt;SelectListItem&gt; and<br />
    puts it into a simple JSON string that I use which is here:</p>
<pre>public static string
    ToJson(this IEnumerable&lt;SelectListItem&gt; slis)
{
    string output = &quot;{&quot;;
    if (slis != null)
    {
        for (int i = 0; i &lt; slis.Count(); i++)
        {
            output += &quot; &#39;&quot; + slis.Skip(i)
            .First().Value + &quot;&#39;: &#39;&quot; +
            slis.Skip(i).First().Text + &quot;&#39;&quot; +
            (i == slis.Count() - 1 ? &quot; &quot; : &quot;,&quot;);
        }
    }
    return output += &quot;}&quot;;
}</pre>
<p>
There is probably a better way to do that&#8230; but I don&#8217;t know it?!</p>
<p>I am also pulling 3 ItemOwners from the database, I know this is silly, but it  just an example.<br />
Here is how I am displaying them in the view:</p>
<pre>&lt;table&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;Name&lt;/th&gt;
            &lt;th&gt;Country&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;% foreach(var owner in Model) { %&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;%= <a href="http://owner.Name" class="autohyperlink" title="http://owner.Name" target="_blank" rel="nofollow">owner.Name</a> %&gt;&lt;/td&gt;
            &lt;td&gt;&lt;%= owner.Country.Abbreviation %&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;% } %&gt;
    &lt;/tbody&gt;
&lt;/table&gt;</pre>
<p>
Now that there is a simple table we want to make it a bit more interactive.<br />
Since we aregoing to make all of these fields editable, we need to add in a way to distinguish exactly what they are.<br />
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).<br />
So to do that, let&#8217;s add in a few css classes and an identifieng ID:</p>
<pre>&lt;td id=&quot;name&lt;%= owner.Id %&gt;&quot; class=&quot;editable text&quot;&gt;
    &lt;%= <a href="http://owner.Name" class="autohyperlink" title="http://owner.Name" target="_blank" rel="nofollow">owner.Name</a> %&gt;&lt;/td&gt;
&lt;td id=&quot;ctry&lt;%= owner.Id %&gt;&quot; class=&quot;editable dropdown&quot;&gt;
    &lt;%= owner.Country.Abbreviation %&gt;&lt;/td&gt;</pre>
<p> <br />
And now add a little css to make them appear to be clickable:</p>
<pre>td.editable:hover
{ cursor:pointer; background-color:Orange; }</pre>
<p>
Now they all look like you can click on them, so we can move on to making the click actually do something.<br />
<br />
<img src="http://naspinski.net/image.axd?picture=hover.JPG" alt=""><br />
<br />
This is where the jQuery comes in, and it is very simple.<br />
I have made these &#8216;helper&#8217; 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.</p>
<pre>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'
    });
}</pre>
<p>
Obviously you can read all about the options on the <a href="http://www.appelsiini.net/projects/jeditable">Jeditable</a><br />
page, but this is how I set them.<br />
Also notice I have a InineTextarea included as well for a textarea which is not covered here but works the exact same.</p>
<p>Now the jQuery calls are almost trivial:</p>
<pre>InlineTextbox(
    $(&#39;td.editable.text&#39;),
    &quot;&lt;%= Url.Content(&quot;~/Ajax/ItemOwner.ashx&quot;) %&gt;&quot;
);

InlineDropdown(
    $(&#39;td.editable.dropdown&#39;),
    &quot;&lt;%= Url.Content(&quot;~/Ajax/ItemOwner.ashx&quot;) %&gt;&quot;,
    &lt;%= ViewData[&quot;countries&quot;].ToString() %&gt;
);</pre>
<p>
What that is doing is sending the POST requests to the specified address.<br />
The POST contains a few things:</p>
<ul>
<li><b>id</b> &#8211; the id of the element that sent the request</li>
<li><b>value</b> &#8211; the new value passed by the element</li>
</ul>
<p>We are also passing more information there &#8211; remember that we passed both the type of field to edit <em>and</em> the id of the ItemOwner to edit, ie [name837] which emans we want to edit the Name field of ItemOwner 837.<br />
So we simply set up an ashx handler (which we specified above) to do the dirty work:</p>
<pre>public void ProcessRequest(HttpContext context)
{
    string newValue;
    try
    {
        myDataContext db = new myDataContext();
        string elementId = context.Request.Form[&quot;id&quot;];

        // since we made the first 4 of the id the &#39;field&#39; 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[&quot;value&quot;].Trim();

        // now that we have the id, get the ItemOwner from the db
        ItemOwner owner = db.ItemOwners.FirstOrDefault(x =&gt; 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 &quot;name&quot;: <a href="http://owner.Name" class="autohyperlink" title="http://owner.Name" target="_blank" rel="nofollow">owner.Name</a> = newValue; break;

            // since the country is an integer foreign key, we need to Convert.ToInt32:
            case &quot;ctry&quot;:
                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 =&gt; x.Id == owner.CountryId).Abbreviation;
                break;
            // if it wasn&#39;t caught, something is wrong:
            default: throw new Exception(&quot;invalid fieldToEdit passed&quot;);
        }

        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 = &quot;Error: &quot; + ex.Message + &quot; [nothing written to db]&quot;; }

    //now return what you want in the element:
    context.Response.Write(newValue);
}</pre>
<p>
And that is all it takes.
<p><iframe src="http://feedads.g.doubleclick.net/~ah/f/kijri0o2kgcv9o6a1kk1fsjgmk/300/250?ca=1&amp;fh=280#http://naspinski.net/post.aspx?id=9c3a446e-35f3-442d-8031-d129914635bd" width="100%" height="280" frameborder="0" scrolling="no" marginwidth="0" marginheight="0"></iframe></p>
<div>
<a href="http://feeds.feedburner.com/~ff/naspinski?a=2N4iwE_dArk:Exnkys-LL1g:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/naspinski?d=yIl2AUoC8zA" border="0"></a> <a href="http://feeds.feedburner.com/~ff/naspinski?a=2N4iwE_dArk:Exnkys-LL1g:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/naspinski?i=2N4iwE_dArk:Exnkys-LL1g:gIN9vFwOqvQ" border="0"></a> <a href="http://feeds.feedburner.com/~ff/naspinski?a=2N4iwE_dArk:Exnkys-LL1g:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/naspinski?i=2N4iwE_dArk:Exnkys-LL1g:F7zBnMyn0Lo" border="0"></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/naspinski/~4/2N4iwE_dArk" height="1" width="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15195/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Performance tuning tricks for ASP.NET and IIS 7 – part 1</title>
		<link>http://zdima.net/blog/archives/15174</link>
		<comments>http://zdima.net/blog/archives/15174#comments</comments>
		<pubDate>Wed, 07 Jul 2010 21:55:00 +0000</pubDate>
		<dc:creator>Mads Kristensen</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Contributors]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15174</guid>
		<description><![CDATA[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 exis...<p class="read-more"><a href="http://zdima.net/blog/archives/15174">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p>In this first installment of performance tuning tricks for <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<p>The following XML snippets <strong>must</strong> be placed in the &lt;system.webServer&gt; section of the web.config.</p>
<h2>HTTP compression</h2>
<p>You’ve always been able to perform HTTP compression in <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> by using <a href="http://blowery.org/httpcompress/">third-party libraries</a> 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:</p>
<p>&lt;urlCompression doDynamicCompression=&quot;true&quot; doStaticCompression=&quot;true&quot; dynamicCompressionBeforeCache=&quot;true&quot;/&gt;</p>
<p>By default, only text based content types are compressed.</p>
<h3>doDynamicCompression</h3>
<p>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.</p>
<h3>doStaticCompression</h3>
<p>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.</p>
<h3>dynamicCompressionBeforeCache</h3>
<p>If you do output caching from within your <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<h3>Tip</h3>
<p>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.</p>
<h3>Resources</h3>
<ul>
<li><a href="http://www.west-wind.com/weblog/posts/98538.aspx">Add new mime-types for compression</a></li>
<li><a href="http://technet.microsoft.com/en-us/library/cc771003(WS.10).aspx">Configure HTTP compression in IIS 7 (Technet)</a></li>
</ul>
<h2>Cache static files</h2>
<p>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 <em>load</em> and <em>DOMContentLoaded</em> event sooner.</p>
<p>By adding this snippet to your web.config, all static files are cached in the browser for 1 year:</p>
<p>&lt;staticContent&gt;<br />     &lt;clientCache cacheControlMode=&quot;UseMaxAge&quot; cacheControlMaxAge=&quot;365.00:00:00&quot;/&gt;<br />&lt;/staticContent&gt;</p>
<p>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.</p>
<p>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.</p>
<h3>Tip</h3>
<p>Make sure that user sensitive information isn&#8217;t cached on the browser. It will then be available by anyone else using the same browser.</p>
<h3>Resources</h3>
<ul>
<li><a href="http://www.iis.net/ConfigReference/system.webServer/staticContent/clientCache">Client Cache &lt;clientCache&gt; (iis.net)</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15174/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using an iPhone with the Visual Studio development server</title>
		<link>http://zdima.net/blog/archives/15086</link>
		<comments>http://zdima.net/blog/archives/15086#comments</comments>
		<pubDate>Thu, 10 Jun 2010 13:10:52 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Contributors]]></category>
		<category><![CDATA[iPhone]]></category>
		<category><![CDATA[Mobile]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15086</guid>
		<description><![CDATA[ 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 mob...<p class="read-more"><a href="http://zdima.net/blog/archives/15086">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p><img style="margin:0 10px 10px 0" alt="Testing an ASP.NET site on an iPhone" align="left" src="http://encosia.com/blog/wp-content/uploads/2010/06/asp.net-on-iphone.png" width="195" height="373"> Developing iPhone-optimized portions of an <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> website presents a challenge. More specifically, it’s <em>testing</em> your creations that can be difficult.</p>
<p>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, <strong>testing with the real thing is preferable</strong>.</p>
<p>Unfortunately, the <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<p>In this post, <strong>I’m going to show you one way I’ve found to circumvent that restriction</strong>, how to configure your iPhone to take advantage of that, and how to connect to the development server once those steps are completed.</p>
<p><em>Note: This post specifically describes configuring an iPhone, but the same approach will work for any mobile device that supports using an HTTP proxy.</em></p>
<h3>Fooling the <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> Development Server</h3>
<p>The fundamental problem is that Visual Studio’s <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<p>The solution that I stumbled onto uses a tool that you may already have installed: <a href="http://www.fiddler2.com/fiddler2/version.asp">Fiddler</a>. If you aren’t familiar with Fiddler, <a href="http://live.visitmix.com/MIX10/Sessions/FT50">this recording of Eric Lawrence’s session at MIX10</a> is a great way to learn a lot about Fiddler in relatively little time.</p>
<p>The feature that we’re specifically interested in is its <a href="http://en.wikipedia.org/wiki/Proxy_server" rel="nofollow">HTTP proxy server</a>. Unlike the <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> Development Server, <strong>Fiddler does not restrict connections from external devices</strong>. Even better, routing an external device’s connections through Fiddler is misdirection enough to fool the development server into accepting them.</p>
<h3>Checking Fiddler’s proxy port</h3>
<p>With Fiddler installed, the first step is to determine which port it’s running the proxy server on. On fresh installs, <strong>the default setting is port 8888</strong>.</p>
<p>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 <em>Tools</em> &gt; <em>Fiddler Options</em>, and selecting the <em>Connections</em> tab:</p>
<p><img border="0" alt="Finding the port that Fiddler&#39;s proxy server listens on" src="http://encosia.com/blog/wp-content/uploads/2010/06/fiddler-options.png" width="492" height="327"></p>
<p>While you have that dialog open, also verify that the three checkboxes circled above <em>are</em> checked.</p>
<h3>Finding your IP address</h3>
<p>The next step is to determine your machine’s IP address on the local network. A quick way to do that is running <em>ipconfig</em> at the command prompt.</p>
<p>To open a command prompt, press <em>Win + R</em>, type <em>cmd</em> in the field, and hit enter.</p>
<p><img border="0" alt="Running cmd" src="http://encosia.com/blog/wp-content/uploads/2010/06/running-cmd.png" width="492" height="271"></p>
<p>At the command prompt that opens, type <em>ipconfig</em> and hit enter.</p>
<p><img alt="Finding the local IP address with ipconfig" src="http://encosia.com/blog/wp-content/uploads/2010/06/finding-ip-address-with-ipconfig.png" width="490" height="225"></p>
<p>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.</p>
<p>Find yours and make note of it for the next step.</p>
<p><em>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.</em></p>
<h3>Configuring an iPhone to route through Fiddler</h3>
<p>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.</p>
<p>To do that, open the settings app and tap the Wi-Fi option <em>(below, left)</em>.</p>
<p><img alt="Navigating through the iPhone&#39;s settings" src="http://encosia.com/blog/wp-content/uploads/2010/06/iphone-network-settings-composite.png" width="492" height="192"> </p>
<p>In the Wi-Fi Networks panel <em>(above, right)</em>, 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.</p>
<p><img style="margin:5px 10px 20px 0" alt="Setting the iPhone&#39;s proxy settings" align="left" src="http://encosia.com/blog/wp-content/uploads/2010/06/wifi-proxy-settings.png" width="225" height="201">At the very bottom of the panel that opens <em>(left)</em>, find the HTTP Proxy setting and tap Manual <em>(1)</em> to enable the feature. In the fields that appear, enter your computer’s local IP address for the server <em>(2)</em>, and the port that Fiddler is listening on for the… Port <em>(3)</em>.</p>
<p>That’s it! Your iPhone is configured to route its traffic through an instance of Fiddler running on your development machine.</p>
<h3>Starting the development server</h3>
<p>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).</p>
<p>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.</p>
<p>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:</p>
<p><img alt="Finding the port and virtual root of your development server app" src="http://encosia.com/blog/wp-content/uploads/2010/06/asp.net-development-server.png" width="492" height="284"></p>
<p>The “Root URL” address there is what you’ll need in the final step.</p>
<h3>Accessing the development server from your device</h3>
<p>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.</p>
<p>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:</p>
<blockquote>
<p>Wrong!</p>
<p><a href="http://localhost:24833/WebSite1" class="autohyperlink" title="http://localhost:24833/WebSite1" target="_blank" rel="nofollow">localhost:24833/WebSite1</a></p>
</blockquote>
<p>To make it work, we simply need to append the trailing period to localhost:</p>
<blockquote><p><a href="http://localhost.:24833/WebSite1" class="autohyperlink" title="http://localhost.:24833/WebSite1" target="_blank" rel="nofollow">localhost.:24833/WebSite1</a></p>
</blockquote>
<p>That does look odd, but it works.</p>
<p><a href="http://www.fiddler2.com/fiddler/help/hookup.asp#Q-LocalTraffic" rel="nofollow">Fiddler also recognizes ipv4.fiddler as an alias for the localhost loopback</a>, which is a little bit more intuitive. So, you could also access the same example with this address if you prefer:</p>
<blockquote><p><a href="http://ipv4.fiddler:24833/WebSite1" class="autohyperlink" title="http://ipv4.fiddler:24833/WebSite1" target="_blank" rel="nofollow">ipv4.fiddler:24833/WebSite1</a></p>
</blockquote>
<p>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.</p>
<h3>Conclusion</h3>
<p>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.</p>
<p>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.</p>
<p>Of course, Fiddler isn’t the only utility that will work as an intermediary like this, but <strong>using Fiddler brings the great side-effect of providing HTTP traffic analysis while you’re testing</strong>. That added utility is welcome when you’re testing on a mobile device where the on-device development tools are basically nonexistent.</p>
<p>
<p>###</p>
<p>Originally posted at <a href="http://encosia.com">Encosia</a>.  If you&#8217;re reading this elsewhere, come on over and see the original.</p>
<p><a href="http://encosia.com/2010/06/10/using-an-iphone-with-the-visual-studio-development-server/">Using an iPhone with the Visual Studio development server</a></p>
<div>
<a href="http://feeds.encosia.com/~ff/Encosia?a=vQoxmC6lOYk:0KA_ZI17Le8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=vQoxmC6lOYk:0KA_ZI17Le8:D7DqB2pKExk" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vQoxmC6lOYk:0KA_ZI17Le8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vQoxmC6lOYk:0KA_ZI17Le8:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vQoxmC6lOYk:0KA_ZI17Le8:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vQoxmC6lOYk:0KA_ZI17Le8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=vQoxmC6lOYk:0KA_ZI17Le8:F7zBnMyn0Lo" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=vQoxmC6lOYk:0KA_ZI17Le8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=vQoxmC6lOYk:0KA_ZI17Le8:gIN9vFwOqvQ" border="0"></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/Encosia/~4/vQoxmC6lOYk" height="1" width="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15086/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ASMX ScriptService mistake – Invalid JSON primitive</title>
		<link>http://zdima.net/blog/archives/15070</link>
		<comments>http://zdima.net/blog/archives/15070#comments</comments>
		<pubDate>Tue, 01 Jun 2010 04:33:58 +0000</pubDate>
		<dc:creator>Dave Ward</dc:creator>
				<category><![CDATA[AJAX]]></category>
		<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[Contributors]]></category>

		<guid isPermaLink="false">http://zdima.net/blog/?p=15070</guid>
		<description><![CDATA[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 t...<p class="read-more"><a href="http://zdima.net/blog/archives/15070">> Read more</a></p>]]></description>
			<content:encoded><![CDATA[<p>One group of searches that consistently brings traffic here is variations on the error: <strong>Invalid JSON primitive</strong>. Unfortunately, the post that Google sends that traffic to doesn’t address the issue until somewhere within its 150+ comments.</p>
<p>Today, the topic gets its own post.</p>
<p>If you’ve worked with ASMX ScriptServices or Page Methods without <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<p>Either way, you may be surprised to learn that <strong>the most common reason for this error is that you’ve lied to <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a></strong> during your AJAX request.</p>
<h3>It all begins with the Content-Type</h3>
<p>HTTP’s <a href="http://www.w3.org/Protocols/rfc1341/4_Content-Type.html" rel="nofollow">Content-Type</a> header is a fundamental aspect of communication between browsers and servers, yet often remains hidden from us in day-to-day development. <strong>The Content-Type header allows an HTTP connection to describe the format of its contents</strong>, using <a href="http://en.wikipedia.org/wiki/Internet_media_type" rel="nofollow">Internet media types</a> (also known as MIME types). A few common ones that you’ve probably seen before are <em>text/html</em>, <em>image/png</em>, and the more topical <em>application/json</em>.</p>
<p>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.</p>
<p>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).</p>
<p>The benefits of Content-Type negotiation are well worth a bit of occasional hassle.</p>
<h3>Okay, but why does that matter?</h3>
<p>When your browser sends a POST request, the W3C’s recommendation is that it should default to using a Content-Type of <em>application/x-www-form-urlencoded</em>. <a href="http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1" rel="nofollow">The HTML 4.01 spec describes that serialization scheme</a>:</p>
<blockquote>
<p>This is the default content type. Forms submitted with this content type must be encoded as follows:</p>
<ol>
<li>[Omitted for brevity; not relevant to this post.] </li>
<li>The control names/values are listed in the order they appear in the document. <strong>The name is separated from the value by ‘=’ and name/value pairs are separated from each other by ‘&amp;’.</strong> </li>
</ol>
</blockquote>
<p>For an example of what that means, consider this simple form:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;form</span> <span style="color:#000066">method</span><span style="color:#66cc66">=</span><span style="color:#ff0000">&quot;post&quot;</span><span style="color:#000000;font-weight:bold">&gt;</span></span>
  <span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;label&gt;</span></span>First Name<span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;/label&gt;</span></span>
  <span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;input</span> <span style="color:#000066">id</span><span style="color:#66cc66">=</span><span style="color:#ff0000">&quot;FirstName&quot;</span> <span style="color:#000066">value</span><span style="color:#66cc66">=</span><span style="color:#ff0000">&quot;Dave&quot;</span> <span style="color:#000066">name</span><span style="color:#66cc66">=</span><span style="color:#ff0000">&quot;FirstName&quot;</span> <span style="color:#66cc66">/</span><span style="color:#000000;font-weight:bold">&gt;</span></span>
 
  <span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;label&gt;</span></span>Last Name<span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;/label&gt;</span></span>
  <span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;input</span> <span style="color:#000066">id</span><span style="color:#66cc66">=</span><span style="color:#ff0000">&quot;LastName&quot;</span> <span style="color:#000066">value</span><span style="color:#66cc66">=</span><span style="color:#ff0000">&quot;Ward&quot;</span> <span style="color:#000066">name</span><span style="color:#66cc66">=</span><span style="color:#ff0000">&quot;LastName&quot;</span> <span style="color:#66cc66">/</span><span style="color:#000000;font-weight:bold">&gt;</span></span>
<span style="color:#009900"><span style="color:#000000;font-weight:bold">&lt;/form&gt;</span></span></pre>
</div>
</div>
<p>When the preceding form is submitted with URL encoded serialization, the request’s POST data will look like this:</p>
<p><img title="URLEncoded POST data" alt="Firebug screenshot showing the URLEncoded POST data" src="http://encosia.com/blog/wp-content/uploads/2010/05/url-encoded-post-data.png" width="492" height="172"></p>
<p>That standardized serialization format allows a server-side backend like <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> 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.</p>
<p>In other words, <strong>the Content-Type corresponds to a serialization scheme</strong>.</p>
<h3>What does that have to do with JSON Primitives?</h3>
<p>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 <a href="http://encosia.com/2008/03/27/using-jquery-to-consume-aspnet-json-web-services/">you must set a Content-Type of application/json on the request</a><em></em> means <strong>you’re instructing <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> to interpret your input parameters as JSON serialized data</strong>.</p>
<p>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 <a href="http://ASP.NET" class="autohyperlink" title="http://ASP.NET" target="_blank" rel="nofollow">ASP.NET</a> MVC examples) will describe sending URL encoded data to the server.</p>
<p>In other words, when you’re working with a client-side object like this:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#003366;font-weight:bold">var</span> Person <span style="color:#339933">=</span> <span style="color:#009900">{</span> FirstName<span style="color:#339933">:</span> <span style="color:#3366CC">'Dave'</span><span style="color:#339933">,</span>
               LastName<span style="color:#339933">:</span>  <span style="color:#3366CC">'Ward'</span> <span style="color:#009900">}</span></pre>
</div>
</div>
<p>The default serialization scheme makes it easy to inadvertently transmit that data to the server as a URL encoded string:</p>
<div>
<div>
<pre style="font-family:monospace">FirstName<span style="color:#339933">=</span>Dave<span style="color:#339933">&amp;</span>LastName<span style="color:#339933">=</span>Ward</pre>
</div>
</div>
<p>Again, remember that <a href="http://weblogs.asp.net/scottgu/archive/2007/04/04/json-hijacking-and-how-asp-net-ajax-1-0-mitigates-these-attacks.aspx">a Content-Type of <em>application/json</em> is a requirement when working with ASMX ScriptServices</a>. 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.</p>
<p>In fact, it’s <strong>invalid JSON</strong> (primitive?), hence the cryptic error message.</p>
<p>Instead of the URL encoded string above, you must be sure to send a JSON string:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#009900">{</span><span style="color:#3366CC">'FirstName'</span><span style="color:#339933">:</span><span style="color:#3366CC">'Dave'</span><span style="color:#339933">,</span><span style="color:#3366CC">'LastName'</span><span style="color:#339933">:</span><span style="color:#3366CC">'Ward'</span><span style="color:#009900">}</span></pre>
</div>
</div>
<p>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.</p>
<h3>When good JavaScript libraries go bad</h3>
<p>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:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#006600;font-style:italic">// WRONG!</span>
$.<span style="color:#660066">ajax</span><span style="color:#009900">(</span><span style="color:#009900">{</span>
  type<span style="color:#339933">:</span> <span style="color:#3366CC">'POST'</span><span style="color:#339933">,</span>
  contentType<span style="color:#339933">:</span> <span style="color:#3366CC">'application/json'</span><span style="color:#339933">,</span>
  dataType<span style="color:#339933">:</span> <span style="color:#3366CC">'json'</span><span style="color:#339933">,</span>
  url<span style="color:#339933">:</span> <span style="color:#3366CC">'WebService.asmx/Hello'</span><span style="color:#339933">,</span>
  data<span style="color:#339933">:</span> <span style="color:#009900">{</span> FirstName<span style="color:#339933">:</span> <span style="color:#3366CC">&quot;Dave&quot;</span><span style="color:#339933">,</span> LastName<span style="color:#339933">:</span> <span style="color:#3366CC">&quot;Ward&quot;</span> <span style="color:#009900">}</span>
<span style="color:#009900">}</span><span style="color:#009900">)</span><span style="color:#339933">;</span></pre>
</div>
</div>
<p>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.</p>
<p>Why? <strong>jQuery serializes $.ajax()’s data parameter using the URL encoded scheme, regardless of what Content-Type is specified</strong>. Even though the contentType parameter clearly specifies JSON serialization, this URL encoded string is what jQuery will send to the server:</p>
<div>
<div>
<pre style="font-family:monospace">FirstName<span style="color:#339933">=</span>Dave<span style="color:#339933">&amp;</span>LastName<span style="color:#339933">=</span>Ward</pre>
</div>
</div>
<p>That obviously isn’t valid JSON!</p>
<p>The solution is as simple as two single-quotes:</p>
<div>
<div>
<pre style="font-family:monospace"><span style="color:#006600;font-style:italic">// RIGHT</span>
$.<span style="color:#660066">ajax</span><span style="color:#009900">(</span><span style="color:#009900">{</span>
  type<span style="color:#339933">:</span> <span style="color:#3366CC">'POST'</span><span style="color:#339933">,</span>
  contentType<span style="color:#339933">:</span> <span style="color:#3366CC">'application/json'</span><span style="color:#339933">,</span>
  dataType<span style="color:#339933">:</span> <span style="color:#3366CC">'json'</span><span style="color:#339933">,</span>
  url<span style="color:#339933">:</span> <span style="color:#3366CC">'WebService.asmx/Hello'</span><span style="color:#339933">,</span>
  data<span style="color:#339933">:</span> <span style="color:#3366CC">&#39;{ FirstName: &quot;Dave&quot;, LastName: &quot;Ward&quot; }&#39;</span>
<span style="color:#009900">}</span><span style="color:#009900">)</span><span style="color:#339933">;</span></pre>
</div>
</div>
<p>Did you spot the difference?</p>
<p>Instead of a JavaScript object literal, <strong>the data parameter is a JSON string now</strong>. <a href="http://benalman.com/news/2010/03/theres-no-such-thing-as-a-json/">The difference is subtle, but helpful to understand</a>. 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.</p>
<h3>It doesn’t have to be this way</h3>
<p>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.</p>
<p><strong>jQuery</strong> – I believe the most correct solution would be $.ajax() attempting to honor the serialization scheme indicated by its contentType parameter. In the case of <em>application/json</em> fixing this could be easy as testing for JSON.stringify and using it if available, to avoid adding any complexity/size to jQuery core.</p>
<p>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. <a href="http://encosia.com/2009/04/07/using-complex-types-to-make-calling-services-less-complex/">We generally do that anyway when the client-side objects get complex</a>.</p>
<p><strong>Microsoft</strong> – 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).</p>
<p>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?</p>
<p>
<p>###</p>
<p>Originally posted at <a href="http://encosia.com">Encosia</a>.  If you&#8217;re reading this elsewhere, come on over and see the original.</p>
<p><a href="http://encosia.com/2010/05/31/asmx-scriptservice-mistake-invalid-json-primitive/">ASMX ScriptService mistake – Invalid JSON primitive</a></p>
<div>
<a href="http://feeds.encosia.com/~ff/Encosia?a=6WFOIfNVBT8:esDuimsm2WA:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/Encosia?i=6WFOIfNVBT8:esDuimsm2WA:D7DqB2pKExk" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=6WFOIfNVBT8:esDuimsm2WA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=yIl2AUoC8zA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=6WFOIfNVBT8:esDuimsm2WA:aWKiLpGymzw"><img src="http://feeds.feedburner.com/~ff/Encosia?d=aWKiLpGymzw" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=6WFOIfNVBT8:esDuimsm2WA:30RXbuXOgYA"><img src="http://feeds.feedburner.com/~ff/Encosia?d=30RXbuXOgYA" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=6WFOIfNVBT8:esDuimsm2WA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Encosia?i=6WFOIfNVBT8:esDuimsm2WA:F7zBnMyn0Lo" border="0"></a> <a href="http://feeds.encosia.com/~ff/Encosia?a=6WFOIfNVBT8:esDuimsm2WA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Encosia?i=6WFOIfNVBT8:esDuimsm2WA:gIN9vFwOqvQ" border="0"></a>
</div>
<p><img src="http://feeds.feedburner.com/~r/Encosia/~4/6WFOIfNVBT8" height="1" width="1"></p>
]]></content:encoded>
			<wfw:commentRss>http://zdima.net/blog/archives/15070/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

