<?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>davidpoll.com &#187; logging</title>
	<atom:link href="http://www.davidpoll.com/tag/logging/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.davidpoll.com</link>
	<description>Software development and other goofy geeky goodness.</description>
	<lastBuildDate>Sat, 18 Jun 2011 22:03:16 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Logging Navigation in the Silverlight 3 Beta</title>
		<link>http://www.davidpoll.com/2009/05/12/logging-navigation-in-the-silverlight-3-beta/</link>
		<comments>http://www.davidpoll.com/2009/05/12/logging-navigation-in-the-silverlight-3-beta/#comments</comments>
		<pubDate>Wed, 13 May 2009 06:58:25 +0000</pubDate>
		<dc:creator>david.poll</dc:creator>
				<category><![CDATA[Silverlight]]></category>
		<category><![CDATA[logging]]></category>
		<category><![CDATA[Navigation]]></category>
		<category><![CDATA[Silverlight 3 Beta]]></category>

		<guid isPermaLink="false">http://www.davidpoll.com/?p=42</guid>
		<description><![CDATA[I’ve been playing around recently with my webserver – I recently switched from a hosted ASP.NET service to a virtual dedicated server, so I’m getting a chance to play with having full control over my server for the first time.&#160; I spent some time setting up logging and statistics on the server using IIS’s logging [...]]]></description>
			<content:encoded><![CDATA[<!-- Advanced AdSense by Jim Gaudet --><!-- google_ad_section_start --><p>I’ve been playing around recently with my webserver – I recently switched from a hosted ASP.NET service to a virtual dedicated server, so I’m getting a chance to play with having full control over my server for the first time.&#160; I spent some time setting up logging and statistics on the server using IIS’s logging feature and some 3rd party log-crunching software.&#160; Having that logging data is invaluable – among other things, it helps me know which pages folks are interested in and gives me insight into whether it’s too hard to reach certain sections of my page.&#160; With the addition of navigation controls in the Silverlight 3 Beta SDK, having a logging solution that cooperates with my web server seems only prudent!</p>
<p>Tim Heuer has a great blog post from December about using <a href="http://timheuer.com/blog/archive/2008/12/04/analytics-web-tracking-with-silverlight.aspx">event tracking with Google Analytics for Silverlight applications</a>.&#160; My impression is that this approach would work well with the new navigation controls, but I was looking for a simple solution that would add entries to my IIS logs straight from the Silverlight application (without having to add any javascript or use the HTML bridge).</p>
<p>The issue at hand is that the navigation controls use the URI fragment (text after the “#” sign in the URL) to determine which Page to navigate to in a Frame control.&#160; As a result (and rightly so), deeplinks into the Silverlight control or navigation that occurs within the Silverlight control never round-trip to the server, so there is no way for the server to log their occurrence.</p>
<p>Hence, my approach is fairly straightforward: make an HTTP request back to the hosting server that it will log any time my Frame is navigated.</p>
<p>My requirements for the experiment:</p>
<ul>
<li>Reuse the built-in logging features of my web server (IIS 7, but I imagine this would work more broadly) </li>
<li>Ensure that unique URIs within my application are logged individually (so query strings, custom URIs, etc. are not lost in the logged data) </li>
<li>Avoid limiting the application by requiring the HTML bridge to be accessible or requiring additional files to be added to my website (such as javascript files or additional ASP.NET Pages) </li>
</ul>
<p>It turns out this isn’t so difficult to do!&#160; I started with the Silverlight Navigation Application project template that ships with the <a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=11dc7151-dbd6-4e39-878f-5081863cbb5d&amp;displaylang=en">Silverlight 3 Beta Tools for Visual Studio</a> that came out at MIX.&#160; This project template gets me set up with a Frame, some Pages, and some buttons that cause the Frame to navigate – everything a newborn navigation application needs to grow big and strong!</p>
<p>I began by handling the Frame control’s “Navigated” event in MainPage.xaml:</p>
<pre class="code"><span style="color: blue">&lt;</span><span style="color: #a31515">navigation</span><span style="color: blue">:</span><span style="color: #a31515">Frame </span><span style="color: red">x</span><span style="color: blue">:</span><span style="color: red">Name</span><span style="color: blue">=&quot;Frame&quot; </span><span style="color: red">Source</span><span style="color: blue">=&quot;/Views/HomePage.xaml&quot;
                  </span><span style="color: red"><strong><em>Navigated</em></strong></span><span style="color: blue"><strong><em>=&quot;Frame_Navigated&quot;</em></strong>
                  </span><span style="color: red">HorizontalContentAlignment</span><span style="color: blue">=&quot;Stretch&quot;
                  </span><span style="color: red">VerticalContentAlignment</span><span style="color: blue">=&quot;Stretch&quot;
                  </span><span style="color: red">Padding</span><span style="color: blue">=&quot;15,10,15,10&quot;
                  </span><span style="color: red">Background</span><span style="color: blue">=&quot;White&quot;/&gt;</span></pre>
<p><a href="http://11011.net/software/vspaste"></a>With the easy part out of the way (who knew?), I started playing with WebRequest and WebClient until I came up with something that seemed to meet my needs:</p>
<pre class="code"><span style="color: blue">private void </span>Frame_Navigated(<span style="color: blue">object </span>sender, <span style="color: #2b91af">NavigationEventArgs </span>e)
{
    <span style="color: #2b91af">Uri </span>uri = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #2b91af">Application</span>.Current.Host.Source.ToString() + <span style="color: #a31515">&quot;?nav=&quot; </span>+ <span style="color: #2b91af">Uri</span>.EscapeDataString(e.Uri.ToString()));
    <span style="color: #2b91af">WebRequest </span>wc = <span style="color: #2b91af">WebRequest</span>.Create(uri);
    wc.Method = <span style="color: #a31515">&quot;POST&quot;</span>;
    wc.BeginGetResponse((res) =&gt;
    {
        <span style="color: #2b91af">WebResponse </span>wr = wc.EndGetResponse(res);
    }, <span style="color: blue">this</span>);
}</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>I’ll walk through this line-by-line and explain my thinking:</p>
<pre class="code"><span style="color: #2b91af">Uri </span>uri = <span style="color: blue">new </span><span style="color: #2b91af">Uri</span>(<span style="color: #2b91af">Application</span>.Current.Host.Source.ToString() + <span style="color: #a31515">&quot;?nav=&quot; </span>+ <span style="color: #2b91af">Uri</span>.EscapeDataString(e.Uri.ToString()));</pre>
<p><a href="http://11011.net/software/vspaste"></a></p>
<p>Here, I needed to come up with a file I knew would be present on the server and that isn’t likely to have any semantics that I’ll be overriding by making a request.&#160; In addition, I wanted to choose a file that would uniquely identify the Silverlight application that is making the request.&#160; It seemed only logical, then to use the XAP file for my Silverlight app for this purpose!&#160; Next, I added a query string that would be sent down to the server that would uniquely identify the URI that the Frame is using.&#160; The result, if the source URI is “/Views/HomePage.xaml” (as is shown in the XAML), the resulting URI is: “http://yourservername.com/yourSilverlightApp.xap?nav=%2FViews%2FHomePage.xaml”.&#160; Ok, ok, it’s not pretty (thanks to the encoding of the URI), but it does the trick.&#160; The query string here never gets used, but it does get sent to the server and logged, which leaves me with exactly the traces I was looking for!</p>
<p>Next:</p>
<pre class="code"><span style="color: #2b91af">WebRequest </span>wc = <span style="color: #2b91af">WebRequest</span>.Create(uri);
wc.Method = <span style="color: #a31515">&quot;POST&quot;</span>;</pre>
<p><a href="http://11011.net/software/vspaste"></a>The important takeaway from these two lines is that I used the HTTP POST method.&#160; I spent a bunch of time trying to use GET to make the logging happen, but it had two critical drawbacks:</p>
<ul>
<li>Every request would re-download the XAP, which was far more data than I wanted to transfer just to get logging going </li>
<li>WebRequest and WebClient both use the browser’s cache (and I couldn’t find a workaround that didn’t involve modifying the query string, which would have scuttled my approach), so repeat-visits to the same Page in the Silverlight application didn’t ever actually reach the server and get logged </li>
</ul>
<p>Finally:</p>
<pre class="code">wc.BeginGetResponse((res) =&gt;
{
    <span style="color: #2b91af">WebResponse </span>wr = wc.EndGetResponse(res);
}, <span style="color: blue">this</span>);</pre>
<p>This just shoots off the web request.&#160; There’s nothing particularly special here aside from noting that the response is entirely ignored.</p>
<p>&#160;</p>
<p><strong><em>And that’s it!</em></strong></p>
<p>&#160;</p>
<p>Here’s the proof, straight from my IIS logs (in W3C format… IP’s redacted):</p>
<div style="border-bottom: black thin solid; border-left: black thin solid; overflow-x: auto; white-space: nowrap; border-top: black thin solid; border-right: black thin solid">
<p>2009-05-13 04:41:06 POST /Samples/LoggedSilverlightNavigation/ClientBin/LoggedSilverlightNavigation.xap nav=%2FViews%2FAboutPage.xaml &#8211; &lt;IP Redacted&gt; HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+8.0;+Windows+NT+6.1;+WOW64;+Trident/4.0;+SLCC2;+.NET+CLR+2.0.50727;+.NET+CLR+3.5.30729;+.NET+CLR+3.0.30729;+Media+Center+PC+6.0) &#8211; 405 1496<br />
    <br />2009-05-13 04:41:06 GET / feed=rss2 &#8211; &lt;IP Redacted&gt; HTTP/1.1 Windows-RSS-Platform/2.0+(MSIE+8.0;+Windows+NT+6.1) &#8211; 304 475 </p>
<p>2009-05-13 04:41:06 POST /Samples/LoggedSilverlightNavigation/ClientBin/LoggedSilverlightNavigation.xap nav=%2FViews%2FHomePage.xaml &#8211; &lt;IP Redacted&gt; HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+8.0;+Windows+NT+6.1;+WOW64;+Trident/4.0;+SLCC2;+.NET+CLR+2.0.50727;+.NET+CLR+3.5.30729;+.NET+CLR+3.0.30729;+Media+Center+PC+6.0) &#8211; 405 1496 </p>
<p>2009-05-13 04:41:08 POST /Samples/LoggedSilverlightNavigation/ClientBin/LoggedSilverlightNavigation.xap nav=%2FViews%2FAboutPage.xaml &#8211; &lt;IP Redacted&gt; HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+8.0;+Windows+NT+6.1;+WOW64;+Trident/4.0;+SLCC2;+.NET+CLR+2.0.50727;+.NET+CLR+3.5.30729;+.NET+CLR+3.0.30729;+Media+Center+PC+6.0) &#8211; 405 1496 </p>
<p>2009-05-13 04:41:08 POST /Samples/LoggedSilverlightNavigation/ClientBin/LoggedSilverlightNavigation.xap nav=%2FViews%2FHomePage.xaml &#8211; &lt;IP Redacted&gt; HTTP/1.1 Mozilla/4.0+(compatible;+MSIE+8.0;+Windows+NT+6.1;+WOW64;+Trident/4.0;+SLCC2;+.NET+CLR+2.0.50727;+.NET+CLR+3.5.30729;+.NET+CLR+3.0.30729;+Media+Center+PC+6.0) &#8211; 405 1496</p>
</div>
<p>And more proof, from my 3rd party stats tool (ignore the large transfer sizes… they’re artifacts of my testing the GET method, which transferred a few hundred KB with each request):</p>
<p><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="AWStats Screenshot showing LoggedSilverlightNavigation.xap being queried" border="0" alt="AWStats Screenshot showing LoggedSilverlightNavigation.xap being queried" src="http://www.davidpoll.com/wp-content/uploads/2009/05/image1.png" width="593" height="167" />&#160;</p>
<p>If you’re curious to download the code (it’s not much more than what you’ve already seen!), you can find it here: <a href="http://www.davidpoll.com/Samples/Download/LoggedSilverlightNavigation.zip">LoggedSilverlightNavigation.zip</a></p>
<p>There’s definitely still room for improvement, though.&#160; One thing I’d like to get working eventually is setting the Referrer header on the HTTP request to a coherent value so that I can track <em>how</em> people get from page to page in my applications – but this is a good first step.</p>
<p>I hope you find that helpful!&#160; If anyone has any other suggestions/tips/tricks for navigation, feel free to let me know!&#160; This was just the result of my experimentation, so if you’ve got a better way, feel free to comment!</p>
<p>&#160;</p>
<p><strong><em>P.S.</em></strong> Still no correct responses to my Easter Egg hunt from my last post!&#160; Don’t give up!&#160; I’ll post the answer later this week.</p>
<p><strong><em>P.P.S. </em></strong>Mark Monster has a great post from a few months ago on his blog about <a href="http://mark.mymonster.nl/2009/02/15/tracking-silverlight-support-in-google-analytics/">tracking Silverlight support in Google Analytics</a>.&#160; I imagine you could use a similar technique to accomplish the type of logging I do here.</p>
<!-- Advanced AdSense by Jim Gaudet --><!-- google_ad_section_end -->]]></content:encoded>
			<wfw:commentRss>http://www.davidpoll.com/2009/05/12/logging-navigation-in-the-silverlight-3-beta/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

