<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.thecodeking.co.uk/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>The Code King</title><link>http://www.thecodeking.co.uk/</link><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.thecodeking.co.uk/co/izpV" /><description>the successful exploitation of new ideas, process, or way of thinking</description><language>en</language><managingEditor>noreply@blogger.com (TheCodeKing)</managingEditor><lastBuildDate>Fri, 10 May 2013 03:42:55 PDT</lastBuildDate><generator>Blogger http://www.blogger.com</generator><openSearch:totalResults xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">40</openSearch:totalResults><openSearch:startIndex xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">1</openSearch:startIndex><openSearch:itemsPerPage xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">25</openSearch:itemsPerPage><feedburner:info uri="co/izpv" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><title>Amazon AWSDeploy To Provision Multiple Websites</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/4AwRVzyD9m4/amazon-cloudformation-to-provision.html</link><category>Amazon</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 03 Feb 2013 23:04:22 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-1642347059980728451</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Recently I've been on a project where we are implementing BlueGreen deployments using Amazon CloudFormation, and came across a number of unanswered questions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How do you deploy multiple applications to a single instance and support auto-scaling?&lt;/li&gt;
&lt;li&gt;How do you deploy non-website applications using AWSDeploy?&lt;/li&gt;
&lt;li&gt;How can you pass in environmental config during provisioning?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official answer to the first 2 questions appears to be that you can't without additional scripts/tools. The third (with some caveats) is that you need to bake them into your package prior to your deployment.&lt;/p&gt;

&lt;p&gt;This seems frustrating for such common real world use cases, but luckily there is a solution which requires minimal effort.&lt;/p&gt;

&lt;h2&gt;First Some Background&lt;/h2&gt;

&lt;p&gt;CloudFormation is Amazon's offering for provisioning a collection of AWS resources on the amazon infrastructure through declarative templates. The collection of resources is known as a stack and can be used for reliable and repeatable infrastructure deployments.&lt;/p&gt;

&lt;p&gt;AWSDeploy is the tool which can be used with the Microsoft stack to provision CloudFormation templates and to deploy web applications onto these provisioned resources. This uses Microsoft WebDeploy under the hood, and as such a WebDeploy package must be provided when provisioning a CloudFormation stack using the tool.&lt;p&gt;

&lt;p&gt;The WebDeploy package provided by the user is uploaded to AWS by the tool and stored in an S3 bucket. When the EC2 web server spins up, AWSDeploy installs the package on the web server as part of initialising the stack. By default any failures will result in a stack rollback.&lt;/p&gt;

&lt;p&gt;Once a web application is provisioned via AWSDeploy, the stack will manage failover and auto-scaling scenarios automatically by redeploying the associated WebDepoy package stored on S3 to any new instances. In doing so it is able to manage resources hands-free and replicate perfect copies of your application on demand.&lt;/p&gt;

&lt;h2&gt;With Great Power Comes Great Limitations&lt;/h2&gt;

&lt;p&gt;As described above, AWSDeploy is incredibly useful for failover and scaling scenarios. Your web application can be replicated and auto-provisioned without manual interaction.&lt;/p&gt;

&lt;p&gt;The downside is a number of limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only 1 WebDeploy package can be associated with a web server instance&lt;/li&gt;
&lt;li&gt;No parameters can be passed when AWSDeploy installs the WebDeploy package&lt;/li&gt;
&lt;li&gt;As such WebDeploy parameterisation cannot be used for config transforms&lt;/li&gt;
&lt;li&gt;Environmental config is limited to a small set of pre-defined appSettings keys, which can be injected during provisioning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The impact is that to work with AWSDeploy you generally have to modify your build artifact for every deployment environment and bake in configuration settings. This is against Continuous Delivery principles and adds complexity to any deployment scripts.&lt;/p&gt;

&lt;h2&gt;An Idea&lt;/h2&gt;

&lt;p&gt;WebDeploy in it's own right is an extremely flexible and versatile tool. In a single WebDeploy package it's possible to deploy multiple websites, deploy directories of arbitrary files, execute commands, and change Acl permissions.&lt;/p&gt;

&lt;p&gt;So, instead of baking environment configuration into the WebDeploy packages to support AWSDeploy, why not instead create a wrapper WebDeploy package and use an embedded &lt;code&gt;RunCommand&lt;/code&gt; to pass environment variables to a child package during provisioning. In this way the original build artifact is unmodified and the full power of WebDeploy can be used to inject parameters during installation.&lt;/p&gt;

&lt;p&gt;This approach has additional benefits in that it allows the install of multiple web applications via a single AWSDeploy package, as well as the ability to deploy Windows Services and Console applications during auto-provisioning. Additionally it's then relatively easy to cheery-pick applications for deployment to a particular instance with very little rework of deployment scripts.&lt;/p&gt;

&lt;h2&gt;The Problem&lt;/h2&gt;

&lt;p&gt;On creating my first wrapper package I immediately ran into a problem when provisioning. The AWSDeploy logs revealed the issue.&lt;/p&gt;

&lt;pre class="brush: jscript"&gt;
ERROR 10 AWSDeploymentHostManager.Tasks.UpdateAppVersionTask - Deploy failed, not iisApp.
&lt;/pre&gt;

&lt;p&gt;It seems AWSDeploy expects the WebDeploy package to contain an &lt;code&gt;iisApp&lt;/code&gt; within it's manifest. So I included a stub website in my WebDeploy package and tried again. Surprisingly I hit the same error!&lt;/p&gt;

&lt;p&gt;After much investigation it turns out that when AWSDeploy executes the WebDeploy package, it passes the following parameter to the package. This is to enable customisation of the target IIS Website name during provisioning, and can be set via a AWSDeploy configuration setting.&lt;/p&gt;

&lt;pre class="brush: jscript"&gt;
-setParam:"IIS Web Application Name"="Default Web Site/"
&lt;/pre&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;

&lt;p&gt;Knowing the parameter requirement, the solution is simple. Provided the WebDeploy package contains a parameters file with this parameter defined within, then AWSDeploy will successfully deploy the package regardless of it's contents. It also means that the WebDeploy package does not actually need to include an &lt;code&gt;iisApp&lt;/code&gt; instance as the error first suggested.&lt;/p&gt;

&lt;h2&gt;Putting It All Together&lt;/h2&gt;

&lt;p&gt;First place any WebDeploy packages to be installed on the server instance in a folder called &lt;code&gt;C:\Packages&lt;/code&gt;. Include any set-parameter configuration files for any environmental settings and config transforms.&lt;/p&gt;  

&lt;p&gt;Create a PowerShell install script called &lt;code&gt;Install.ps1&lt;/code&gt; and add this to the &lt;code&gt;C:\Packages&lt;/code&gt; directory. The script will be executed on the server during provisioning. It will be used to deploy the WebDeploy packages in this folder on the server, and can be used to invoke explicit WebDeploy commands during install; such as to leverage environment specific parameterisation.&lt;/p&gt;

&lt;pre class="brush: jscript"&gt;
Set-Alias msdeploy "C:\Program Files\IIS\Microsoft Web Deploy V3\msdpeloy.exe"

msdeploy -verb:sync -source:package=WebsiteA.zip -dest:auto -setParamFile:WebSiteA-Params.xml
msdeploy -verb:sync -source:package=WebsiteB.zip -dest:auto -setParamFile:WebSiteB-Params.xml
&lt;/pre&gt;

&lt;p&gt;Next create the parameters file for inclusion in the WebDeploy wrapper package as follows. Name the file &lt;code&gt;parameters.xml&lt;/code&gt; and place it in a folder called &lt;code&gt;C:\Build&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;parameters&amp;gt;
 &amp;lt;parameter name="IIS Web Application Name" defaultValue="Default Web Site/" tags="IisApp" /&amp;gt;
&amp;lt;/parameters&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Now create a WebDeploy manifest file for the wrapper package as follows. This will provision the contents of &lt;code&gt;C:\Packages&lt;/code&gt; to the server instance and use the &lt;code&gt;RunCommand&lt;/code&gt; provider to execute the &lt;code&gt;Install.ps1&lt;/code&gt; PowerShell script in the root of this directory. Name the file &lt;code&gt;manifest.xml&lt;/code&gt; and place it in the &lt;code&gt;C:\Build&lt;/code&gt; folder.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;siteManifest&amp;gt;
  &amp;lt;contentPath path="C:\Packages" /&amp;gt;
  &amp;lt;runCommand path="%SystemRoot%\System32\WindowsPowerShell\v1.0\PowerShell.exe
       -inputformat none -command &amp;amp;quot;Set-ExecutionPolicy Unrestricted -force&amp;amp;quot;" 
       waitInterval="10000" /&amp;gt;
  &amp;lt;runCommand path="%SystemRoot%\System32\WindowsPowerShell\v1.0\PowerShell.exe 
       -inputformat none -command C:\Packages\Install.ps1" 
       waitInterval="300000" /&amp;gt;
&amp;lt;/siteManifest&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Finally package up the WebDeploy wrapper package using the command line as follows, which should be executed from the &lt;code&gt;C:\Build&lt;/code&gt; folder. The trick is the &lt;code&gt;declareParamFile&lt;/code&gt; parameter and &lt;code&gt;parameters.xml&lt;/code&gt; file which keeps AWSDeploy happy.&lt;/p&gt;

&lt;pre class="brush: jscript"&gt;
msdeploy -verb:sync -source:manifest=manifest.xml -dest:package=Deploy.zip
         -declareParamFile=parameters.xml
&lt;/pre&gt;

&lt;p&gt;The WebDeploy package produced is now ready to be used with the AWSDeploy tool to provision 1 or more applications on your EC2 server. It is also fully compatible with auto-scaling and failover scenarios.&lt;/p&gt;

&lt;p&gt;You can test the install locally by executing the following command in the &lt;code&gt;C:\Build&lt;/code&gt; directory.&lt;/p&gt;

&lt;pre class="brush: jscript"&gt;
msdeploy -verb:sync -source:package=Deploy.zip -dest:auto
&lt;/pre&gt;

&lt;h2&gt;Further Enhancements&lt;/h2&gt;

&lt;p&gt;The solution minimises the customisation of deployment scripts for different environments, and results in a solution much less coupled to Amazon AWSDeploy. It also works around the limitations of AWSDeploy and provides a much greater level of flexibility in how instances can be configured to support auto-provisioning.&lt;/p&gt;

&lt;p&gt;This is an improvement, but we are still having to build different artifacts per environment which is not ideal. A further enhancement would be to leverage AWS &lt;code&gt;UserData&lt;/code&gt; from within the PowerShell script. &lt;code&gt;UserData&lt;/code&gt; is configured during provisioning and made available to each server instance via a web service at a fixed address:

&lt;pre class="brush: jscript"&gt;
http://169.254.169.254/latest/user-data
&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;UserData&lt;/code&gt; is persisted during failover &amp; scaling, and could be used to either feed the PowerShell script entire set-parameter files dynamically, or provide flags to indicate to the PowerShell script which pre-deployed set-parameter file to use per environment when installing packages. In this way a single artifact could be used across all environments inline with best practice, as well as a single install and deployment script.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/4AwRVzyD9m4" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-04T07:04:22.646Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">5</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2013/02/amazon-cloudformation-to-provision.html</feedburner:origLink></item><item><title>XDMessaging 4.0</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/b-Wh1_z45HI/xdmessaging-net-library-20.html</link><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Tue, 12 Mar 2013 01:19:42 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-4065266097865087906</guid><description>&lt;div class="leftBox"&gt;
&lt;div class="downloadBoxTop"&gt;
XDMessaging .Net Library 4.0
&lt;br /&gt;
&lt;ul class="link"&gt;
&lt;li&gt;&lt;a href="https://github.com/TheCodeKing/XDMessaging.Net.git" target="_self"&gt;Project source&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul class="help"&gt;
&lt;li&gt;&lt;a href="http://thecodeking.github.com/XDMessaging.Net/" target="_self"&gt;Project documentation&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="https://github.com/TheCodeKing/XDMessaging.Net/archive/master.zip" target="_self"&gt;Download demo&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;The XDMessaging library provides an easy-to-use, zero configuration solution to inter-process communication for .NET applications. It provides a simple API for broadcasting and receiving messages across application domain, process, and even network boundaries.&lt;/p&gt;

&lt;p&gt;The library allows the use of user-defined pseudo channels through which messages may be sent and received. Any application can send a message to any channel, but it must register as a listener with the channel in order to receive. In this way developers can quickly and programmatically devise how their applications will communicate with each other best to work in harmony.&lt;/p&gt;

&lt;p&gt;The messages may optionally be propagated to other processes over a network automatically.&lt;/p&gt; &lt;!--&lt;div class="separator" style="float: right; margin-left: 1em; margin-top:1em; text-align: center;"&gt;
&lt;img border="0" src="http://2.bp.blogspot.com/_DZF2ziLToks/SyqmvtIvGmI/AAAAAAAAAjE/Wer3n0xgjqQ/s320/messaging-demo2.png" /&gt;&lt;/div&gt;--&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;Install the library using Nuget.&lt;/p&gt;
&lt;div class="nuget-badge"&gt;
&lt;p&gt;&lt;code&gt;PM&amp;gt; Install-Package XDMessaging&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Advantages&lt;/h2&gt;

&lt;p&gt;The XDMessaging library offers some advantages over other IPC technologies like WCF, .Net Remoting, Sockets, NamedPipes and MailSlots. To begin with the library does not require a server-client relationship as there is no physical connection between processes.&lt;/p&gt;

&lt;p&gt;With XDMessaging messages can be broadcast by multiple applications and instantly received by multiple listeners in a disconnected fashion. It's also worth noting that most of the existing IPC implementations require the opening of specific ports and somewhat painful configuration of settings to make work. With XDMessaging there is no configuration, the API determines where messages are sent, and which messages are received using pseudo channels.&lt;/p&gt;

&lt;h2&gt;Network Propagation&lt;/h2&gt;

&lt;p&gt;Network propagation is a feature of the library that allows messages to leverage &lt;code&gt;HighPerformanceUI&lt;/code&gt; or &lt;code&gt;Compatibility&lt;/code&gt; modes, whilst additionally distributing messages to a remote server. &lt;code&gt;RemoteNetwork&lt;/code&gt; mode is used under the hood to transfer messages to disconnected servers, and messages are rebroadcast by a slave &lt;code&gt;IXDListener&lt;/code&gt; instance using the original transport mode. If the slave instance terminates for any reason, then another listener instance will automatically take it’s place.&lt;/p&gt;

&lt;img border="0" src="http://3.bp.blogspot.com/-2rbE7IcwywA/UT7ifU4Rx0I/AAAAAAAAAwc/zQaptxGjF70/s1600/XDMessaging.png" style="border: 0px;" /&gt;

&lt;h2&gt;Using the Library&lt;/h2&gt;

&lt;p&gt;To use the library, create an instance of a &lt;code&gt;IXDBroadcaster&lt;/code&gt; and use this to send a message to a named &lt;em&gt;channel&lt;/em&gt;. You can then create an instance of &lt;code&gt;IXDListener&lt;/code&gt; to receive messages on a particular &lt;em&gt;channel&lt;/em&gt;. The channels are arbitrary strings chosen to represent a channel, and are not case sensitive.
Before creating the broadcaster and listener instances you must first decide which transport mode you want to use for the library. There are 3 modes as follows and each has advantages over the other. Modes are abstracted from their specific implementations for extensibility, and loosely coupled. In order to use one of the modes the appropriate assembly must be referenced in the project in addition to &lt;code&gt;XDMessaging&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Transport Modes&lt;/h4&gt;

&lt;ul class="wideList"&gt;
&lt;li&gt;&lt;b&gt;Compatibility&lt;/b&gt;: The default implementation uses file based IO to broadcast messages via a shared directory. A &lt;code&gt;FileSystemWatcher&lt;/code&gt; is used within listener classes to monitor changes and trigger the &lt;code&gt;MessageReceived&lt;/code&gt; event containing the broadcast message. This mode can be used in Windows Services, console applications, and Windows Forms based applications. Channels are created as separate directories on the file system for each channel. The temporary directories should be accessible by all processes, and there should be no need for manual configuration. To use this implementation add a reference to &lt;code&gt;XDMessaging.Transport.IOStream&lt;/code&gt; in your project.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;HighPerformanceUI&lt;/b&gt;: The default&amp;nbsp;implementation&amp;nbsp;uses the &lt;code&gt;WM_COPYDATA&lt;/code&gt; Windows Message to copy data between applications. The broadcaster implementation sends the Windows Messages directly to a hidden window on the listener instance, which dispatches the &lt;code&gt;MessageReceived&lt;/code&gt; event with the copied data. Channels are created by adding/removing Windows properties. This offers the most performant solution for Windows Forms based applications, but does not work for Windows Services, Console apps, or other applications without a message pump. To use this implementation add a reference to &lt;code&gt;XDMessaging.Transport.WindowsMessaging&lt;/code&gt; in your project.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RemoteNetwork&lt;/b&gt;: By default this uses &lt;code&gt;Amazon Web Services&lt;/code&gt; to implement a subscriber/publisher implementation for broadcasting messages over a network and interprocess. There may be associated costs involved in using this mode, and you will need to supply valid Amazon account credentials. This mode is used internally to send messages from other transport modes over the network when using network propagation mode. To use this implementation add a reference to &lt;code&gt;XDMessaging.Transport.Amazon&lt;/code&gt; in your project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: Messages broadcast using a particular mode can only be read by applications using a listener in the same mode. For example, &lt;code&gt;Compatibility&lt;/code&gt; listeners cannot read messages broadcast in the &lt;code&gt;HighPerformanceUI&lt;/code&gt; mode. It is possible to broadcast in several modes at the same time, see documentation for further details.
See the included sample applications for more information on using the library in Windows Forms applications or within a Windows Service.&lt;/p&gt;

&lt;h2&gt;Messaging Demo&lt;/h2&gt;

&lt;p&gt;Download the source code and demo application from &lt;a href="https://github.com/TheCodeKing/XDMessaging.Net.git" target="_self"&gt;GitHub&lt;/a&gt;. Refer to &lt;a href="http://thecodeking.github.com/XDMessaging.Net/" target="_self"&gt;user guide&lt;/a&gt; for more information.&lt;/p&gt;

&lt;img border="0" src="http://2.bp.blogspot.com/_DZF2ziLToks/SyqmvtIvGmI/AAAAAAAAAjE/Wer3n0xgjqQ/s320/messaging-demo2.png" style="border: 0px"/&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/b-Wh1_z45HI" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2013-03-12T08:19:42.362Z</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_DZF2ziLToks/SyqmvtIvGmI/AAAAAAAAAjE/Wer3n0xgjqQ/s72-c/messaging-demo2.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">39</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/12/xdmessaging-net-library-20.html</feedburner:origLink></item><item><title>Twitter OAuth authentication using .Net</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/20CeI-a9U0g/twitter-oauth-authentication-using-net.html</link><category>C# .Net</category><category>Twitter</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Mon, 29 Aug 2011 15:52:30 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-1309954450679602359</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
        &lt;p&gt;Source Code&lt;/p&gt;
          &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk.s3.amazonaws.com/software/twitteroauth/TwitterOAuth.zip"
                    target="_self" onclick="javascript:urchinTracker('/downloads/TwitterOAuth.zip');"&gt;TwitterOAuth.zip&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In this article I want to demonstrate how to implement OAuth authentication in .Net. I've &lt;a href="http://www.thecodeking.co.uk/2011/07/great-social-change.html"&gt;previously written&lt;/a&gt; about my dislike of third party SDKs for social media integration and how we should leverage technology based solutions instead. One of the sticking points in doing this tends to be that implementing OAuth based authentication is relatively difficult compared with actually  making the requests themselves. There is documentation available, but there seems to be a lack of .NET example code to go with it.&lt;/p&gt;

&lt;p&gt;In keeping with my thoughts in previous articles I would recommend using open source OAuth based libraries to solve this problem, and again avoid resorting to third party Twitter/Facebook implementations which more strongly couple code to specific APIs. This keeps the solution more reusable and builds on specific technologies to better future proof your application.&lt;/p&gt;

&lt;p&gt;I've also &lt;a href="http://www.thecodeking.co.uk/2011/07/facebook-integration-via-hammock.html"&gt;previously shown&lt;/a&gt; how client-side plugins can be used in combination with server-side code to speed development in this area. However sometimes authentication does need to be implemented purely on the server-side.&lt;/p&gt;

&lt;p&gt;So how difficult is this?&lt;/p&gt;

&lt;p&gt;It turns out implementing OAuth on the server-side in .Net isn't too difficult, the battle is getting the encoding and authentication signature right. With so few examples it can be a little daunting, so here's an example written in pure .NET using the official &lt;a href="https://dev.twitter.com/docs/auth/oauth"&gt;Twitter OAuth documentation&lt;/a&gt; and a bit of trial and error.&lt;/p&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;The following example shows how to authenticate against the Twitter APIs using a registered &lt;a href="https://dev.twitter.com/"&gt;Twitter application&lt;/a&gt;. Any interaction with the APIs when authenticated in this manner will behave as if coming from the Twitter account under which the application has been registered. It's therefore useful for sending out status updates or sending out notifications from a specific account.&lt;/p&gt;   

&lt;p&gt;Usually OAuth requires redirecting the user to a login screen to obtain an oAuth token which requires a bit more work. However when authenticating via a Twitter application this step is skipped as your application already has an oAuth token provided (access token). Whether you are using the application oAuth token or a user oAuth token, the following code can be used to authenticate against the twitter APIs.&lt;/p&gt;

&lt;h2&gt;The Code&lt;/h2&gt;

&lt;p&gt;The first step is to visit the &lt;a href="https://dev.twitter.com/"&gt;Twitter developer&lt;/a&gt; section and register a new application. On completion you will be provided with a set of public/private keys which you will need the replace in the example below in order to run. The values I have used directly correspond with the documented example &lt;a href="https://dev.twitter.com/docs/auth/oauth#Making_a_resource_request_on_a_user-s_behalf"&gt;here&lt;/a&gt;. Make sure you replace them with your own.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var oauth_token           = "819797-Jxq8aYUDRmykzVKrgoLhXSq67TEa5ruc4GJC2rWimw";
var oauth_token_secret    = "J6zix3FfA9LofH0awS24M3HcBYXO5nI1iYe8EfBA";
var oauth_consumer_key    = "GDdmIQH6jhtmLUypg82g";
var oauth_consumer_secret = "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98";
&lt;/pre&gt;

&lt;p&gt;We also need to define some details about the request. This includes a unique &lt;code&gt;oauth_nonce&lt;/code&gt; parameter which must be generated per request, and a timestamp.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var oauth_version          = "1.0";
var oauth_signature_method = "HMAC-SHA1";
var oauth_nonce            = Convert.ToBase64String(
                                  new ASCIIEncoding().GetBytes(
                                       DateTime.Now.Ticks.ToString()));
var timeSpan               = DateTime.UtcNow
                                  - new DateTime(1970, 1, 1, 0, 0, 0, 0,
                                       DateTimeKind.Utc);
var oauth_timestamp        = Convert.ToInt64(timeSpan.TotalSeconds).ToString();
var resource_url           = "http://api.twitter.com/1/statuses/update.json";
var status                 = "Updating status via REST API if this works";
&lt;/pre&gt;

&lt;p&gt;The next step is to generate an encrypted oAuth signature which Twitter will use to validate the request. To do this all of the request data is concatenated into a particular format as follows.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var baseFormat = "oauth_consumer_key={0}&amp;oauth_nonce={1}&amp;oauth_signature_method={2}" +
                "&amp;oauth_timestamp={3}&amp;oauth_token={4}&amp;oauth_version={5}&amp;status={6}";

var baseString = string.Format(baseFormat,
                            oauth_consumer_key,
                            oauth_nonce,
                            oauth_signature_method,
                            oauth_timestamp,
                            oauth_token,
                            oauth_version,
                            Uri.EscapeDataString(status)
                            );

baseString = string.Concat("POST&amp;", Uri.EscapeDataString(resource_url), "&amp;", Uri.EscapeDataString(baseString));
&lt;/pre&gt;

&lt;p&gt;Using this base string we then encrypt the data using a composite of the secret keys and the &lt;code&gt;HMAC-SHA1&lt;/code&gt; algorithm.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
                        "&amp;",  Uri.EscapeDataString(oauth_token_secret));

string oauth_signature;
using (HMACSHA1 hasher = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(compositeKey)))
{
    oauth_signature = Convert.ToBase64String(
        hasher.ComputeHash(ASCIIEncoding.ASCII.GetBytes(baseString)));
}
&lt;/pre&gt;

&lt;p&gt;The oAuth signature is then used to generate the Authentication header. This requires concatenating the public keys and the token generated above into the following format.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var headerFormat = "OAuth oauth_nonce=\"{0}\", oauth_signature_method=\"{1}\", " +
                   "oauth_timestamp=\"{2}\", oauth_consumer_key=\"{3}\", " +
                   "oauth_token=\"{4}\", oauth_signature=\"{5}\", " +
                   "oauth_version=\"{6}\"";

var authHeader = string.Format(headerFormat,
                        Uri.EscapeDataString(oauth_nonce),
                        Uri.EscapeDataString(oauth_signature_method),
                        Uri.EscapeDataString(oauth_timestamp),
                        Uri.EscapeDataString(oauth_consumer_key),
                        Uri.EscapeDataString(oauth_token),
                        Uri.EscapeDataString(oauth_signature),
                        Uri.EscapeDataString(oauth_version)
                );
&lt;/pre&gt;

&lt;p&gt;We are now ready to send the request, which is the easy part. Note we must also disable the &lt;code&gt;Expect: 100-Continue&lt;/code&gt; header using the &lt;code&gt;ServicePointManager&lt;/code&gt;. Without this code the .Net sends the header by default which is not supported by Twitter.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var postBody = "status=" + Uri.EscapeDataString(status);

ServicePointManager.Expect100Continue = false;

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resource_url);
request.Headers.Add("Authorization", authHeader);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
using (Stream stream = request.GetRequestStream())
{
    byte[] content = ASCIIEncoding.ASCII.GetBytes(postBody);
    stream.Write(content, 0, content.Length);
}
WebResponse response = request.GetResponse();
&lt;/pre&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;This example hopefully shows how OAuth can be implemented with fairly little effort. In the example provided I've kept everything inline for clarity, however in the real world you would obviously refactor the code into more sensible layers.&lt;/p&gt;
 
&lt;p&gt;In this way it's possible to build some highly testable lightweight classes in order to generate the required message signature, make the requests, and handle the response.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/20CeI-a9U0g" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-29T23:52:30.145+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/08/twitter-oauth-authentication-using-net.html</feedburner:origLink></item><item><title>ASP.NET Session End event fires immediately after Session Start - Resolved</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/QJuBBcLDIq4/why-sessionend-is-sometimes-called.html</link><category>ASP.NET</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 28 Aug 2011 12:06:35 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-6928897392243449625</guid><description>&lt;h2&gt;The Question&lt;/h2&gt;

&lt;p&gt;Whilst browsing StackOverflow I came across an old &lt;a href="http://stackoverflow.com/questions/2236129/asp-net-large-number-of-session-start-with-same-session-id"&gt;unanswered question&lt;/a&gt; from Feb 10 which caught my eye.&lt;/p&gt;

&lt;p&gt;At first I was quick to dismiss it as nonsense, but then I started looking into it further and became interested. It seems a lot of people are reporting an issue whereby &lt;code&gt;Session_End&lt;/code&gt; is sometimes called immediately after &lt;code&gt;Session_Start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This can be reproduced in .NET 2.0/3.5 using the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a new .Net 2.0 WebForms WebApplication&lt;/li&gt;
&lt;li&gt;Configure session for InProc, and set the timeout to 1 minute&lt;/li&gt;
&lt;li&gt;Add a break point on Session_Start and Session_End events&lt;/li&gt;
&lt;li&gt;Debug the application and F5 to skip the first Session_Start break point&lt;/li&gt;
&lt;li&gt;Wait until the Session_End fires after 1 minute&lt;/li&gt;
&lt;li&gt;Refresh the browser, and notice Session_End is called immediately after Session_Start&lt;/li&gt;
&lt;li&gt;Note that adding a session variable to the page OnLoad solves the issue&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;According to &lt;a href="http://msdn.microsoft.com/en-us/library/ms178583.aspx" target="_BLANK"&gt;documentation&lt;/a&gt;, there are 2 activities that can cause the Session_End event to fire.&lt;/p&gt;


&lt;li&gt;When Session.Abandon() is called&lt;/li&gt;
&lt;li&gt;Immediately after the Session expires&lt;/li&gt;

&lt;p&gt;In this example neither are true. So how can this be?&lt;/p&gt;

&lt;h2&gt;The Answer&lt;/h2&gt;

&lt;p&gt;Doing some research on the internet I found a clue in a &lt;a href="http://erlend.oftedal.no/blog/?blogid=41" target="_BLANK"&gt;blog post&lt;/a&gt; on session state. It revealed an interesting quirk about how session state is handled.&lt;/p&gt;

&lt;p&gt;This is that ASP.NET will only create a new InProc session if the session is actually used by the application. If not then the session is not persisted, and it will not even issue a session cookie (where it doesn't already exist).&lt;/p&gt;

&lt;p&gt;So here's what's happening.&lt;/p&gt;

&lt;p&gt;When the browser is refreshed after the session timeout, the old session cookie is sent in the request. This causes ASP.NET to reuse the original session ID for a new session. However because at the end of the request the application has not yet used the session, ASP.NET affectively abandons it to avoid persistance and to free resources. This causes an early Session_End event.&lt;/p&gt;

&lt;p&gt;Now because ASP.NET does not actually delete the pre-existing session cookie, every subsequent request is essentially restarting the session ID and repeating the sequence of events, such that Session_Start/Session_End are fired repeatedly until either the session is used or the cookie deleted.&lt;/p&gt;

&lt;h2&gt;The Fix&lt;/h2&gt;

&lt;p&gt;The issue has already been resolved in .NET 4.0. I suspect the session now remains persisted in the case of a session restart.&lt;/p&gt;

&lt;p&gt;If your application is using .NET 2.0/3.5 and has expensive code hooked into the session start/end events, then I recommend you add a dummy session variable to your session start routine. This solves the problem by flagging the session as in use, and helps protect your server resources from excessive session events.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/QJuBBcLDIq4" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-28T20:06:35.080+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/08/why-sessionend-is-sometimes-called.html</feedburner:origLink></item><item><title>Children Of The Social Revolution</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/J4Ovt1t6jlQ/children-of-social-revolution.html</link><category>Social Media</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 31 Jul 2011 12:56:50 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-2464392779336542649</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;div class="separator" style="clear: both; text-align: center; float: right;"&gt;
&lt;img border="0" height="200" width="200" src="http://2.bp.blogspot.com/-OO5MLCNG21U/TjCOMjGNqfI/AAAAAAAAAqc/2hfq6CplYg8/s200/183836_stock-photo-global-network-of-people.jpg" style="border: 0px; margin-left: 10px;" /&gt;&lt;/div&gt;

&lt;p&gt;The social revolution is upon us, and we are all a part of it. Within our generation the world has changed. Individuals now form vast community networks which span the globe, and social media is prolific.&lt;/p&gt;

&lt;p&gt;In the past decade the balance of power has shifted to the consumer through the uptake in social media. It affects how we search for content, how we consume content, and how we increasingly hold corporations accountable.&lt;/p&gt;

&lt;h2&gt;Beyond Our Origins&lt;/h2&gt;

&lt;p&gt;Facebook was the first player to take social media mainstream after it launched in 2004, but it wasn't the first of it's kind. Sites such as SixDegrees were around in the late 90s and many more niche sites briefly gained notoriety around the same time such as FaceParty in the UK; a site at one time more popular than eBay or Amazon with 7 million users&lt;sup id="cite_ref-1" class="reference"&gt;&lt;a href="#cite_ref-1"&gt;&lt;span&gt;[&lt;/span&gt;1&lt;span&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Before the newer generation of social networking sites, users were constrained to smaller isolated communities built around forums, newsgroups and IRC (Internet Relay Chat). Before these it all started with BBS (bulletin board system); a rudimentary system for exchanging data over dial-up connections in the 70s.&lt;/p&gt;

&lt;p&gt;Even before wide availability of computers in the household in the 50s, underground groups came together through the phenomenon of phreaking. Originally involving exploits in the analog phone system, it allowed individuals to route free calls with home made electronic devices such as blue boxes. As well as being used for pranking, notably by the Apple founders Steve Wozniak and Steve Jobs, phreaking became a social outlet not constrained by physical location&lt;sup id="cite_ref-2" class="reference"&gt;&lt;a href="#cite_ref-2"&gt;&lt;span&gt;[&lt;/span&gt;2&lt;span&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;. In doing so small communities formed in the darkness via a network of party lines and long distance calls.&lt;/p&gt;

&lt;p&gt;Going back even further amateur radio also allowed people to span great distances more legitimately, and formed niche communities from as early as the 20th century. What distinguishes this use of technology from the common telephone is that people were drawn together through common interests, rather than being centered around those already known to them.&lt;/p&gt;

&lt;p&gt;It seems the human desire to reach out and form communities is in our DNA. It is the secret to our evolutionary success, yet it’s technology that empowers us beyond our humble origins. It not only gives us a voice, but ensures we are heard.&lt;/p&gt;

&lt;h2&gt;The Evolution Of Social&lt;/h2&gt;

&lt;p&gt;What’s interesting to observe looking back is how social media has evolved both in terms of acceptance within our society and in terms of the technology that takes it forward.&lt;/p&gt;

&lt;p&gt;First the audience has changed. From the early days in the 70s, 80s, and 90s there was generally a stereotypical stigma attached to those who participated in the practice of online socialising. This stigma existed across all age groups with even young teenagers snubbing the practice. Slowly over generations as technology became increasingly more accessible and more integrated into everyday life the stigma dissipated. Online dating and gaming has helped take acceptance into new age groups and today social media is the norm embracing all generations. Within just the last year my entire family is now on Facebook, and I’m sure most of yours are too.&lt;/p&gt;

&lt;p&gt;What this means is there are now almost no social boundaries left within the industry, at least within the western world. This makes it a huge market to tap into and puts the onus on the big players to gain our trust and keep us onside. In return they glean revenue from billions of page views via carefully positioned advertising.&lt;/p&gt;

&lt;p&gt;The other interesting observation is that it’s not the older more established sites that are the most successful today. Instead it’s the youngest sites which have used smarter technologies and learnt from the failings of others that thrive, toppling the once dominating leaders in their wake. At the time of writing GooglePlus has just launched and already seeing unprecedented widespread adoption that could fast become a real threat to Facebook. It has already gained 20 million users in the first 3 weeks to become the fastest growing network of it’s kind&lt;sup id="cite_ref-3" class="reference"&gt;&lt;a href="#cite_ref-3"&gt;&lt;span&gt;[&lt;/span&gt;3&lt;span&gt;]&lt;/span&gt;&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;h2&gt;Social Power&lt;/h2&gt;

&lt;p&gt;It’s truly a fierce and highly competitive market which has changed the way social media engages with us. As a result it empowers consumers to heavily influence functional design based on our evolving expectations over privacy and security concerns. Through this process we have already achieved much greater transparency over how our data is shared. On platforms such as Facebook for instance, we no longer get rogue applications spamming our feeds with notifications at every conceivable opportunity. Instead third party apps are now relegated to the edges where they can only solicit our data.&lt;/p&gt;

&lt;p&gt;Besides evolving with us, social media also empowers us beyond the platform. By giving us a voice and allowing us to form these vast social networks, it is changing the internet as we know it. Today the digital consumer is king. Any bad experiences can be instantly shared with thousands, retweeted, liked, and +1 to the masses. Suddenly our opinions matter. In the same way that advertising spreads it’s idealistic branding that companies spend millions to promote, social chatter is beginning to spread a more realistic viewpoint based on real experiences. Increasingly every customer interaction is key; both online and in the physical world.&lt;/p&gt;

&lt;p&gt;Likewise whereas search engines were once the most important avenue for driving traffic and promoting brands, online social communities are now establishing their own independent content streams through content sharing. This is becoming a process of natural selection where popular content is not necessarily based on search placement.&lt;/p&gt;

&lt;p&gt;Social media is the future of digital. It evolves with us, and it empowers us. We are truly children of the social revolution, and together through these online hubs we shape the future.&lt;/p&gt;

&lt;b&gt;References&lt;/b&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a name="cite_ref-1"&gt;^1&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Faceparty"&gt;Wikipedia, Hitwise / ABC (Audit Bureau of Circulations UK)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a name="cite_ref-2"&gt;^2&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/IWoz"&gt;iWoz: From Computer Geek to Cult Icon: How I Invented the Personal Computer, Co-Founded Apple, and Had Fun Doing It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a name="cite_ref-3"&gt;^3&lt;/a&gt; &lt;a href="http://www.telegraph.co.uk/technology/google/8655358/Google-attracts-20-million-users-in-first-3-weeks.html"&gt;Telegraph, Google+ attracts 20 million users in first 3 weeks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/J4Ovt1t6jlQ" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-31T20:56:50.158+01:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-OO5MLCNG21U/TjCOMjGNqfI/AAAAAAAAAqc/2hfq6CplYg8/s72-c/183836_stock-photo-global-network-of-people.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/07/children-of-social-revolution.html</feedburner:origLink></item><item><title>Facebook Integration via Hammock</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/eWDZuhnee3E/facebook-integration-via-hammock.html</link><category>C# .Net</category><category>Social Media</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Tue, 30 Aug 2011 05:00:31 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-5083311791275101309</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
        &lt;p&gt;Source Code&lt;/p&gt;
          &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk.s3.amazonaws.com/software/facebookdemo/FacebookDemo.zip"
                    target="_self" onclick="javascript:urchinTracker('/downloads/FacebookDemo.zip');"&gt;FacebookDemo.zip&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Recently, I wrote about &lt;a href="http://www.thecodeking.co.uk/2011/07/great-social-change.html"&gt;Social Media and strategies for integration&lt;/a&gt;. I intentionally didn't go into detail as I wanted to take a more philosophical view on our development processes. I made the distinction between frameworks where community driven libraries thrive, and evolving APIs where they often become the kiss of death for projects.&lt;/p&gt;

&lt;p&gt;I believe we need to change the way we work with Social Media APIs and stop trying to create SDKs for these APIs in the technology of our choice. The technologies evolve too quickly and instead we need to embrace the core technologies, whilst keeping the integration layers lightweight.&lt;/p&gt;

&lt;p&gt;In this article, I want to give an example of one approach by demonstrating some integration with Facebook. The key point here is that rather than using one of the many .NET libraries which wrap Facebook APIs, I'm instead using a generic library that is entirely decoupled from the Facebook APIs themselves.&lt;/p&gt;

&lt;h2&gt;Hammock - REST, easy&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/danielcrenna/hammock" target="_BLANK"&gt;Hammock&lt;/a&gt; is an open source project built in .NET which facilitates the consumption of RESTFul services in a generic way. It offers support for asynchronous operation, query caching, mocking, and rate limiting among other features. There are of course other libraries which could equally be used.&lt;/p&gt;

&lt;h2&gt;The Code&lt;/h2&gt;

&lt;p&gt;The following shows an example of retrieving posts from a user's wall in ASP.NET. We could achieve the same functionality through JavaScript alone, but let's assume we want to do something with the data on the server. This requires that the user has granted the &lt;code&gt;read_stream&lt;/code&gt; permission to the Facebook application and assumes the user is authenticated. In the source code provided, I've shown how to achieve both of these tasks using Social Plugins and JavaScript with minimal effort.&lt;/p&gt;

&lt;p&gt;The first thing we need to do is create an instance of Hammock's &lt;code&gt;RestClient&lt;/code&gt; class. This contains the base URI of the service EndPoint and can also contain other default properties such as a UserAgent string.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
IRestClient client = new RestClient
{
 Authority = "https://graph.facebook.com/",
 UserAgent = "MyFacebookApp"
};
&lt;/pre&gt;

&lt;p&gt;Next we create an instance of Hammock's &lt;code&gt;RestRequest&lt;/code&gt; class. This allows us to make RESTFul calls to a particular path relative to the base EndPoint URI defined above. Using Hammock's API it's then simple to add request parameters to the call. In this case, the user's &lt;code&gt;access_token&lt;/code&gt; is appended to the querystring to provide the required authorization.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// call https://graph.facebook.com/[userid]/feed
var request = new RestRequest
{
 Path = string.Concat(UserId, "/feed"),
 Method = WebMethod.Get
};
request.AddParameter("access_token", AccessToken);
&lt;/pre&gt;

&lt;p&gt;Note the &lt;code&gt;UserId&lt;/code&gt; and &lt;code&gt;AccessToken&lt;/code&gt; values shown in the sample above are obtained from the currently authenticated Facebook user. In the source code provided, I'm passing these values from an ajax call triggered by a Social Plugin login event.&lt;/p&gt;

&lt;p&gt;OK so far it's easy right? Any changes to the Facebook API means we can quickly add or remove parameters that are sent to the API.&lt;/p&gt;

&lt;p&gt;The next step is to make the request and parse the response. This is done using the &lt;code&gt;RestClient&lt;/code&gt; we created earlier.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
var response = client.Request(request);

// check for errors and do something
if (response.StatusCode != HttpStatusCode.OK)
{
 throw new CommunicationException(
  string.Format("The EndPoint {0}{1} returned an unexpected StatusCode {2}",
  client.Authority, client.Path, response.StatusCode));
}

// this is the raw JSON response
var content = response.Content;
&lt;/pre&gt;

&lt;p&gt;OK, so now the interesting bit, and this is where I come back to my point about keeping this lightweight and loosely coupled. We could use Hammock's deserializer to type the response directly to our own object, but that's too rigid for my liking. Instead I want to use the dynamic type. This will allow us to access the JSON properties in a loose fashion which can more easily be changed if the API is updated.&lt;/p&gt;

&lt;p&gt;Now I couldn't figure out how to get Hammock's out-of-box deserialization to work with dynamic objects. It may be possible, and if anyone knows, please let me know. Instead I created my own &lt;code&gt;JavaScriptConverter&lt;/code&gt; extension so I can use .NETs in-built &lt;code&gt;JavaScriptSerializer&lt;/code&gt; class. You could also register your own custom deserialization classes via Hammock's interfaces but I've kept it simple.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// set up deserialization classes
JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new JsonConverter() });

// deserialize the raw JSON
dynamic result = serializer.Deserialize&amp;lt;ExpandoObject&amp;gt;(response.Content);

// parse the results 
foreach (dynamic obj in result.data)
{
 Response.Write(obj.from.name + " wrote " + obj.message);
}
&lt;/pre&gt;

&lt;h2&gt;Static vs Dynamic Typing&lt;/h2&gt;

&lt;p&gt;The nice thing about &lt;code&gt;ExpandoObject&lt;/code&gt; is that not only does it provide dynamic access to the response object to keep it loosely coupled, but it also implements &lt;code&gt;IDictionary&amp;lt;string, object&amp;gt;&lt;/code&gt;. This means it can easily be converted to a typed object using &lt;code&gt;JavaScriptSerializer&lt;/code&gt;. This is useful if we decide to move the code into a service layer and want to provide a strong typed model to our business layer. Only properties that are defined on both source and target will be mapped across in the conversion, other properties are simply ignored.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// define a class for post content
public class Post
{
 public string Id { get; set; }
 public string Message { get; set; }
}

foreach (var obj in result.data)
{
 // convert ExpandoObject to the Post class
 var post = serializer.ConvertToType&lt;Post&gt;(obj);

 // we now have strong typed access to content
 var message = post.Message;
}
&lt;/pre&gt;

&lt;h2&gt;Running The Demo&lt;/h2&gt;

&lt;p&gt;To run the demo code included, you should replace the Facebook &lt;code&gt;AppId&lt;/code&gt; in value &lt;code&gt;FBHelper&lt;/code&gt; class with your own Facebook application key. See Facebook documentation for more details on how to obtain this.&lt;/p&gt;

&lt;p&gt;You will notice in the source code provided, that I've created a custom expando class called &lt;code&gt;JsonExpandoObject&lt;/code&gt;. This is because &lt;code&gt;ExpandoObject&lt;/code&gt; throws exceptions if you try to access a property that doesn't exist. My version returns null instead and therefore works much better with JSON.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;So to summarize, generic third party libraries such as Hammock can be used to speed integration with Social Media APIs. This has the advantage over third party Social Media SDKs in that it keeps the codebase more loosely coupled. In doing so, it allows developers to build applications around long established core technologies and produces a codebase more adaptive to change.&lt;/p&gt;

&lt;p&gt;By implementing late binding via dynamic types, you can further decouple hard dependencies on APIs. This is particularly useful for lightweight manipulation of content within the data layer. For passing objects to the business layer, I've shown how &lt;code&gt;JavaScriptSerializer&lt;/code&gt; can be used to quickly convert dynamic types into static types as required.&lt;/p&gt;

&lt;p&gt;Static types are of course checked at compile time and offer many advantages over dynamic types. The trick here is that we are able to leverage static types in our business layer, but map/convert from objects which are late-bound to API code. This mapping/conversion code becomes the single touch point for maintenance when APIs change.&lt;/p&gt;

&lt;p&gt;The example included also shows how we can leverage the emerging Social Plugins and JavaScript APIs which are more resilient to change. These can be used for core functionality and should always be favoured where possible.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/eWDZuhnee3E" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-08-30T13:00:31.130+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/07/facebook-integration-via-hammock.html</feedburner:origLink></item><item><title>Twitter The Undiscovered Truth</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/dybJkW4LlXs/why-hot-girls-follow-me.html</link><category>Social Media</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Thu, 14 Jul 2011 13:05:13 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-6461702104316035487</guid><description>&lt;h2&gt;Suspect Activity Detected&lt;/h2&gt;

&lt;div class="separator" style="float: right"&gt;
&lt;img border="0" height="167" width="374" src="http://2.bp.blogspot.com/-6JaC6T_Lijo/Th4IDccUMuI/AAAAAAAAApU/OwVb7Q_2wOg/s400/Screen%2Bshot%2B2011-07-13%2Bat%2B22.01.39.png" /&gt;&lt;/div&gt;

&lt;p&gt;Here's a thought. I recently became active on Twitter. Having never really used it before I thought I should embrace the technology in order to help me better understand what is quickly becoming my industry.&lt;/p&gt;

&lt;p&gt;Within 3 days I have about 40 followers. Fair enough I posted my Twitter name on various sites and I expect to get some followers who might be interested in my articles. But here's the thing, I'm getting an usual amount of &lt;i&gt;young ladies&lt;/i&gt; following me and I have to wonder why.&lt;/p&gt; 

&lt;p&gt;Yes I know what you're thinking, but even with my good looks I'm still a geek writing about geeky things. So why on earth would an 18 year old &lt;i&gt;babe&lt;/i&gt; from California be interested in anything I have to say?&lt;/p&gt;

&lt;h2&gt;A Pessimist's Theory&lt;/h2&gt;

&lt;p&gt;So heres my pessimistic theory. If I were a shrewd entrepreneur who saw an opportunity to provide Twitter accounts pre-populated with followers in the magnitude of 10s of thousands of users, then here's what I'd do.&lt;/p&gt;

&lt;p&gt;I'd write a bot to harvest Twitter user accounts by auto following users just often enough to stay under the radar. I'd set up that follower account with pictures of hot girls with names like Thumper and Sandy and give them cute profiles like "I love lollipops" and "looking to make friends".&lt;/p&gt;

&lt;p&gt;For every 5 accounts I follow I'd probably get about 3 follow me back. Over time my accounts would ripen and be ready for market. A quick change in username, picture and profile, and I'd be ready to cash in the account to some high flying exec for $$$. A CEO profile to boast status, power, and influence among their peers, or a powerful marketing tool providing an instant voice to 1000s.&lt;/p&gt;

&lt;h2&gt;The Million Dollar Question&lt;/h2&gt;

&lt;p&gt;Now it's just a theory, and it could well be I'm just too damn good looking for my own good, who's to say! However a quick search for &lt;a href="http://www.google.co.uk/search?q=twitter+accounts+for+sale" target="_BLANK"&gt;Twitter accounts for sale&lt;/a&gt; and the evidence speaks for itself.&lt;/p&gt;

&lt;p&gt;Now here's the million dollar question. Do I publish this article and inform others of my findings in a selfless stride to make the world a better place? Or do I get straight to work building a bigger &amp; better bot of my own!&lt;/p&gt;

&lt;p&gt;Screw it I'll do both ;)&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/dybJkW4LlXs" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-14T21:05:13.903+01:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/-6JaC6T_Lijo/Th4IDccUMuI/AAAAAAAAApU/OwVb7Q_2wOg/s72-c/Screen%2Bshot%2B2011-07-13%2Bat%2B22.01.39.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/07/why-hot-girls-follow-me.html</feedburner:origLink></item><item><title>The Great Social Change</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/RVXKOgXVBC8/great-social-change.html</link><category>Social Media</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 10 Jul 2011 17:25:30 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-3930506890900553958</guid><description>&lt;h2&gt;Social Change?&lt;/h2&gt;

&lt;div class="separator" style="float: right; text-align: center; margin-left: 1em;"&gt;
&lt;img border="0" height="240" width="320" src="http://4.bp.blogspot.com/-r7HC5I0468k/ThcEIcWpcvI/AAAAAAAAAmk/I54da5NhiSM/s320/3735594nv2rqmjt.jpg" /&gt;&lt;/div&gt;

&lt;p&gt;Wow what a title. No you haven't stumbled upon a piece of broad-sheet journalism reflecting on the evolution of our society in modern time. This article is about something far more important, Social Media! Or rather, Social Media and strategies for integration.&lt;/p&gt;

&lt;p&gt;I will be referring to Social Media in the broad sense as I think it's more relevant than focusing on Facebook or Twitter in particular. Of course a lot of what I'm referring to is based on my direct experiences with the two big players.&lt;/p&gt;

&lt;h2&gt;Full Disclosure&lt;/h2&gt;

&lt;p&gt;I must admit, although in my work I build a lot of Social Media enabled sites, this is something that usually gets implemented by front-end web developers. It's not something I have had to deal with too often in terms of the software engineering side of things, but times are (rightly) changing. As we increasingly push boundaries with Social Media it can no longer be considered a value-add or an after-thought. Social Media is forever ingrained in our lives and is becoming the hub for our online experiences. More than ever it's crucial to understand these technologies and how to harness them. As such I've been researching Social Media to get a better idea of what's out there and how we can leverage them in our projects without introducing significant risk.&lt;/p&gt;

&lt;h2&gt;The Colour Of Chaos&lt;/h2&gt;

&lt;p&gt;So what's out there? Well the bad news is it's chaos! The good news is its getting better.&lt;/p&gt;

&lt;p&gt;So what do I mean by chaos? Well Social Media has evolved rapidly, not only the technologies themselves but also our understanding and acceptance of them. The result is a sway of privacy and policy changes influencing functional change and several generations of progressive APIs leaving a trail of misinformation.&lt;/p&gt;

&lt;p&gt;Now change is a great thing, it's the key the to success and acceptance of Social Media in our life's, but it gives us developers a terrible time. Just search for samples and tutorials for working with Social Media and there's a vast sea of misinformation out there referring to out-dated APIs, functionality long since removed, and links to abandoned libraries. What's more is that the applications we build today, don't necessarily work tomorrow.&lt;/p&gt;

&lt;p&gt;OK so we have the official documentation right? The problem with those Social Media giants is that they are busy people. They spend a lot of time working to enrich our lives, inventing new features, refining APIs, and re-organising their sites. All this takes its toll on documentation which can be quite slim and sparse of specific examples.&lt;/p&gt;  

&lt;h2&gt;The Kiss Of Death&lt;/h2&gt;

&lt;p&gt;I don't need to tell you, we're a friendly bunch us developers. We love to share our ideas and contribute to open source communities. Usually this is a great thing, it brings a competitive edge to the industry; it broadens our experiences; makes us proud; and allows us to achieve so much more of our potential.&lt;/p&gt;

&lt;p&gt;Now the thing about Social Media is that they certainly aren't in the business of creating frameworks. And where those lovely community libraries can lead to faster development times and reduce costs when working with frameworks, they can be the kiss of death when working with third party APIs. It's an unnecessary layer between you and a moving target, and if you can't adapt fast enough, you're dead in the water.&lt;/p&gt;

&lt;p&gt;The internet is littered with these good-willed projects that once sort to enrich our lives by bringing Social Media to our particular brand of technology. They now lay abandoned where the effort in upkeep overtook good-will or where functional changes have crippled the once sparkly widget that we all craved. Whereas Apple's move to block third party libraries on their platform was unexpected, it's clear that this was some clever thinking on their part to keep the community and platform nibble. The truth is Apple are more focused on producing APIs than developing frameworks, and it makes perfect sense.&lt;/p&gt;

&lt;p&gt;Now there are some good libraries out there, notably the Facebook C# SDK and Twitterizer, but I question the need for these and personally I believe it's only time before these go the way of their predecessors. Social Media has grown up and their APIs are built on simple technologies, but unlike frameworks they will continue to adapt and be redefined as the community demands.&lt;/p&gt;

&lt;h2&gt;Write Code Not Libraries&lt;/h2&gt;

&lt;p&gt;So how do we deal with change whilst still enabling cost effective development? Well as it evolves Social Media is becoming much smarter and a more robust than ever before. Facebook is moving forward with Social Plugins, a technology that removes previous coupling between developer code and the Facebook hub. This approach now allows us to take Social Media completely off-platform where it can self-update and become much more resilient to change. We can utilize the Facebook JavaScript API directly without compiling a single line of code, and share consistant experiences both within and outside of Facebook from a single codebase.&lt;/p&gt;

&lt;p&gt;The other emerging feature of Social Media APIs are the streaming content services which move away from more traditional RESTFul integration techniques. This allows much more efficient B2B communication, and the handling of much higher volumes of data than ever before.&lt;/p&gt;

&lt;h2&gt;A New Hope&lt;/h2&gt;

&lt;p&gt;To really leverage Social Media and take advantage of the advancements being made we need to create more lightweight adaptive solutions that build on the core technologies, and not the APIs.&lt;/p&gt;

&lt;p&gt;OK so what do I mean by that? Well both Twitter and Facebook are built on RESTFul technologies. Rather than looking for C# libraires (for example) that provide an easy hook into the platform and are tightly coupled to a particular version of the API, I suggest effort is better spent investigating, developing, and implementing RESTFul libraries written in C# (for example), that make it easier to call the Social API. This promotes code reuse without coupling the application to one approach or one technology. Any changes to the API can then easily be rectified by tweaks to the high level codebase without functional changes.&lt;/p&gt;

&lt;h2&gt;The Capitalists&lt;/h2&gt;

&lt;p&gt;Lastly I want to talk about another emerging solution to integration woes. These are service based companies that are springing up. Many of these are in their infancy with Alpha or Beta products but their offerings are attractive and come at a premium. These companies take on the integration effort across numerous Social Media Networks so you don't have to. Unlike community based projects this is becoming big business and they are forming tight partnerships with the big players. Whereas they may not be useful for helping you develop your Facebook application or run your Twitter campaign they can really help you access the results and get out the raw data. Common features include the aggregation and normalization of data across multiple Social Networks, and the provision of that data which you may not otherwise have access to.&lt;/p&gt;

&lt;p&gt;For example access to 100% of the unfiltered Twitter firehose (i.e. all the data) is very difficult to achieve due to the way the APIs are request limited and the way public streams are filtered to reduce noise. This data is massively valuable so of course companies are keen to offer solutions at a premium. Prices vary and usually charged on a per message basis. These services could prove themselves very valuable, although I suspect we may start to see these offers being made more directly in the future.&lt;/p&gt;

&lt;h2&gt;Key To Success&lt;/h2&gt;

&lt;p&gt;The Social APIs are constantly in flux and we shouldn't try to pin them down with middleware. The nature of Social Media is that it's driven by the will of the community and natural evolution. It requires a different thought and development process than traditional frameworks. Embrace the core technologies and build on those rather than the APIs directly. Keep the actual integration light and adaptive, watch out for depreciated APIs. Embrace the new integration mechanisms on offer such as Social Plugins and streaming services. Keep an eye out for data mining services to help aggregate and normalize your data.&lt;/p&gt;

&lt;h2&gt;In Closing&lt;/h2&gt;

&lt;p&gt;The one thing Social Media has taught us is that it's no longer acceptable to force our messaging on the user, or jump on every opportunity to spam them with content. This is reflected in the emerging APIs which curb our dark desires. We need to educate our clients on this and find new ways to reach out. The message is clear, it's about quality, relevance and user consent.&lt;/p&gt;

&lt;p&gt;Build it well and they will come!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/RVXKOgXVBC8" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-11T01:25:30.429+01:00</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-r7HC5I0468k/ThcEIcWpcvI/AAAAAAAAAmk/I54da5NhiSM/s72-c/3735594nv2rqmjt.jpg" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/07/great-social-change.html</feedburner:origLink></item><item><title>WinRM in mixed domain environments</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/WS0Snve50PQ/winrm-with-mixed-domain-environments.html</link><category>WinRM</category><category>CodeProject</category><category>PowerShell</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Fri, 08 Jul 2011 11:01:30 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-3158529461600163814</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Windows Remoting works perfectly for same domain situations, and the set-up is relatively straight-forward. It's extremely powerful when it works, and offers a highly flexible way to securely execute commands remotely.&lt;/p&gt;

&lt;p&gt;Problems arise however when trying to use WinRM in mixed domain environments, or where only one machine is on a domain. As I discovered this requires some additional configuration steps outlined below.&lt;/p&gt;

&lt;h2&gt;Enabling Remoting&lt;/h2&gt;

&lt;p&gt;Enabling WinRM between computers on the same domain is straight forward by running the following command in an elevated Powershell console on the remote server. This enables WinRM and configures the firewall so that it can accept incoming commands.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
Enable-PSRemoting
&lt;/pre&gt;

&lt;p&gt;Once this is done commands can then be executed against the machine remotely as follows.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
Invoke-Command -ComputerName RM-SERVER -ScriptBlock {Get-Process}
&lt;/pre&gt;

&lt;p&gt;This example will list processes on the remote machine named &lt;i&gt;RM-SERVER&lt;/i&gt; using the &lt;code&gt;Get-Process&lt;/code&gt; cmdlet.&lt;/p&gt;

&lt;h2&gt;Mixed domain&lt;/h2&gt;

&lt;p&gt;Mixed domain environments require some additional configuration to get working. To do this the following command needs to be executed on the remote server. This will allow the client server to authenticate from a different domain, or with an account local to the remote server.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
New-Itemproperty -name LocalAccountTokenFilterPolicy -path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -propertyType DWord -value 1
&lt;/pre&gt;

&lt;p&gt;With this configuration it's now possible to authenticate and execute a command remotely with explicit credentials.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
$credential = Get-Credential
Invoke-Command -ComputerName RM-SERVER -ScriptBlock {Get-Process} -Credential $credential
&lt;/pre&gt;

&lt;p&gt;Or create the credential explicitly in script as shown below.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
$securePassword = ConvertTo-SecureString "Password" -AsPlainText -force
$credential = New-Object System.Management.Automation.PsCredential("domain\username",$securePassword)
Invoke-Command -ComputerName RM-SERVER -ScriptBlock {Get-Process} -Credential $credential
&lt;/pre&gt;

&lt;h2&gt;Troubleshooting&lt;/h2&gt;

&lt;h4&gt;WinRM cannot process the request&lt;/h4&gt;
&lt;p&gt;Beware, I spent several hours on this. No matter what I did I kept getting the following error. It turns out this was caused by anti-virus software running on the remote server which had to be disabled.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
Connecting to remote server failed with the following error message : WinRM cannot process the request. The following error occured while using Kerberos authentication: There are currently no logon servers available to service the logon request.
Possible causes are:
  -The user name or password specified are invalid.
  -Kerberos is used when no authentication method and no user name are specified.
  -Kerberos accepts domain user names, but not local user names.
  -The Service Principal Name (SPN) for the remote computer name and port does not exist.
  -The client and remote computers are in different domains and there is no trust between the two domains.
After checking for the above issues, try the following:
  -Check the Event Viewer for events related to authentication.
  -Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
   -For more information about WinRM configuration, run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
    + CategoryInfo          : OpenError: (:) [], PSRemotingTransportException
    + FullyQualifiedErrorId : PSSessionStateBroken
&lt;/pre&gt;

&lt;h4&gt;Trusted hosts&lt;/h4&gt;

&lt;p&gt;The remote server can be configured to allow commands from only specific hosts. To set this run the following in an elevated Powershell console on the remote server. By default this is set to allow any host (*).&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
Set-item wsman:localhost\client\trustedhosts -value RM-Client1,RM-Client2
&lt;/pre&gt;

&lt;p&gt;The line above configures the remote server to allow only commands from machines &lt;i&gt;RM-Client1&lt;/i&gt; and &lt;i&gt;RM-Client2&lt;/i&gt;.&lt;/p&gt;

&lt;h4&gt;Firewall configuration&lt;/h4&gt;

&lt;p&gt;WinRm requires port 5985 for http, or port 5986 for https. The &lt;code&gt;Enable-PSRemoting&lt;/code&gt; cmdlet will auto-configure the Windows software firewall, but do ensure these ports are accessible across your network infrastructure.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/WS0Snve50PQ" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-07-08T19:01:30.356+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/02/winrm-with-mixed-domain-environments.html</feedburner:origLink></item><item><title>Blogger Hacks Part 2: Creating a navigation structure</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/kz0nCPYVriw/hacks-part-2-creating-navigation.html</link><category>Blogger</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Wed, 09 Feb 2011 14:49:42 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-6593187561713184867</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In &lt;a href="http://www.thecodeking.co.uk/2011/02/hacks-part-1-creating-static-homepage.html"&gt;Part 1&lt;/a&gt; I showed how to create a static homepage. In this article I'll explain a way to gain more control over the navigation of your site. This is for users like myself who may want to get more out of Blogger than purely the journal functionality.&lt;/p&gt;

&lt;h2&gt;Update&lt;/h2&gt;

&lt;p&gt;This article has been updated to reflect the techniques I'm currently using on this site.&lt;/p&gt;

&lt;h2&gt;The Principle&lt;/h2&gt;

&lt;p&gt;OK so here's the basic principle, relax it's not rocket science.&lt;/p&gt;

&lt;p&gt;With a static homepage in place users entering the site will be faced with a single    post (rather than usual list of latest posts). If we then remove the &lt;i&gt;Blog Archive&lt;/i&gt; gadget from the template, then we can remove the default &lt;i&gt;blog&lt;/i&gt; based navigation. This leaves us with a clean slate to build our own navigation structure.&lt;/p&gt;

&lt;p&gt;To remove the default navigation, login to the admin console and navigate to &lt;code&gt;Design -&gt; Page Elements&lt;/code&gt;. Locate the &lt;i&gt;Archive&lt;/i&gt; gadget, click edit and then remove.&lt;/p&gt; 

&lt;h2&gt;Simple Navigation&lt;/h2&gt;

&lt;p&gt;This is the technique I'm currently using to create the menus on the left-sidebar of my site. It's done by simply adding a &lt;i&gt;Links&lt;/i&gt; gadget to the Blogger template, and then using the gadget to create links to the various posts as desired. You can add multiple gadgets to the template in order to create multiple menus.&lt;/p&gt;

&lt;p&gt;With this technique it's a good idea to also disable the &lt;i&gt;auto-archive&lt;/i&gt; function of Blogger. Do this by logging into the admin console and navigating to &lt;code&gt;Settings -&gt; Archiving&lt;/code&gt;. Set the &lt;i&gt;Archive Frequency&lt;/i&gt; setting to "No Archive".&lt;/p&gt;  

&lt;img border="0" height="104" width="400" src="http://4.bp.blogspot.com/_DZF2ziLToks/TVL32smd1yI/AAAAAAAAAko/H4vo2JIC_QA/s400/noarchive.png" /&gt;

&lt;p&gt;A further enhancement you may wish to implement is to disable the footer navigation via some custom CSS. This further restricts navigation in the site, and avoids the ugly list view.&lt;/p&gt;

&lt;h2&gt;Static Pages&lt;/h2&gt;

&lt;p&gt;A quick &amp; easy way to create 2-tier navigation is to create a post (or static page) that simply contains links to other posts in your site. This can then be added to a menu as described above to create a second level navigation.&lt;/p&gt; 

&lt;p&gt;Personally I prefer not to use this technique as think the experience is a little clunky.&lt;/p&gt;

&lt;h2&gt;Label Navigation&lt;/h2&gt;

&lt;p&gt;This technique creates a similar experience to the &lt;i&gt;Static Pages&lt;/i&gt; technique described above as is no longer used on my site. I've included it for reference, but don't recommend it.&lt;/p&gt;

&lt;p&gt;To implement label based navigation use the Blogger designer to add a &lt;i&gt;Labels&lt;/i&gt; gadget to your template. When creating posts you can then label them as desired to form the navigation structure.&lt;/p&gt;

&lt;p&gt;Now by default the gadget will display each label with a post count, and provide a link to all posts with the corresponding label. To avoid this unwanted list view of posts you can implement a hack to create an interstitial navigation page. This is a more advanced set-up so you should only proceed if you are comfortable editing the Blogger template and understand CSS.&lt;/p&gt;

&lt;p&gt;The following steps implement conditional CSS based on the view type, and is used to hide the post body content in the list view to form a list of formatted links.&lt;/p&gt;

&lt;p&gt;To implement the behaviour login to the console and navigate to the template editor &lt;code&gt;Design -&gt; Edit HTML&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Backup your existing template before making changes.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Using the editor scroll down to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag, and insert the following code directly beneath this line. You may need to change the CSS to work with your particular template.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;style&amp;gt;
   &amp;lt;b:if cond=&amp;#39;data:blog.pageType == &amp;quot;item&amp;quot;&amp;#39;&amp;gt;
  .post-footer, .post-body 
  { 
   display: inline;
  }
 &amp;lt;b:else /&amp;gt;
  .post-footer, .post-body 
  { 
   display: none;
  }  
 &amp;lt;/b:if&amp;gt;
&amp;lt;/style&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Posts without labels do not appear in the categorized navigation menu, and therefore we can use these hidden pages as static pages which we link to from other posts.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;The techniques described above vary greatly in complexity and can be used together or individually to customise the Blogger navigation. This can help change the look &amp; feel from a standard blog site into a more conventional website structure. Hopefully the sample code included also gives you some ideas for how you can further customise the Blogger templates using the markup. See here for more info: &lt;a href="http://code.blogger.com/" target="_BLANK"&gt;http://code.blogger.com&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/kz0nCPYVriw" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-09T22:49:42.947Z</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_DZF2ziLToks/TVL32smd1yI/AAAAAAAAAko/H4vo2JIC_QA/s72-c/noarchive.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/02/hacks-part-2-creating-navigation.html</feedburner:origLink></item><item><title>Blogger Hacks Part 1: Creating a static homepage</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/dN9YqHcMq5I/hacks-part-1-creating-static-homepage.html</link><category>Blogger</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Fri, 11 Feb 2011 02:01:27 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-3680776289412996997</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;After searching around for somewhere to host my site I finally settled with Blogger. Why? Because I decided I preferred the choice of templates and in particular the drag-drop gadgets and page elements.&lt;/p&gt;

&lt;p&gt;What I didn't like is that it is purely a blogging site. This is quite restrictive in terms of content as I really wanted the ability to create more of a website than a blog.&lt;/p&gt;
&lt;p&gt;Well after a bit of trial and error, it turns out the new Blogger templates are fairly easy to 'hack', and as such I've managed to get the best of both worlds. I have the cool WYSIWYG gadgets and templates of Blogger, but have also fashioned a static home page and navigation structure.&lt;p /&gt;

&lt;h2&gt;Update&lt;/h2&gt;

&lt;p&gt;This article has been updated to reflect the simplified technique that I'm currently using for this website. There are also several alternative techniques which involve editing the Blogger template directly, or by making use of the new static pages. I've briefly described these solutions below for reference.&lt;/p&gt;

&lt;h2&gt;Simplified Technique&lt;/h2&gt;

&lt;p&gt;This technique is simply a Blogger setting which allows a user to limit the number of blogs displayed on the default page. By changing this setting to 1, a static homepage is created which will always display the most recent post. By manually configuring the publish dates of the blogs you can then control which content will will displayed on the homepage.&lt;/p&gt;

&lt;p&gt;To set the &lt;i&gt;post limit&lt;/i&gt; login to the Blogger console and navigate to &lt;code&gt;Settings -&gt; Formatting&lt;/code&gt;. Change the "show at most" setting to "1 post".&lt;/p&gt;

&lt;img border="0" height="104" width="400" src="http://4.bp.blogspot.com/_DZF2ziLToks/TVLl21VoY2I/AAAAAAAAAkU/8kdAe-KWias/s400/postlimit.png" /&gt;

&lt;p&gt;Next override the publish date of the post you wish to display on the homepage. This can be found in the &lt;i&gt;Post Options&lt;/i&gt; menu at the bottom of the blog editor.&lt;/p&gt;

&lt;img border="0" height="108" width="400" src="http://4.bp.blogspot.com/_DZF2ziLToks/TVLnDTY2wPI/AAAAAAAAAkc/ODw0ZSpxrdA/s400/postdate.png" /&gt;

&lt;h2&gt;Template Redirect Hack&lt;/h2&gt;

&lt;p&gt;An alternative technique I've previously written about involves editing the Blogger template, and adding code to redirect to a URL of choice. This has the advantage that you don't have to manually edit the post dates every time you create a new post, but does break the Blogger designer view and is not SEO friendly.&lt;/p&gt;

&lt;p&gt;To implement the redirect on the homepage login to the console and navigate to the template editor &lt;code&gt;Design -&gt; Edit HTML&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Backup your existing template before making changes.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Using the editor scroll down to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; tag, and insert the following code directly beneath this line. Replace &lt;i&gt;http://mysite.com/post.html&lt;/i&gt; with the URL you wish to use as your homepage (this should be the URL of a specific post, or you could use a static page now supported by Blogger).&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;b:if cond=&amp;#39;data:blog.url == data:blog.homepageUrl&amp;#39;&amp;gt;
       &amp;lt;meta content=&amp;#39;0;url=http://mysite.com/post.html&amp;#39; http-equiv=&amp;#39;refresh&amp;#39;/&amp;gt;
&amp;lt;/b:if&amp;gt;
&lt;/pre&gt;

&lt;p&gt;The code above causes a client-side redirect as soon as the page loads. If you really want to go all-out and improve the implementation further, you can also include the following edits. This will reduce the time taken for the initial page-load prior to the redirect and further improve the user experience. It also provides a manual link for users with JavaScript disabled. I'd recommend only making these changes if you are comfortable editing HTML.&lt;/p&gt;

&lt;p&gt;Using the editor scroll down and locate the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag in the template. You now need to wrap the &lt;b&gt;entire&lt;/b&gt; contents of the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag with the following code. This is everything inside the &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag and the &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;body&amp;gt;
    &amp;lt;b:if cond=&amp;#39;data:blog.url != data:blog.homepageUrl&amp;#39;&amp;gt;
          [existing template code]
     &amp;lt;b:else/&amp;gt; 
           &amp;lt;p&amp;gt; If the page doesn&amp;#39;t automatically refresh click &amp;lt;a href=&amp;#39;http://mysite.com/post.html&amp;#39;&amp;gt;here&amp;lt;/a&amp;gt;.&amp;lt;/p&amp;gt;
     &amp;lt;/b:if&amp;gt;
&amp;lt;/body&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Remember that with this technique in place you will not be able to use the Blogger designer to manage your gadgets. To do this you will need to temporarily disable the hack.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;That's all there is to it. In the &lt;a href="http://www.thecodeking.co.uk/2011/02/hacks-part-2-creating-navigation.html"&gt;next article&lt;/a&gt; I'll explain how to set up a navigation structure within Blogger.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/dN9YqHcMq5I" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-02-11T10:01:27.695Z</app:edited><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_DZF2ziLToks/TVLl21VoY2I/AAAAAAAAAkU/8kdAe-KWias/s72-c/postlimit.png" height="72" width="72" /><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2011/02/hacks-part-1-creating-static-homepage.html</feedburner:origLink></item><item><title>AutoObjectBuilder.Net</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/6jXXSWUalKU/autoobjectbuildernet.html</link><category>C# .Net</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sat, 09 Feb 2013 16:58:47 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-5606965649591701880</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
            &lt;p&gt;AutoObjectBuilder.Net Beta&lt;/p&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://nuget.org/List/Packages/AutoObjectBuilder"
                    target="_self"
onclick="javascript:urchinTracker('/link/nuget.org/List/Packages/AutoObjectBuilder');"&gt;
                    Project downloads&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/TheCodeKing/AutoObjectBuilder.Net/wiki"
                    target="_self"
onclick="javascript:urchinTracker('/link/github.com/TheCodeKing/AutoObjectBuilder.Net/wiki');"&gt;
                    Project documentation&lt;/a&gt; 
                &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;AutoObjectBuilder.Net is my latest open source project designed to assist with Unit testing by automatically building simple and complex object graphs with predictable test data.&lt;p&gt;

&lt;p&gt;Now available on NuGet.&lt;/p&gt;

&lt;div class="nuget-badge"&gt;
&lt;p&gt;&lt;code&gt;PM&amp;gt; Install-Package AutoObjectBuilder&lt;/code&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;h2&gt;Features&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Recursive instance creation - injecting constructor dependencies as required&lt;/li&gt;
&lt;li&gt;Able to create internal, protected and constructor-less instances&lt;/li&gt;
&lt;li&gt;Auto generation of interface/abstract class proxies&lt;/li&gt;
&lt;li&gt;Provides instances recursively populated with predicable test data&lt;/li&gt;
&lt;li&gt;Provides a fluent interface for overriding default construction behaviour to cover different edge cases&lt;/li&gt;
&lt;li&gt;Auto populates ICollection, IList, IDictionary, and Array types with a configurable number of items&lt;/li&gt;
&lt;li&gt;Enables use of custom configuration via extension methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The library can be used to automatically create and build objects recursively, populating them with predicable test data as they are constructed. These instances can then be used to compliment other Mocking frameworks, by allowing them to be injected as Mocked return values. This avoids bloating unit tests with extensive set-up code for complex objects.&lt;/p&gt;

&lt;p&gt;The following simplistic example shows how the library might be used with the Moq framework to return an auto-generated instance pre-populated with test values. The test takes advantage of the fact that the Username/Password members of the generated instance are predicable, and therefore is able to validate the application logic within the UserService Login method.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
     IPerson person = Auto.Make&amp;lt;IPerson&amp;gt;().Object;

     var moq = new Mock&amp;lt;IUserRespository&amp;gt;();
     var moq.SetUp(o =&amp;gt; o.FindUser(It.IsAny&amp;lt;int&amp;gt;())).Return(person);

     UserService service = new UserService(moq.Object);
     var loggedInUser = service.Login("Username", "Password");

     Assert.That(loggedInUser, Is.EqualTo(person));
     Assert.That(loggedInUser.Username, Is.EqualTo("Username"));
     Assert.That(loggedInUser.Password, Is.EqualTo("Password"));
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/6jXXSWUalKU" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2013-02-10T00:58:47.262Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2010/10/autoobjectbuildernet.html</feedburner:origLink></item><item><title>Making Log4Net work with the .Net Client Profile</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/oob1HQIj6eY/making-log4net-work-with-net-client.html</link><category>C# .Net</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 12 Sep 2010 03:02:37 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-7551382408183054386</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
        &lt;p&gt;Log4net for Client Profile&lt;/p&gt;
          &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/log4net/log4net.zip"
                    target="_self" onclick="javascript:urchinTracker('/downloads/WixWindowsinstallerDemo.zip');"&gt;log4net.zip&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;I've recently been working on a desktop application targeted at the Microsoft .Net Framework 4 Client Profile and ran into a problem using log4net. The issue is that the .Net Client Profile does not include any web related assemblies which are required by the log4net assembly. In particular for the &lt;i&gt;AspNetTraceAppender &lt;/i&gt;class.&lt;/p&gt;

&lt;p&gt;The result is that the C# compiler cannot resolve the log4net references and this results in a "reference not found" compiler error. When using Visual Studio it appears as if it cannot find the log4net dll when the project is built, but it's actually caused by missing dependencies. The error displayed is as follows:&lt;/p&gt;

&lt;pre&gt;
Error 1 The type or namespace name 'log4net' could not be found (are you missing a using directive or an assembly reference?)
&lt;/pre&gt;

&lt;p&gt;There are some open tickets (&lt;a href="https://issues.apache.org/jira/browse/LOG4NET-174" target="_blank"&gt;LOG4NET-174&lt;/a&gt;, &lt;a href="https://issues.apache.org/jira/browse/LOG4NET-233" target="_blank"&gt;LOG4NET-233&lt;/a&gt;) raised against this issue, but there is no indication of when (or if) this will be resolved.&lt;/p&gt;

&lt;h2&gt;The Solution&lt;/h2&gt;

&lt;p&gt;Luckily log4net is open source and the solution is relatively straight forward, although perhaps not entirely obvious. The following steps will allow you to build a custom version of log4net that will work with an application targeted at the 3.5 or 4 Client Profile.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the &lt;a href="http://logging.apache.org/log4net/download.html"&gt;log4net source&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open &amp; upgrade the solution using Visual Studio 2010&lt;/li&gt;
&lt;li&gt;Remove the System.Web project reference&lt;/li&gt;
&lt;li&gt;Exclude Appender\AspNetTraceAppender.cs class from the project&lt;/li&gt;
&lt;li&gt;Add a reference to System.Configuration&lt;/li&gt;
&lt;li&gt;Navigate to Project -&gt; log4net properties, and select the application tab&lt;/li&gt;
&lt;li&gt;Change the target framework to &lt;b&gt;.NET Framework 3.5 Client Profile&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Select the Build tab, and change the configuration to Debug&lt;/li&gt;
&lt;li&gt;Under &lt;i&gt;Conditional compilation symbols&lt;/i&gt; change this to &lt;b&gt;NET;NET_1_0;NET_2_0;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Change the configuration to Release&lt;/li&gt;
&lt;li&gt;Under &lt;i&gt;Conditional compilation symbols&lt;/i&gt; change this to &lt;b&gt;STRONG;NET;NET_1_0;NET_2_0;&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;Edit the &lt;code&gt;AssemblyInfo.cs&lt;/code&gt; class and update the &lt;i&gt;AssemblyKeyFile&lt;/i&gt; attribute with a valid strong key&lt;/li&gt;
&lt;li&gt;Compile the project in Release mode and distribute the new assembly&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Note log4net must be compiled for &lt;i&gt;3.5 Client Profile&lt;/i&gt; and not &lt;i&gt;4 Client Profile&lt;/i&gt;. This allows the assembly to work correctly with both versions of the framework. For some reason compiling for 4 results in a runtime error deep with the framework which I didn't have time to resolve.&lt;/p&gt;

&lt;p&gt;For convenience I've provided a version of the log4net dll compiled for client profile via this page, but be aware that the strong name does not match that of the official release.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/oob1HQIj6eY" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T11:02:37.828+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2010/08/making-log4net-work-with-net-client.html</feedburner:origLink></item><item><title>Creating a localized Windows Installer &amp; bootstrapper: Part 1</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/TP7EGT6ShTk/creating-localized-windows-installer.html</link><category>Wix</category><category>C# .Net</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 22 Aug 2010 11:40:11 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-1334458960242995239</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
           &lt;ul class="link"&gt;
                &lt;li&gt;Part 1: Introduction &amp; Setup&lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_7830.html"
                    target="_self"&gt;
                    Part 2: Defining Conditions&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_22.html"
                    target="_self"&gt;
                    Part 3: Localization&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
          &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_9309.html"
                    target="_self"&gt;Part 4: Provision Prerequisites&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
         &lt;ul class="download"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/WixWindowsInstallerDemo/WixWindowsInstallerDemo.zip"
                    target="_self" onclick="javascript:urchinTracker('/downloads/WixWindowsinstallerDemo.zip');"&gt;Download Source Code&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;It's been a while still my last article so I thought I'd write about my recent experiences with Wix for creating Windows Installer packages. I last used Wix 1.0 about 4 years ago with great results and had forgotten how satisfying it is to use. Unfortunately at the time of writing Wix 3.5 isn't out, but it sounds like there are some great additions in the pipeline including the much anticipated &lt;i&gt;Burn&lt;/i&gt; utility (a bootstrap compiler), as well as Votive support for Visual Studio 2010.&lt;/p&gt;

&lt;p&gt;In this series of articles I want to provide a complete end-to-end solution for deploying a .NET application based on my recent experiences. The solution provided is based around the following real-world requirements:&lt;/p&gt; 

&lt;ul&gt;
&lt;li&gt;Provide a MSI installer which deploys a .NET application&lt;/li&gt; 
&lt;li&gt;Use NGen to pre-cache .NET assemblies for faster start-up times&lt;/li&gt;
&lt;li&gt;Only allow the installer to run on a specific OS&lt;/li&gt;
&lt;li&gt;Only allow the installer to run based on the results of an WMI lookup&lt;/li&gt; 
&lt;li&gt;Only allow the installer to run if prerequisites are installed (.NET 4.0)&lt;/li&gt;
&lt;li&gt;Inject version info and other specifics into the installer from a build script&lt;/li&gt;
&lt;li&gt;Provide localized versions within a single MSI installer and auto detect the user language&lt;/li&gt;
&lt;li&gt;Create a localized bootstrapper as a single file that installs the necessary prerequisites (.NET 4.0)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note because in my example I'm targeting a Visual Studio 2010 project which isn't supported by the Wix 3.0's Votive project, I'm instead using a NAnt script to automate the build process.&lt;/p&gt;

&lt;h2&gt;Technology Stack&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://wix.sourceforge.net/" target="_BLANK"&gt;Wix 3.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://dotnetinstaller.codeplex.com/" target="_BLANK"&gt;dotNetInstaller 2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nant.sourceforge.net/" target="_BLANK"&gt;NAnt 0.90&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Note about GUIDs&lt;/h2&gt;

&lt;p&gt;It's important to generate your own GUIDs when working with Wix to avoid conflicts with other products. As it's common to copy &amp; paste examples, I've deliberately masked my GUIDs to prevent any duplicates ending up in production code. To work with any of the examples in the solution, be sure to replace all ids of the format &lt;code&gt;NEWGUID-XXXX-XXXX-XXXX-XXXXXXXXXXXX&lt;/code&gt; with your own unique GUIDS. You'll find these have been factored into &lt;code&gt;Config.Wsi&lt;/code&gt; for convenience.&lt;/p&gt;

&lt;h2&gt;Solution Overview&lt;/h2&gt;

&lt;p&gt;The MSI installer and EXE bootstrapper are produced from a single NAnt script. The script performs the following steps which are described in more detail throughout this series of articles. To build the project execute the included &lt;code&gt;build.bat&lt;/code&gt; file.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use HEAT to produce a Wix component fragment&lt;/li&gt;
&lt;li&gt;Transform HEAT output to inject NGen elements&lt;/li&gt;
&lt;li&gt;Use CANDLE to compile the Wix project, injecting build variables&lt;/li&gt;
&lt;li&gt;Use LIGHT linker to generate an English version of the MSI&lt;/li&gt;
&lt;li&gt;Use LIGHT linker to generate a language variation of the MSI&lt;/li&gt;
&lt;li&gt;Use TORCH to create a transform (delta) file by comparing the output of steps 4 &amp; 5&lt;/li&gt;
&lt;li&gt;Use WISUBSTG.VBS to embed the MST into the original MSI file&lt;/li&gt;
&lt;li&gt;Repeat steps 5-7 for each language supported&lt;/li&gt;
&lt;li&gt;Pre-process the dotNetInstaller config file to inject build parameters&lt;/li&gt;
&lt;li&gt;Compile the bootstrapper&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Using HEAT&lt;/h2&gt;
  
&lt;p&gt;The HEAT utility is used to generate Wix code fragments. The solution uses HEAT to create a Wix component fragment that describes the target files that will be deployed by the installer.&lt;/p&gt;

&lt;p&gt;As we want the installer to deploy these files to the user's chosen installation directory, we need to nest the generated component element within a specific directory node that relates to this location. Luckily HEAT provides an argument for this, and we just need to pass the correct directory id into the tool using the &lt;code&gt;-dr&lt;/code&gt; parameter. As we will be using the WixUI library the installation directory id must be set to &lt;code&gt;WIXUI_INSTALLDIR&lt;/code&gt;.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
heat dir MyProject\bin\Release
     -o Component.wsx
     -dr WIXUI_INSTALLDIR
     -cg AppFiles 
     -var var.InputSourceFolder
     -g1 -gg -srd -sfrag
&lt;/pre&gt;

&lt;p&gt;We also pass the &lt;code&gt;-cg&lt;/code&gt; argument so that HEAT writes out a generated &lt;code&gt;ComponentGroup&lt;/code&gt; with a specific id. This allows us to reference it from the main Wix project and include it in a Wix feature. The &lt;code&gt;var&lt;/code&gt; argument tells HEAT to swap the absolute paths to the target files with a custom variable &lt;code&gt;var.InputSourceFolder&lt;/code&gt;. This allows us to define the location of the target files at compile time.&lt;/p&gt;

&lt;h2&gt;Provision NGen&lt;/h2&gt;

&lt;p&gt;The Native Image Generator (Ngen.exe) is a .NET tool that improves the performance of managed applications start-up time by pre-caching a compiled image. Normally with .NET applications the JIT compiler compiles the image on first run and therefore causes an initial delay. By running NGen against the application during installation the compiled .NET application image is pre-cached and will therefore execute faster on first launch.&lt;/p&gt;

&lt;p&gt;Wix comes with the &lt;code&gt;WixNetFxExtension.dll&lt;/code&gt; extension that can be used to provision the NGen tool. To use the extension we just add the &lt;code&gt;netfx&lt;/code&gt; namespace to the &lt;code&gt;Main.wxs&lt;/code&gt; project file, and add the &lt;code&gt;NativeImage&lt;/code&gt; element to any file nodes that we want to pre-cache. Lastly we must ensure that we pass the extension to CANDLE during compilation.&lt;/p&gt;

&lt;p&gt;The following shows how NGen is provisioned as a child of a parent file node within a component definition.&lt;/p&gt;  

&lt;pre class="brush: xml"&gt;
&amp;lt;Component Id=&amp;quot;...&amp;quot; Guid=&amp;quot;....&amp;quot;&amp;gt;
   &amp;lt;File Id=&amp;quot;...&amp;quot; KeyPath=&amp;quot;yes&amp;quot; Source=&amp;quot;$(var.InputSourceFolder)\MyAppLibrary.dll&amp;quot;&amp;gt;
      &amp;lt;netfx:NativeImage Priority=&amp;quot;1&amp;quot; Id=&amp;quot;MyAppLibrary.dll&amp;quot; AppBaseDirectory=&amp;quot;WIXUI_INSTALLDIR&amp;quot; /&amp;gt;
   &amp;lt;/File&amp;gt;
&amp;lt;/Component&amp;gt;
&lt;/pre&gt;

&lt;p&gt;However there's a problem, as HEAT is used to generate the component fragment dynamically, how can we then inject our &lt;code&gt;NativeImage&lt;/code&gt; nodes?&lt;/p&gt;

&lt;p&gt;Well luckily Wix comes to the rescue in the form of an additional parameter that can be passed to the HEAT tool. This parameter describes an optional XSLT file that is applied to the fragment during output. This is used in the solution to inject the &lt;code&gt;NativeImage&lt;/code&gt; nodes into the component fragment for all files with an extension of &lt;code&gt;DLL&lt;/code&gt; or &lt;code&gt;EXE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Our HEAT command now looks something like this:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
heat.exe dir MyProject\bin\Release
     -o Component.wsx
     -dr WIXUI_INSTALLDIR
     -cg AppFiles 
     -g1 -gg -srd -sfrag
     -t:Components.xslt
&lt;/pre&gt;

&lt;h2&gt;WixUI Library&lt;/h2&gt;

&lt;p&gt;In the example solution provided I'm using the stock &lt;code&gt;WixUI_MONDO&lt;/code&gt; interface provided by the &lt;a href="http://wix.sourceforge.net/manual-wix2/WixUI_dialog_library.htm" target="_BLANK"&gt;WixUI library&lt;/a&gt;. This is simply included in &lt;code&gt;Main.wsx&lt;/code&gt; with the following reference. In doing this we must include the &lt;code&gt;WixUIExtension.dll&lt;/code&gt; extension when executing LIGHT.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
   &amp;lt;UI&amp;gt;
      &amp;lt;UIRef Id=&amp;quot;WixUI_Mondo&amp;quot; /&amp;gt;
      &amp;lt;UIRef Id=&amp;quot;WixUI_ErrorProgressText&amp;quot; /&amp;gt;
   &amp;lt;/UI&amp;gt;
&lt;/pre&gt;

&lt;p&gt;In our solution we also swap out the stock images &amp; agreement files used by the library dialogs by overriding some WixUI variables.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
    &amp;lt;WixVariable Id=&amp;quot;WixUIBannerBmp&amp;quot; Value=&amp;quot;binary\banner.bmp&amp;quot; /&amp;gt;
    &amp;lt;WixVariable Id=&amp;quot;WixUIDialogBmp&amp;quot; Value=&amp;quot;binary\dialog.bmp&amp;quot; /&amp;gt;
    &amp;lt;WixVariable Id=&amp;quot;WixUILicenseRtf&amp;quot; Value=&amp;quot;binary\EULA_en-gb.rtf&amp;quot; /&amp;gt;
&lt;/pre&gt;

&lt;p&gt;When using &lt;code&gt;WixUI_Mondo&lt;/code&gt; the target installation directory defined in the source code must use an id of &lt;code&gt;WIXUI_INSTALLDIR&lt;/code&gt;. This relates back to the reference in the auto-generated &lt;code&gt;Component.wsx&lt;/code&gt; file, and allows a user to override the location via the WixUI interface. If the user does not customize the installation location then files are deployed to the folder within &lt;code&gt;Program Files&lt;/code&gt; as defined by the fragment below. This is using custom variables injected at compile time to determine the default folder names.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;Directory Id='TARGETDIR' Name='SourceDir'&amp;gt;
    &amp;lt;Directory Id='ProgramFilesFolder' Name='PFiles'&amp;gt;
      &amp;lt;Directory Id='ManufacturerDir' Name='$(var.CompanyName)'&amp;gt;
        &amp;lt;Directory Id='WIXUI_INSTALLDIR' Name='$(var.FriendlyName) v$(var.ProductVersion)' /&amp;gt;
      &amp;lt;/Directory&amp;gt;
    &amp;lt;/Directory&amp;gt;
      ... 
&amp;lt;/Directory&amp;gt;
&lt;/pre&gt;

&lt;h2&gt;Using CANDLE&lt;/h2&gt;

&lt;p&gt;The Wix CANDLE utility compiles the Wix source files into a intermediate file format with a &lt;code&gt;WixOBJ&lt;/code&gt; extension. Build parameters can also be injected at this point as Wix &lt;a href="http://wix.sourceforge.net/manual-Wix2/preprocessor.htm" target="_BLANK"&gt;custom define variables&lt;/a&gt;. We can use these to pass in the product name and version number, as well as the location of the target files to be included by the installer.&lt;/p&gt;

&lt;p&gt;The CANDLE command looks something like this:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
candle.exe -o bin\Release\
     -ext WixNetFxExtension.dll
     -dInputSourceFolder=MyProject\bin\Release\
     -dFriendlyName="My App"
     -dVersion=1.0.0.0
     Main.wxs 
     Component.wxs
&lt;/pre&gt;

&lt;p&gt;In the solution provided you'll note I'm using a NAnt task provided by Wix for the CANDLE command. The build script is able to pass in the custom variables from build properties which could originate from a build server such as CruiseControl.&lt;/p&gt;

&lt;h2&gt;Using LIGHT&lt;/h2&gt;

&lt;p&gt;LIGHT is the linker used to generate the MSI file from the intermediate &lt;code&gt;WixObj&lt;/code&gt; libraries to produce a MSI file. The command line to do this in our solution would be as follows, but again in the solution we are actually using Wix NAnt task instead.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
light.exe -o bin\Release\Setup.msi
     -ext WixNetFxExtension.dll
     -ext WixUIExtension.dll
     Main.wixobj 
     Component.wixobj
&lt;/pre&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;In this part we have created a fully functional Windows Installer file for deploying the .NET application. In Part 2 I'll discuss adding condition checks to enhance the installer further. &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_7830.html" target="_self"&gt;Part 2&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/TP7EGT6ShTk" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-22T19:40:11.161+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html</feedburner:origLink></item><item><title>Creating a localized Windows Installer &amp; bootstrapper: Part 4</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/LTQ3Wm_3rIw/creating-localized-windows-installer_9309.html</link><category>Wix</category><category>C# .Net</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 22 Aug 2010 10:08:00 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-8982332637718462215</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
           &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html" target="_self"&gt;Part 1: Introduction &amp; Setup&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_7830.html"
                    target="_self"&gt;
                    Part 2: Defining Conditions&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_22.html"
                    target="_self"&gt;
                    Part 3: Localization&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
          &lt;ul class="link"&gt;
                &lt;li&gt;Part 4: Provision Prerequisites &lt;/li&gt;
            &lt;/ul&gt;
         &lt;ul class="download"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/WixWindowsInstallerDemo/WixWindowsInstallerDemo.zip"
                    target="_self" onclick="javascript:urchinTracker('/downloads/WixWindowsinstallerDemo.zip');"&gt;Download Source Code&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html" target="_self"&gt;Part 1&lt;/a&gt;,&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_7830.html" target="_self"&gt;2&lt;/a&gt; and &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_22.html" target="_self"&gt;3&lt;/a&gt; we created a localizable MSI installer using the Wix tools. We also created conditions to ensure that the application can only be installed on Dell hardware running Windows 7 and the Microsoft .NET Framework 4 Client Profile. In our original requirements we stated that this must be deployable as a single file, and should install any prerequisites specifically .NET 4. To achieve this we need to create a bootstrapper that will preform the prerequisites installations from unmanaged code. The bootstrapper will be deployable as a single self-contained &lt;code&gt;EXE&lt;/code&gt; with the original MSI file embedded inside.&lt;/p&gt;

&lt;p&gt;I investigated many utilities for creating a bootstrapper, including the Wix &lt;code&gt;SETUPBLD&lt;/code&gt; tool, and the MSBuild &lt;code&gt;GenerateBootStrapper&lt;/code&gt; task. In the end I settled on a powerful free utility called &lt;a href="http://dotnetinstaller.codeplex.com/" target="_BLANK"&gt;dotNetInstaller&lt;/a&gt;. This allows the creation of highly configurable and localizable bootstrappers which can be compiled from the command line.&lt;/p&gt;   

&lt;h2&gt;DotNetInstaller&lt;/h2&gt;

&lt;p&gt;DoNetInstaller includes several utilities for authoring and compiling the bootstrapper. The bootstrapper is compiled from a single XML config file by the &lt;code&gt;InstallerLinker.exe&lt;/code&gt; tool. To author the configuration file an editor is provided in the form of &lt;code&gt;InstallerEditor.exe&lt;/code&gt;.&lt;/p&gt; 

&lt;p&gt;Using the editor language variations can quickly be set up through the UI and prerequisites defined by adding child nodes. Any prerequisite installers can either be embedded directly into the bootstrapper or a URL provided from which they will be downloaded and installed. In our case we embed the Web Installer for the Microsoft .NET Framework 4 Client Profile. This will launch the installation process and download the necessary components on demand to keep the size of the bootstrapper down.&lt;/p&gt;

&lt;p&gt;Once the prerequisites are installed dotNetInstaller allows us to define a custom command to launch our own embedded MSI file using the &lt;code&gt;complete_command&lt;/code&gt; property. We can set up different commands for different languages and therefore explicitly pass a transform to the MSI file after the prerequisite checks. If all prerequisites are found we can hide the bootstrapper interface altogether and simply launch the MSI file.&lt;/p&gt; 

&lt;p&gt;DotNetinstaller includes it's own auto-language detection based on either user or system settings. To leverage this we can refer to a &lt;code&gt;#LCID&lt;/code&gt; token in the config file that will evaluate to the detected LCID at runtime. This allows us to pass the LCID explicitly to our MSI in order to launch a particular language variation.&lt;/p&gt;

&lt;p&gt;Through the command line we can still inject properties into our MSI for overriding the hardware check for example. The syntax for this would be:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
setup.exe /CompleteCommandArgs "SKIPCHECK=1"
&lt;/pre&gt;

&lt;p&gt;The features of dotNetInstaller are too many to cover in this article but there is plenty of documentation and it's very feature rich.&lt;/p&gt;

&lt;h2&gt;Build Automation&lt;/h2&gt;

&lt;p&gt;To complete our bootstrapper we really want to integrate this into our build script and inject parameters such as product name and version. To achieve this we can use a NAnt script that performs token replacement on the dotNetInstaller config file prior to compilation. I could have equally used XML manipulation, but NAnt makes the token replacement somewhat easy.&lt;/p&gt;

&lt;p&gt;This is implemented using a &lt;code&gt;filterchain&lt;/code&gt; with the NAnt &lt;code&gt;copy&lt;/code&gt; task as shown below. The original config file is copied to a new location where it is modified and then parsed to the installer linker.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;copy tofile=&amp;quot;${installer.dir}\obj\${build.configuration}\Configuration.xml&amp;quot;
          file=&amp;quot;${installer.dir}\bootstrapper\Configuration.xml&amp;quot; overwrite=&amp;quot;true&amp;quot;
          inputencoding=&amp;quot;utf-8&amp;quot;
          outputencoding=&amp;quot;utf-8&amp;quot;
          &amp;gt;
      &amp;lt;filterchain&amp;gt;
        &amp;lt;replacetokens&amp;gt;
          &amp;lt;token key=&amp;quot;APPLICATION_MANUFACTURER&amp;quot; value=&amp;quot;${project.companyname}&amp;quot; /&amp;gt;
          &amp;lt;token key=&amp;quot;APPLICATION_NAME&amp;quot; value=&amp;quot;${app.name}&amp;quot; /&amp;gt;
          &amp;lt;token key=&amp;quot;APPLICATION_VERSION&amp;quot; value=&amp;quot;v${version}&amp;quot; /&amp;gt;
          &amp;lt;token key=&amp;quot;INSTALLER_VERSION&amp;quot; value=&amp;quot;${installer.version}&amp;quot; /&amp;gt;
          &amp;lt;token key=&amp;quot;INSTALLER_COPYRIGHT&amp;quot; value=&amp;quot;Copyright &amp;#169; ${datetime::get-year(datetime::now())} ${project.companyname}&amp;quot; /&amp;gt;
          &amp;lt;token key=&amp;quot;MSI_PATH&amp;quot; value=&amp;quot;${installer.dir}\bin\${build.configuration}\Setup.msi&amp;quot; /&amp;gt;
        &amp;lt;/replacetokens&amp;gt;
        &amp;lt;tabstospaces /&amp;gt;
      &amp;lt;/filterchain&amp;gt;
    &amp;lt;/copy&amp;gt;
&lt;/pre&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;In this final part we have fulfilled our original requirements and provided a build script for dynamically generating a localizable installer &amp; self-contained bootstrapper. All of the source code and scripts are provided as a download on this page, and I hope it's useful for demonstrating the technologies in a real-world scenario. When building the demo solution don't forget to replace the GUIDs in the source &lt;code&gt;Config.wsi&lt;/code&gt; file with your own unique ids.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/LTQ3Wm_3rIw" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-22T18:08:00.474+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_9309.html</feedburner:origLink></item><item><title>Creating a localized Windows Installer &amp; bootstrapper: Part 3</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/XcyiuU34yhc/creating-localized-windows-installer_22.html</link><category>Wix</category><category>C# .Net</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 22 Aug 2010 10:07:48 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-7391763877251629812</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
           &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html" target="_self"&gt;Part 1: Introduction &amp; Setup&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_7830.html"
                    target="_self"&gt;
                    Part 2: Defining Conditions&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;Part 3: Localization&lt;/li&gt;
            &lt;/ul&gt;
          &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_9309.html"
                    target="_self"&gt;Part 4: Provision Prerequisites&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
         &lt;ul class="download"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/WixWindowsInstallerDemo/WixWindowsInstallerDemo.zip"
                    target="_self" onclick="javascript:urchinTracker('/downloads/WixWindowsinstallerDemo.zip');"&gt;Download Source Code&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html" target="_self"&gt;Part 1&lt;/a&gt; &amp; &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_7830.html" target="_self"&gt;2&lt;/a&gt; we created a Windows Installer using Wix in the form of an MSI file. In the real-world installers often require localization and in this part we'll look at a solution for localizing the installer into a second language; in this example Italian.&lt;/p&gt;

&lt;p&gt;Strictly speaking Windows Installer doesn't support multiple languages and can only store one set of strings at any point in time. However it does provide a mechanism which allows for localization via an implementation of transforms. A transform is a delta &lt;code&gt;MST&lt;/code&gt; file which can sit inside or outside of the main MSI package. By supplying the transform to Windows Installer the MSI content is replaced by matching content in the MST file at runtime before installation begins, which is ideal for localization.&lt;/p&gt;

&lt;p&gt;Our localization solution involves the following steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make the Wix source localizable&lt;/li&gt;
&lt;li&gt;Generate an Italian version of the MSI file&lt;/li&gt;
&lt;li&gt;Create a MST transform file&lt;/li&gt;
&lt;li&gt;Embed the transform file into the original MSI&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Localizing Wix&lt;/h2&gt;

&lt;p&gt;Wix contains all of the tools required for localization, and the WixUI library we are using already comes with stock translations for the UI dialogs provided. The localization authoring features allow us to move localizable strings into separate Wix translation files, which can then be swapped out by LIGHT when generating an MSI. This will ultimately make it easier to generate transforms later on in the process.&lt;/p&gt;

&lt;p&gt;In the solution provided all of the custom strings have been moved into external localization files and named with the relevant culture code. These are then referenced in the main source files using the syntax &lt;code&gt;!(loc.VariableName)&lt;/code&gt;. The &lt;code&gt;WixLocalization&lt;/code&gt; element in the localization file must contain correct values for &lt;code&gt;Culture&lt;/code&gt; and &lt;code&gt;Codepage&lt;/code&gt; attributes for the localized version to function correctly with different character sets. We also add the language LCID as a translation string so that we can reference the language code as a variable in the main project and override the product language attribute.&lt;/p&gt;

&lt;p&gt;The final localization file looks something like this:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;WixLocalization Culture=&amp;quot;en-GB&amp;quot; xmlns=&amp;quot;http://schemas.microsoft.com/wix/2006/localization&amp;quot; Codepage=&amp;#39;1252&amp;#39;&amp;gt;
  &amp;lt;String Id=&amp;#39;LANG&amp;#39; Overridable=&amp;quot;yes&amp;quot;&amp;gt;1033&amp;lt;/String&amp;gt;
  &amp;lt;String Id=&amp;quot;Windows7Required&amp;quot; Overridable=&amp;quot;yes&amp;quot;&amp;gt;This application only runs on Windows 7.&amp;lt;/String&amp;gt;
   ...  
&amp;lt;/WixLocalization&amp;gt;
&lt;/pre&gt;

&lt;p&gt;The main source code references these localization strings as follows:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;Condition Message=&amp;#39;!(loc.Windows7Required)&amp;#39;&amp;gt;
   &amp;lt;![CDATA[VersionNT = 601 AND WindowsBuild &amp;gt; 7100]]&amp;gt;
&amp;lt;/Condition&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Once the strings are re-factored into the localization files, we can go ahead and get these translated into multiple languages. A set of localization files are created for each new language and the culture specific attributes set up accordingly.&lt;/p&gt; 

&lt;h2&gt;Create Localized MSI&lt;/h2&gt;

&lt;p&gt;LIGHT provides some handy features that allow us to create a localized version of the MSI. Firstly the utility takes multiple translation files that can contain a mixture of cultures. The output file however will only contain a single set of translation strings. So how does this work?&lt;/p&gt;

&lt;p&gt;The trick is the &lt;code&gt;cultures&lt;/code&gt; argument that takes a list of cultures in order of precedence. From left to right LIGHT will look through the supplied translations looking for the first matching culture for each string. This allows us to build fall-backs into our translation set.&lt;/p&gt;

&lt;p&gt;Please note that WixVariables cannot reference localized translation variables, and therefore to swap out the path to the T&amp;Cs agreement we must change our solution so that this is passed through on the command line. We can then pass in references to different agreement files for each localized installer.&lt;/p&gt;

&lt;p&gt;So implementing this technique we can create a Italian version of the Installer as follows:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
light.exe -o bin\Release\Setup.msi
     -ext WixNetFxExtension.dll
     -ext WixUIExtension.dll
     -cultures:"it-IT,en-GB"
     -dWixUILicenseRtf=Binary\EULA_it-IT.rtf
     Main.wixobj 
     Component.wixobj
     -loc it-IT.wxl
     -loc en-GB.wxl
&lt;/pre&gt;

&lt;p&gt;The example above will look for Italian translations, and for any strings not found it will fall back to English. Note, the naming of the &lt;code&gt;WXL&lt;/code&gt; files is irrelevant to the linker.&lt;/p&gt;

&lt;h2&gt;Creating a Transform&lt;/h2&gt;

&lt;p&gt;Now that we have an English and Italian version of the MSI we can generate a transform file. The transform will contain a set of differences between the two files. In this case it will contain just the Italian translations and a new agreement file.&lt;/p&gt;

&lt;p&gt;The Wix TORCH tool is used to create the transform &lt;code&gt;MST&lt;/code&gt; file as follows:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
torch.exe setup.msi it-IT\setup.msi -o it-IT.mst
&lt;/pre&gt;

&lt;p&gt;The resultant &lt;code&gt;it-IT.mst&lt;/code&gt; file is smaller than the original and contains the transforms which can be applied to the original MSI file in order to localize the installer. It could be deployed alongside the MSI file, but in our case we want to embed the transform and create a single MSI for ease of deployment.&lt;/p&gt;

&lt;p&gt;This is where we can leverage an undocumented and unsupported feature of Windows Installer which allows us to auto-detect the language of the installer from the user's region settings. By naming the transform with the corresponding LCID Windows Installer will automatically apply the transform at runtime.&lt;/p&gt;

&lt;p&gt;The tool used to embed the MST with a specific name is a script taken from the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=c17ba869-9671-4330-a63e-1fd44e0e2505&amp;displaylang=en" target="_BLANK"&gt;Microsoft Windows Software Development Kit&lt;/a&gt;. This is used as follows, where &lt;code&gt;1040&lt;/code&gt; is the Italian LCID:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
cscript.exe WiSubStg.vbs setup.msi it-IT.mst 1040
&lt;/pre&gt;

&lt;p&gt;Once embedded the transform can be applied explicitly through the command line to launch the Italian version of the installer.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
msiexec /i setup.msi TRANSFORMS=":1040"
&lt;/pre&gt;

&lt;p&gt;Note the &lt;code&gt;TRANSFORMS=":1040"&lt;/code&gt; syntax (with colon) applies embedded transforms, whereas &lt;code&gt;TRANSFORMS="it-IT.mst"&lt;/code&gt; (without colon) will apply an external transform file.&lt;/p&gt;

&lt;p&gt;To test the auto-language detection functionality change the regional settings by opening control panel and navigating to regional settings. On the first dialog which defines date and time Formats, select Italy from the language selector. Apply the settings and launch the MSI with no parameters. You should then see the Italian version of the installer.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;In this part of the series we talked through localizing the installer by leveraging some of the Wix tools and by taking advantage of some undocumented features of Windows Installer. Our installer is almost complete. In part 4 I'll show how to create bootstrapper for the installer that will detect and install any prerequisites. &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_9309.html" target="_self"&gt;Part 4&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/XcyiuU34yhc" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-22T18:07:48.573+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_22.html</feedburner:origLink></item><item><title>Creating a localized Windows Installer &amp; bootstrapper: Part 2</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/JcXZ1IHHSiw/creating-localized-windows-installer_7830.html</link><category>Wix</category><category>C# .Net</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 22 Aug 2010 10:07:27 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-8158980184437920072</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
           &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html" target="_self"&gt;Part 1: Introduction &amp; Setup&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;
                    Part 2: Defining Conditions&lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_22.html"
                    target="_self"&gt;
                    Part 3: Localization&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
          &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_9309.html"
                    target="_self"&gt;Part 4: Provision Prerequisites&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
         &lt;ul class="download"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/WixWindowsInstallerDemo/WixWindowsInstallerDemo.zip"
                    target="_self" onclick="javascript:urchinTracker('/downloads/WixWindowsinstallerDemo.zip');"&gt;Download Source Code&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html" target="_self"&gt;Part 1&lt;/a&gt; we looked at the steps required to create a Windows Installer using Wix that dynamically packages the binaries from a target .NET application ready for deployment. In this part we'll look at adding some condition checks into the installer that prevents a user from installing the software unless some conditions are met.&lt;/p&gt;

&lt;p&gt;In our solution we will create condition checks for the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install only on Windows 7&lt;/li&gt;
&lt;li&gt;Install only if the Microsoft .NET Framework 4 Client Profile is installed&lt;/li&gt;
&lt;li&gt;Install only on Dell hardware&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Wix provides a variety of ways to add condition checks using registry or file system searches for example. When a condition element is added as a child node of the &lt;code&gt;Project&lt;/code&gt; element it will only allow installation when the condition is met. If not the installation will be terminated with the given error message.&lt;/p&gt;

&lt;h2&gt;Windows 7 Condition&lt;/h2&gt;

&lt;p&gt;To add a condition that prevents users from installing the application on versions of Windows other than Windows 7 we can leverage some existing properties populated by Windows Installer. These are the &lt;code&gt;VersionNT&lt;/code&gt; and &lt;code&gt;WindowsBuild&lt;/code&gt; properties. If we look at the documentation for &lt;a href="http://msdn.microsoft.com/en-us/library/aa370556(v=VS.85).aspx" target="_BLANK"&gt;Operating System Property Values&lt;/a&gt; we find that the required values for detecting Windows 7 are VersionNT 601 and WindowsBuild greater than 7100.&lt;/p&gt;

&lt;p&gt;To implement the condition we add the following element into the &lt;code&gt;Main.wxs&lt;/code&gt; file within the &lt;code&gt;Project&lt;/code&gt; node.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;Condition Message=&amp;#39;[ProductName] can only be installed on Windows 7&amp;#39; &amp;gt;
  VersionNT = 601 AND WindowsBuild &amp;gt; 7100
&amp;lt;/Condition&amp;gt;
&lt;/pre&gt;

&lt;p&gt;The result is that the installer will now only install the application on devices running Windows 7, otherwise an error is thrown and the installation is terminated.&lt;/p&gt;

&lt;h2&gt;Microsoft .NET Framework 4 Client Profile Condition&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;WixNetFxExtension.dll&lt;/code&gt; extension used in &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer.html" target="_self"&gt;Part 1&lt;/a&gt; provides a set of useful utilities related to the .NET framework and this includes properties that can be used for detecting the version of the .NET framework that is currently installed.&lt;/p&gt;

&lt;p&gt;Unfortunately version 3.0 of the framework doesn't include a property for detecting .NET 4.0 and this will only be available in Wix 3.5. Luckily detecting if a particular version of the framework is installed isn't too difficult, and we can use a simple registry search as follows:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;Property Id=&amp;quot;NETFRAMEWORK40CLIENT&amp;quot;&amp;gt;
   &amp;lt;RegistrySearch Id=&amp;quot;NetFramework40Client&amp;quot; 
      Root=&amp;quot;HKLM&amp;quot; 
      Key=&amp;quot;SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Client&amp;quot; 
      Name=&amp;quot;Install&amp;quot;
      Type=&amp;quot;raw&amp;quot; /&amp;gt;
&amp;lt;/Property&amp;gt;
&lt;/pre&gt;

&lt;p&gt;This populates a property named &lt;code&gt;NETFRAMEWORK40CLIENT&lt;/code&gt; with a value of 1 if the registry key is found. Using this we can then implement the condition check. We skip the condition check on uninstall in case the framework is subsequently removed.&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;Condition Message=&amp;quot;[ProductName] requires the Microsoft .NET Framework 4 Client Profile&amp;quot;&amp;gt;
    Installed Or NETFRAMEWORK40CLIENT
&amp;lt;/Condition&amp;gt;
&lt;/pre&gt;

&lt;h2&gt;Dell Hardware Condition&lt;/h2&gt;

&lt;p&gt;To implement a hardware check we need to perform a WMI lookup to determine the hardware manufacturer. To get the WMI value into Windows Installer so that we can implement a condition we need to use a custom action.&lt;/p&gt;

&lt;p&gt;There are a variety of ways to implement a custom action. For simplicity in this case we will use an embedded VBScript called &lt;code&gt;WMIQuery.vbs&lt;/code&gt;. The script will perform the WMI lookup and poke this into the installer as a property named &lt;code&gt;WMI_Manufacturer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To begin we add a reference to the &lt;code&gt;WMIQuery.vbs&lt;/code&gt; file using a &lt;code&gt;Binary&lt;/code&gt; element. We then define a custom action that will invoke a function within the script and schedule this to run after &lt;code&gt;AppSearch&lt;/code&gt; in the &lt;code&gt;InstallExecuteSequence&lt;/code&gt; and &lt;code&gt;InstallUISequence&lt;/code&gt; sequences. This makes the property available prior to running the condition checks during install.&lt;/p&gt;

&lt;p&gt;The new code looks something like this:&lt;/p&gt;

&lt;pre class="brush: xml"&gt;
&amp;lt;Condition Message=&amp;#39;This application cannot be installed on this hardware.&amp;#39;&amp;gt;
  &amp;lt;![CDATA[
    SKIPCHECK 
    OR Installed 
    OR WMI_Manufacturer &amp;gt;&amp;lt; &amp;quot;dell&amp;quot;
  ]]&amp;gt;
&amp;lt;/Condition&amp;gt;

&amp;lt;CustomAction Id=&amp;quot;WMIQuery&amp;quot; Return=&amp;quot;check&amp;quot; BinaryKey=&amp;quot;WMIQuery&amp;quot; VBScriptCall=&amp;quot;Main&amp;quot; /&amp;gt;
&amp;lt;Binary Id=&amp;quot;WMIQuery&amp;quot; SourceFile=&amp;quot;Binary\WMIQuery.vbs&amp;quot; /&amp;gt;

&amp;lt;InstallExecuteSequence&amp;gt;
  &amp;lt;Custom Action=&amp;quot;WMIQuery&amp;quot; After=&amp;quot;AppSearch&amp;quot; /&amp;gt;
&amp;lt;/InstallExecuteSequence&amp;gt;

&amp;lt;InstallUISequence&amp;gt;
  &amp;lt;Custom Action=&amp;quot;WMIQuery&amp;quot; After=&amp;quot;AppSearch&amp;quot; /&amp;gt;
&amp;lt;/InstallUISequence&amp;gt;
&lt;/pre&gt;

&lt;p&gt;Note the use of the contains string operator &lt;code&gt;&amp;gt;&amp;lt;&lt;/code&gt; for the condition check. The operator characters must be escaped within &lt;code&gt;CDATA&lt;/code&gt; blocks to prevent validation issues with the XML. We have also added an override property called &lt;code&gt;SKIPCHECK&lt;/code&gt; that will allow us to override the hardware condition when run from the command line for testing. To do this we execute the MSI as follows:&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
msiexec /i setup.msi SKIPCHECK=1
&lt;/pre&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;So far in this series we have looked at creating a Windows Installer using Wix which dynamically packages a .NET application and applies NGen against the assemblies during installation. We have now also added some conditions to prevent the application being installed in specific scenarios using a range of techniques. In Part 3 we will look at localizing the installer and providing auto-language detection using the user's region settings.  &lt;a href="http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_22.html" target="_self"&gt;Part 3&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/JcXZ1IHHSiw" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-08-22T18:07:27.933+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2010/08/creating-localized-windows-installer_7830.html</feedburner:origLink></item><item><title>Error: Only Content controls are allowed directly in a content page</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/wnkiWJUJuf0/error-only-content-controls-are-allowed.html</link><category>Sharepoint Tips</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Thu, 25 Feb 2010 01:25:17 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-6141003049115960133</guid><description>&lt;p&gt;I recently came across the following error which happened during a full content deployment, and despite the fact that the template in question was ghosted:&lt;/p&gt;

&lt;pre&gt;
An error occurred during the processing of . Only Content controls are allowed directly in a content page that contains Content controls. 
&lt;/pre&gt;

&lt;p&gt;It turns out (rather randomly) that this can be caused when a lowercase is used for the &lt;code&gt;asp:content&lt;/code&gt; user controls in the template. The fix is to modify these to use an uppercase as follows &lt;code&gt;asp:Content&lt;/code&gt;.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/wnkiWJUJuf0" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2010-02-25T09:25:17.442Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2010/02/error-only-content-controls-are-allowed.html</feedburner:origLink></item><item><title>XDMessaging 3.0 : Downloads</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/sUdeMjXgkJ4/xdmessaging-downloads.html</link><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 27 Mar 2011 12:52:25 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-9028886080651681444</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
         &lt;p&gt;XDMessaging .Net Library 3.0&lt;/p&gt;
         &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="/2009/12/xdmessaging-net-library-20.html"
                    target="_self"&gt;Project home&lt;/a&gt; &lt;/li&gt;
        &lt;/ul&gt;
      &lt;ul class="link"&gt;
              &lt;li&gt;Project downloads&lt;/li&gt;
&lt;/ul&gt;
&lt;ul class="link"&gt;
               &lt;li&gt;&lt;a href="/2009/12/xdmessaging-20-documentation.html"
                    target="_self"&gt;Project documentation&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;Latest Release 3.0.0.0&lt;/h2&gt;

&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-3.0.0.0-src.zip"
 onclick="javascript:urchinTracker('/downloads/XDMessaging-3.0.0.0-src.zip');"&gt;
                    XDMessaging Library 3.0.0.0&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;What's new in this release&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Enhancements to IOStream mode for performance.&lt;/li&gt;
&lt;li&gt;Refactoring code to split DataGram into various implementations.&lt;/li&gt;
&lt;li&gt;This version adds additional error handling around mixed elevation scenarios.&lt;/li&gt;
&lt;li&gt;Obsolete APIs are now removed.&lt;/li&gt;
&lt;li&gt;Codebase migrated to VS2010.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note: This library is free for personal and educational use. Please ask permission before using in commercial applications and consider making a small donation.&lt;p&gt;
&lt;form action="https://www.paypal.com/cgi-bin/webscr" method="post"&gt;
&lt;input value="_s-xclick" name="cmd" type="hidden"/&gt;
&lt;input border="0" alt="Make payments with PayPal - it's fast, free and secure!" src="https://www.paypal.com/en_US/i/btn/x-click-but04.gif" name="submit" type="image"/&gt;
&lt;img border="0" alt="" width="1" src="https://www.paypal.com/en_GB/i/scr/pixel.gif" height="1"/&gt;
&lt;input value="-----BEGIN PKCS7-----MIIHfwYJKoZIhvcNAQcEoIIHcDCCB2wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYAmE1b/7/8gIAMHfO/b8ApKVM7TaAYh0KlVg0/tYsQci1d9OXtak14rWMu6BveT/wE9TzW0YOHgCAMfdpLNZsWyx0MU0YuH8KuYVINycBb5qVyfq/V8j9b9xRwIw078YO55/TU+K8eu7pE327pHLGl7wm5UcIU42qoTXjb7s3GMIjELMAkGBSsOAwIaBQAwgfwGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIr73xtapWLzyAgdgRmqAg64o0x074GP0H24xb9hgTa+FmeX8p0rSSun43k65ciEkAcEbyAQGV5zos2YDhfDqPx6KQimuhxnB/UO+N/l/0Esd3H/+Oia8QKRsaHBx4DXV/K6tY85hl3NEc99Z4/UiuQJYDK4LCUvkfkux96QuZc4AoJMyn7N1wFih41BoKOXz/u5H4rVbPFHMsAhDyXcHOzKiBQSUwXIaPaJwYD8iR1WhxdF42F0/eqinVMvIF8q/Mub5Ye1Pn4lAXf8VF28U3V8p5lQ9HLVkvFIvmxwvzGKWMhHOgggOHMIIDgzCCAuygAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20wHhcNMDQwMjEzMTAxMzE1WhcNMzUwMjEzMTAxMzE1WjCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMFHTt38RMxLXJyO2SmS+Ndl72T7oKJ4u4uw+6awntALWh03PewmIJuzbALScsTS4sZoS1fKciBGoh11gIfHzylvkdNe/hJl66/RGqrj5rFb08sAABNTzDTiqqNpJeBsYs/c2aiGozptX2RlnBktH+SUNpAajW724Nv2Wvhif6sFAgMBAAGjge4wgeswHQYDVR0OBBYEFJaffLvGbxe9WT9S1wob7BDWZJRrMIG7BgNVHSMEgbMwgbCAFJaffLvGbxe9WT9S1wob7BDWZJRroYGUpIGRMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbYIBADAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAIFfOlaagFrl71+jq6OKidbWFSE+Q4FqROvdgIONth+8kSK//Y/4ihuE4Ymvzn5ceE3S/iBSQQMjyvb+s2TWbQYDwcp129OPIbD9epdr4tJOUNiSojw7BHwYRiPh58S1xGlFgHFXwrEBb3dgNbMUa+u4qectsMAXpVHnD9wIyfmHMYIBmjCCAZYCAQEwgZQwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tAgEAMAkGBSsOAwIaBQCgXTAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wNzAyMTcxMjIyMjlaMCMGCSqGSIb3DQEJBDEWBBTrPQMLeYPx4IW2vi7YaV1jMH5hBjANBgkqhkiG9w0BAQEFAASBgDgaxIivYAHrs6V3ypCtp2sCrFEO2Cqou1kP4cStxgCnEf2oXpp25PoDoUBWad5Tfs6uYwsDSLJQ9fPIgoaW8paa4CCXKjoDednHiB05RxvDFZViXMSX+uSc1C5HUCtrXEYMHoQoO46VuiEbH58XI7nahPLbmOKQC+Wg/Wcu03Tl-----END PKCS7-----
" name="encrypted" type="hidden"/&gt;
&lt;/form&gt;
&lt;p&gt;&lt;/p&gt;
&lt;hr  /&gt;
&lt;h2&gt;Archive Versions&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;
&lt;b&gt;Version 2.1.0.3&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.1.0.3.zip"
 onclick="javascript:urchinTracker('/downloads/XDMessaging-2.1.0.3.zip');"&gt;
                    XDMessaging Library 2.1.0.3&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Enhancements to IOStream mode for performance.&lt;/li&gt;
&lt;li&gt;Refactoring code to split DataGram into various implementations.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.1.0.0&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.1.0.0.zip"
 onclick="javascript:urchinTracker('/downloads/XDMessaging-2.1.0.0.zip');"&gt;
                    XDMessaging Library 2.1.0.0&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Adding error handling around mixed elevation scenarios.&lt;/li&gt;
&lt;li&gt;Obsolete APIs are now removed.&lt;/li&gt;
&lt;li&gt;Codebase migrated to VS2010.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.3.0&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.3.0.zip"
 onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.3.0.zip');"&gt;
                    XDMessaging Library 2.0.3.0&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Adding filter to remove duplicate MailSlot messages sent once per protocol.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.8&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.8.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.8.zip');"&gt;
                    XDMessaging Library 2.0.2.8&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Fixes to DataGram dispose bug, causing crashing on 64bit.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.7 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.7.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.7.zip');"&gt;
                    XDMessaging Library 2.0.2.7&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Fixing IOStream Mutex&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.6 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.6.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.6.zip');"&gt;
                    XDMessaging Library 2.0.2.6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Fixes to ensure MailSlot read handles are closed correctly.&lt;/li&gt;
&lt;li&gt;Removing Mutex on MailSlot writes.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.5 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.5.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.5.zip');"&gt;
                    XDMessaging Library 2.0.2.5&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Correcting MailSlot implementation to block rather than poll.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.4 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.4.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.4.zip');"&gt;
                    XDMessaging Library 2.0.2.4&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Workaround for MailSlot throughput limitations to minimize dropping of messages under load&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.3 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.3.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.3.zip');"&gt;
                    XDMessaging Library 2.0.2.3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Improving MailSlot listener to ensure MailSlot can be opened&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.2 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.2.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.2.zip');"&gt;
                    XDMessaging Library 2.0.2.2&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Improving exception handling, adding exception log to demo applications&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.1 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.1.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.1.zip');"&gt;
                    XDMessaging Library 2.0.2.1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Increasing robustness of MailSlot implementation through retry on IO fail&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.2.0 (beta)&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.2.0.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.2.0.zip');"&gt;
                    XDMessaging Library 2.0.2.0&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Implementation of MailSlots for IPC broadcasting as well as over a local Domain or Workgroup&lt;/li&gt;
&lt;li&gt;Option to broadcast messages in any mode over the local network&lt;/li&gt;
&lt;li&gt;Added Multi-broadcast API for broadcasting in multiple modes&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.1.0&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging-2.0.zip"
                    onclick="javascript:urchinTracker('/downloads/XDMessaging-2.0.zip');"&gt;
                    XDMessaging Library 2.0.1.0&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Performance enhancements&lt;/li&gt;
&lt;li&gt;Implementation of IDisposable on listener classes&lt;/li&gt;
&lt;li&gt;Mutex process synchronization on clean up of File IO&lt;/li&gt;
&lt;li&gt;Changed WindowsMessaging to only iterate and use top-level Windows&lt;/li&gt;
&lt;li&gt;Changed WindowsMessaging to use async message processing&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 2.0.0.0&lt;/b&gt;
&lt;ul&gt;
&lt;li&gt;Added support Windows Services, Console applications&lt;/li&gt;
&lt;li&gt;Added concept of transport modes, and refactored API to allow additional implementations&lt;/li&gt;
&lt;li&gt;Implemented IOStream for IO file based communication&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Version 1.0.0.0&lt;/b&gt;
&lt;ul class="download"&gt;
&lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk/software/xdmessaging/XDMessaging.zip"
                  onclick="javascript:urchinTracker('/downloads//downloads/XDMessaging.zip');"&gt;
                    XDMessaging Library 1.0.0.0&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Windows Services, Console applications are not supported&lt;/li&gt;
&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/sUdeMjXgkJ4" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-27T20:52:25.441+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/12/xdmessaging-downloads.html</feedburner:origLink></item><item><title>XDMessaging 3.0 : Documentation</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/nV3bB1kV64s/xdmessaging-20-documentation.html</link><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sun, 27 Mar 2011 13:45:11 PDT</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-8385981271193383259</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
&lt;p&gt;XDMessaging .Net Library 3.0&lt;/p&gt;
           &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="/2009/12/xdmessaging-net-library-20.html"
                    target="_self"&gt;Project home&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
            &lt;ul class="link"&gt;
                &lt;li&gt;&lt;a href="/2009/12/xdmessaging-downloads.html"
                    target="_self"&gt;Project downloads&lt;/a&gt; &lt;/li&gt;
            &lt;/ul&gt;
         &lt;ul class="link"&gt;
                &lt;li&gt;Project documentation&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;

&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;p&gt;The following API is all you need to start broadcasting and receiving messages across application, process and local network boundaries in your .Net application.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;XDTransportMode&lt;/h2&gt;
&lt;p&gt;This defines the implementation to use for broadcasting and receiving messages. There are currently three modes as follows, each with advantages over the other.&lt;/p&gt;

&lt;ul class="wideList"&gt;
&lt;li&gt;&lt;strong&gt;IOStream&lt;/strong&gt;: This uses file based IO to broadcast messages via a shared directory. A &lt;code&gt;FileSystemWatcher&lt;/code&gt; is used within listener classes to monitor changes and trigger the &lt;code&gt;MessageReceived&lt;/code&gt; event containing the broadcast message. This mode can be used in Windows Services, console applications, and Windows Forms based applications. Channels are created as separate directories on the file system for each channel. The temporary directories should be accessible by all processes, and there should be no need for manual configuration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;WindowsMessaging&lt;/strong&gt;: This uses the &lt;code&gt;WM_COPYDATA&lt;/code&gt; Windows message to copy data between applications. The broadcast implementation sends the Windows messages directly to a hidden window on the listener instance, which dispatches the &lt;code&gt;MessageReceived&lt;/code&gt; event with the copied data. Channels are created by adding/removing Windows properties. This offers the most performant solution for Windows Forms based applications, but does not work for Windows Services, console apps, or other applications without a message pump.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MailSlot&lt;/strong&gt;: This uses a &lt;code&gt;MailSlot&lt;/code&gt; to broadcast messages over the local network and interprocess. A limitation of the &lt;code&gt;MailSlot&lt;/code&gt; is that only one process may read the message within the scope of a single machine. The library uses a &lt;code&gt;Mutex&lt;/code&gt; to synchronize access to the &lt;code&gt;MailSlot&lt;/code&gt; across the system, and ensures that when one process terminates another listener can pick up further messages. This mode is used internally to send messages from other transport modes over the local network. Machines must be a member of the same &lt;i&gt;Domain&lt;/i&gt; or &lt;i&gt;Workgroup&lt;/i&gt; in order to send and receive MailSlot messages. MailSlot are not robust when used over the network and there may be a high drop rate using this implementation.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;IXDBroadcast&lt;/h2&gt;

&lt;p&gt;Use these implementations to broadcast string messages on named channel to other processes. Messages will be received by listeners in the same mode which have registered with the same named channel.

&lt;p&gt;&lt;b&gt;Example: Creating an instance.&lt;/b&gt;&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Create an instance of IXDBroadcast using IOStream mode
IXDBroadcast broadcast = XDBroadcast.CreateBroadcast(XDTransportMode.IOStream);

// or create an instance of IXDBroadcast using WindowsMessaging mode
IXDBroadcast broadcast = XDBroadcast.CreateBroadcast(XDTransportMode.WindowsMessaging);

// or create an instance of IXDBroadcast using MailSlot mode
IXDBroadcast broadcast = XDBroadcast.CreateBroadcast(XDTransportMode.MailSlot);
&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Example: Sending a message.&lt;/b&gt;&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Send shutdown message to a channel named commands
broadcast.SendToChannel("commands", "shutdown");

// Send serializable object to a channel named binary1
broadcast.SendToChannel(&amp;quot;binary1&amp;quot;, new CustomData(&amp;quot;Some text&amp;quot;));
&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Example: Network propagation&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Set the optional &lt;code&gt;propagateNetwork&lt;/code&gt; parameter to &lt;code&gt;true&lt;/code&gt; in order to send messages to listeners on other machines. Network messages are received by all listener instances which are in the same mode and channel as the broadcast instance. For network communication the machines must be on the same &lt;i&gt;Domain&lt;/i&gt; or &lt;i&gt;Workgroup&lt;/i&gt;.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;

// create an instance of IXDBroadcast and allow network propagation
IXDBroadcast broadcast = XDBroadcast.CreateBroadcast(XDTransportMode.WindowsMessaging, true);

// Send a message on the commands channel to all listeners on the local network
// which are in WindowsMessaging mode
broadcast.SendToChannel("commands", "doWork");
&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Example: Multi-broadcast&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;This example shows how to send messages using multiple modes at the same time.&lt;/p&gt;
&lt;pre class="brush: csharp"&gt;
// create an instance of IXDBroadcast which uses multiple modes
IXDBroadcast broadcast = XDBroadcast.CreateBroadcast(
                               XDTransportMode.WindowsMessaging,
                               XDTransportMode.IOStream);

// Dispatch to all listeners in either modes
broadcast.SendToChannel("commands", "doWork");
&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;IXDListener&lt;/h2&gt;

&lt;p&gt;Use these implementations to receive events when messages are broadcast from other processes. Events will only occur if the listener is in the same mode as the broadcasting instance, and if it's listening on the same channel.&lt;/p&gt;

&lt;p&gt;By default each listener is capable of acting as a system-wide listener for network messages propagated over the network in order that they may be re-distributed to all processes on the same machine. By setting the optional &lt;code&gt;excludeNetworkMessages&lt;/code&gt; flag to true the listener will not take part in listening for network messages. With this setting however the instance may still receive network messages that have been re-broadcast by other listeners in the same mode.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;Example: Creating an instance.&lt;/b&gt;&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Create our listener instance using IOStream mode
IXDListener listener = XDListener.CreateListener(XDTransportMode.IOStream);

// or create our listener using WindowsMessaging mode
IXDListener listener = XDListener.CreateListener(XDTransportMode.WindowsMessaging);
&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Example: Registering an unregistering channels.&lt;/b&gt;&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Register channels to listen on
listener.RegisterChannel("events");
listener.RegisterChannel("status");
listener.RegisterChannel("commands");

// Stop listening on a specific channel
listener.UnRegisterChannel("status");
&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;Example: Handling the MessageReceived event.&lt;/b&gt;&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Attach an event handler to a listener instance
listener.MessageReceived+=XDMessageHandler(this.listener_MessageReceived);

// process the message
private void listener_MessageReceived(object sender, XDMessageEventArgs e)
{
    // e.DataGram.Message is the message
    // e.DataGram.Channel is the channel name
    if (e.DataGram.Channel == "commands")
    {
       switch(e.DataGram.Message)
       {
           case "shutdown":
             this.Close();
             break;
       }
    }
}
&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Example: Handling a serialized messages:&lt;/b&gt;&lt;/p&gt;
 
&lt;pre class="brush: csharp"&gt;// Attach an event handler to a listener instance
listener.MessageReceived+=XDMessageHandler(this.listener_MessageReceived);
 
// process the message
private void listener_MessageReceived(object sender, XDMessageEventArgs e)
{
 switch(e.DataGram.Channel)
 {
  case &amp;quot;binary1&amp;quot;:
      TypedDataGram&amp;lt;CustomData&amp;gt; typedMsg = e.DataGram;
      UserMessage customData = typedMsg.Message;
      // do something with customData
      break;
 }
}&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Example: Dispose IXDListener to release resources.&lt;/b&gt;&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
// Create our listener instance using IOStream mode
IXDListener listener = XDListener.CreateListener(XDTransportMode.IOStream);

// when no longer needed ensure it's disposed
// without this the IOStream listener will continue using resources to listen for messages
listener.Dispose();

// create a new instance
listener = XDListener.CreateListener(XDTransportMode.WindowsMessaging);
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/nV3bB1kV64s" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-27T21:45:11.774+01:00</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/12/xdmessaging-20-documentation.html</feedburner:origLink></item><item><title>Ghosting the Unghostable</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/AsIm9nfUs_o/ghosting-unghostable.html</link><category>Sharepoint</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sat, 05 Dec 2009 18:26:22 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-5778858571497355262</guid><description>&lt;div class="leftBox"&gt;
        &lt;div class="downloadBoxTop"&gt;
            &lt;p&gt;Download the sample code.&lt;/p&gt;
            &lt;ul class="download"&gt;
                &lt;li&gt;&lt;a href="http://s3.thecodeking.co.uk.s3.amazonaws.com/software/ReghostSample/CodeKing.Reghost.zip" target="_blank" onclick="javascript:urchinTracker('/downloads/CodeKing.Reghost.zip');"&gt;                   CodeKing.Reghost.zip&lt;/a&gt;&lt;/li&gt;
            &lt;/ul&gt;
        &lt;/div&gt;
    &lt;/div&gt;
&lt;h2&gt;Introduction&lt;/h2&gt; 
 
&lt;p&gt;This article shows a way to remap a ghosted file to a new location, and also shows how to ghost a non-ghostable file, such as one originally created via SharePoint designer. This assumes a basic knowledge of SharePoint and the concept of ghosted and unghosted files.&lt;/p&gt; 
 
&lt;p&gt;This is actually a trick which overwrites the existing file with a new ghosted version. To actually modify a non-ghostable file so that it becomes ghostable is near on impossible without committing the cardinal sin of modifying the content database directly. An alternative is to delete the original and deploy the ghosted version in its place; however, problems arise with layouts (for example) that may still be referenced by existing content. I found the following technique overcomes these issues and allows files to be swapped out with a ghosted version seamlessly.&lt;/p&gt; 
 
&lt;p&gt;Note: if your desire is simply to reghost an existing file, then I recommend one of the many existing tools available, such as &lt;a href="http://stsadm.blogspot.com/2007/09/re-ghosting-pages.html"&gt;gl-reghostfile&lt;/a&gt;.&lt;/p&gt; 
 
&lt;h2&gt;The Solution&lt;/h2&gt; 
 
&lt;p&gt;In this example, we will remap the &lt;code&gt;ArticleLeft&lt;/code&gt; layout from the SharePoint publishing template to an updated version deployed via our sample feature. This changes the location of the ghosted file to that of our feature, and allows us to deploy subsequent changes to the &lt;code&gt;ArticleLeft&lt;/code&gt; layout by upgrading the new solution. The sample adds the word &lt;em&gt;MODIFIED&lt;/em&gt; to the page title of the template.&lt;/p&gt; 
 
&lt;p&gt;The first step is to save out the existing file from the SharePoint database using the SharePoint designer. This is then added to a feature in the usual way as if you were provisioning it for the first time. In the case of layouts, be sure to also provision the properties from the original file; otherwise, the new layout will not behave correctly.&lt;/p&gt; 
 
&lt;pre class="brush: xml"&gt;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot; ?&amp;gt;
&amp;lt;Elements xmlns=&amp;quot;http://schemas.microsoft.com/sharepoint/&amp;quot;&amp;gt;
  &amp;lt;Module Url=&amp;quot;_catalogs/masterpage&amp;quot; Path=&amp;quot;Layouts&amp;quot;&amp;gt;
    &amp;lt;File Url=&amp;quot;ArticleLeft_Ghosted.aspx&amp;quot; 
         Type=&amp;quot;GhostableInLibrary&amp;quot; IgnoreIfAlreadyExists=&amp;quot;true&amp;quot;&amp;gt;
      &amp;lt;Property Name=&amp;quot;Title&amp;quot; 
         Value=&amp;quot;Modified Article page with image on left&amp;quot; /&amp;gt;
      &amp;lt;Property Name=&amp;quot;MasterPageDescription&amp;quot; 
         Value=&amp;quot;The modified article page with image on left contains 
                an image field and a rich text field.&amp;quot; /&amp;gt;
      &amp;lt;Property Name=&amp;quot;ContentType&amp;quot; 
         Value=&amp;quot;Page Layout&amp;quot; /&amp;gt;
      &amp;lt;Property Name=&amp;quot;PublishingPreviewImage&amp;quot; 
         Value=&amp;quot;/_catalogs/masterpage/en-US/Preview Images/ArticleLeft.png, 
                /_catalogs/masterpage/en-US/Preview Images/ArticleLeft.png&amp;quot; /&amp;gt;
      &amp;lt;Property Name=&amp;quot;PublishingAssociatedContentType&amp;quot; 
         Value=&amp;quot;;#Article Page;#0x010100C568DB52D9D0A14D9B2FDCC96666E9F2007
                948130EC3DB064584E219954237AF3900242457EFB8B24247815D688C526CD44D;#&amp;quot; /&amp;gt;
    &amp;lt;/File&amp;gt;
  &amp;lt;/Module&amp;gt;
&amp;lt;/Elements&amp;gt;&lt;/pre&gt; 
 
&lt;p&gt;The next step is to rename the file so that it can initially be deployed alongside the the existing layout. In the example included, I have named the file &lt;em&gt;ArticleLeft_Ghosted.aspx&lt;/em&gt;.&lt;/p&gt; 
 
&lt;p&gt;Lastly, we add a feature receiver with the following code to overwrite the target file with the new ghosted version. Note: this code has been simplified for brevity; see the sample for full code.&lt;/p&gt; 
 
&lt;pre class="brush: csharp"&gt;public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    SPSite site = properties.Feature.Parent as SPSite;
 
    PublishingWeb pubweb = PublishingWeb.GetPublishingWeb(site.RootWeb);
 
    // get reference to newly provisioned file
    SPFile file = site.RootWeb.GetFile(&amp;quot;/_catalogs/masterpage/ArticleLeft_Ghosted.aspx&amp;quot;);
    if (file != null)
    {
        // overwrite the old layout with the ghosted version
        file.MoveTo(&amp;quot;/_catalogs/masterpage/ArticleLeft.aspx&amp;quot;, true);
        file.Update();
    }
}&lt;/pre&gt; 
 
&lt;p&gt;Once overwritten, the new version of the file remains ghosted. In the case of layouts and master pages, all existing content will begin to use the ghosted version. The key to the technique is the &lt;code&gt;MoveTo&lt;/code&gt; command which allows any referenced layout to be overwritten without breaking references to existing content.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/AsIm9nfUs_o" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-06T02:26:22.147Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/12/ghosting-unghostable.html</feedburner:origLink></item><item><title>Intermittent access denied</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/WobjAT49b18/intermittent-access-denied.html</link><category>Sharepoint Tips</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Fri, 11 Dec 2009 15:04:55 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-9165270591386820262</guid><description>&lt;p&gt;The following is an interesting error I recently came across in SharePoint on an application inherited from another company. For some reason (probably accidently) they had enabled the batch compilation setting in the web.config as follows.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;compilation batch=&amp;quot;true&amp;quot; debug=&amp;quot;false&amp;quot; /&amp;gt;
&lt;/pre&gt;

&lt;p&gt;This resulted in a particular page on the website throwing a 401 error intermittently, and prompting the user to authenticate. After repeated requests the error would disappear and the page would display as normal. We finally worked out that this was happening on application re-start. SharePoint logs recorded an unhelpful &lt;span style="font-style:italic;"&gt;Access Denied&lt;/span&gt; entry with no further details.&lt;/p&gt; 

&lt;p&gt;It turns out that the batch compilation setting is not supported in SharePoint as discussed in &lt;a href="http://support.microsoft.com/kb/953459"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The fix was to turn off batch compilation, and the page then behaved as normal.&lt;/p&gt;

&lt;pre&gt;
&amp;lt;compilation batch=&amp;quot;false&amp;quot; debug=&amp;quot;false&amp;quot; /&amp;gt;
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/WobjAT49b18" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-11T23:04:55.975Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/09/intermittent-access-denied.html</feedburner:origLink></item><item><title>Exception from HRESULT: 0x80040E14</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/lvqDnDQPq34/exception-from-hresult-0x80040e14.html</link><category>Sharepoint Tips</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Fri, 11 Dec 2009 15:05:12 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-5710511830975973783</guid><description>&lt;p&gt;During restore of a SharePoint application with &lt;code&gt;stsadm -o restore&lt;/code&gt; command I recently came across the following error:&lt;/p&gt;

&lt;pre&gt;
Exception from HRESULT: 0x80040E14
&lt;/pre&gt;

&lt;p&gt;It turns out this happens when the database does not have enough disk space to complete the task. Freeing up some space on the db server resolved the issue.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/lvqDnDQPq34" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-11T23:05:12.756Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/09/exception-from-hresult-0x80040e14.html</feedburner:origLink></item><item><title>Using SharePoint and log4net in harmony</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/cpiphwuaqfE/using-sharepoint-and-log4net-in-harmony.html</link><category>Sharepoint</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sat, 05 Dec 2009 18:28:19 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-4754455992190923273</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt; 
 
&lt;p&gt;With traditional .NET applications, configuring log4net is relatively straightforward by simply changing the &lt;em&gt;web.config&lt;/em&gt; and using xcopy deployment. In SharePoint, however, things become a little more complicated, and getting log4net working effectively takes a little more effort.&lt;/p&gt; 
 
&lt;p&gt;Firstly, it's not recommended that you modify the &lt;em&gt;web.config&lt;/em&gt; manually or use xcopy deployments when working with SharePoint. This breaks the whole SharePoint model, and is likely to cause issues later on (for instance, when joining a new FTE server to the farm or extending an application). I'm a firm believer in repeatable builds and deploying everything via solutions and features, so this is not an option.&lt;/p&gt; 
 
&lt;p&gt;Secondly, not all code executes within the web application context. Take feature receivers and jobs, for example; depending on how they are invoked, these could run within the &lt;code&gt;&lt;em&gt;stsadm&lt;/em&gt;&lt;/code&gt; process or within &lt;code&gt;&lt;em&gt;OWSTimer&lt;/em&gt;&lt;/code&gt;. Setting up your &lt;code&gt;log4net&lt;/code&gt; settings in the &lt;em&gt;web.config&lt;/em&gt; can therefore be somewhat futile for debugging these components.&lt;/p&gt; 
 
&lt;h2&gt;Solution&lt;/h2&gt; 
 
&lt;p&gt;The solution I recommend is to deploy log4net into the GAC, and &lt;em&gt;log4net.config&lt;/em&gt; to the 12 hive (using &lt;a href="http://www.codeplex.com/wspbuilder"&gt;WSPBuilder&lt;/a&gt;). It's then possible to pass the location of the &lt;em&gt;config&lt;/em&gt; file to log4net on initialize by simply adding the following line to your &lt;em&gt;AssemblyInfo.cs&lt;/em&gt; file.&lt;/p&gt; 
 
&lt;pre class="brush: csharp"&gt;[assembly: log4net.Config.XmlConfigurator(ConfigFile = 
  @&amp;quot;C:\Program Files\Common Files\Microsoft Shared\&amp;quot; + 
  @&amp;quot;Web Server Extensions\12\CONFIG\log4net.config&amp;quot;, Watch = true)]&lt;/pre&gt; 
 
&lt;p&gt;Note that although this requires hard-coding the location of your previously deployed &lt;em&gt;config&lt;/em&gt; file, I feel that it's acceptable as the path never changes between SharePoint installations. I would deploy the log4net assembly and config within a globally scoped solution rather than packaging with your main application codebase. The reasons for this are discussed briefly in a previous article &lt;a href="http://www.thecodeking.co.uk/2009/11/be-afraid-retractsolution-with.html"&gt;here&lt;/a&gt;, and will reduce risk with managing shared resources in the farm.&lt;/p&gt; 
 
&lt;p&gt;Often, you may wish to have different log4net configurations per environment. If this is the case, I recommend using a different technique for configuring the location of the log4net &lt;em&gt;config&lt;/em&gt; file within your codebase. This allows you to inject some additional application logic to determine the location of your &lt;em&gt;config&lt;/em&gt; file.&lt;/p&gt; 
 
&lt;pre class="brush: csharp"&gt;public static void InitializeLog4Net(string environment)
{ 
   string configFile = string.Concat(&amp;quot;log4net.&amp;quot;,environment,&amp;quot;.config&amp;quot;);
   FileInfo configFileInfo = new FileInfo(@&amp;quot;C:\Program Files\Common Files\&amp;quot; + 
     @&amp;quot;Microsoft Shared\Web Server Extensions\12\CONFIG\log4net\&amp;quot;+ configFile);
   log4net.Config.XmlConfigurator.ConfigureAndWatch(configFileInfo);
}&lt;/pre&gt; 
 
&lt;h2&gt;Summary&lt;/h2&gt; 
 
&lt;p&gt;The beauty of this solution is that log4net settings may be managed across the entire farm centrally. It also doesn't matter how your code is executed or what process it's running in, all log messages will be processed according to your settings. Use filters to customize log messages for different applications from the one &lt;em&gt;config&lt;/em&gt; file.&lt;/p&gt; 
 
&lt;p&gt;For debugging feature receivers and jobs, I highly recommend configuring the log4net &lt;code&gt;OutputDebugStringAppender&lt;/code&gt; and using the Sysinternals &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx"&gt;DebugView&lt;/a&gt;. This allows you to see your debug code in real-time, and can easily be switched on in various environments without the need for a debug build.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/cpiphwuaqfE" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-06T02:28:19.586Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/11/using-sharepoint-and-log4net-in-harmony.html</feedburner:origLink></item><item><title>Working with SPWebConfigModification</title><link>http://feeds.thecodeking.co.uk/~r/co/izpV/~3/3UCD77iL8PI/working-with-spwebconfigmodification.html</link><category>Sharepoint</category><author>noreply@blogger.com (TheCodeKing)</author><pubDate>Sat, 05 Dec 2009 18:28:58 PST</pubDate><guid isPermaLink="false">tag:blogger.com,1999:blog-8290471407463655572.post-1713273380470873339</guid><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;The following tips relate to working with the SharePoint &lt;code&gt; SPWebConfigModification&lt;/code&gt; API in order to manage changes to the &lt;code&gt;web.config&lt;/code&gt;. Note it's not recommended that you modify the &lt;code&gt;web.config&lt;/code&gt; directly as this may have side effects with the running of your SharePoint instance, and changes may be lost when installing updates or service packs.&lt;p&gt;

&lt;h2&gt;Avoiding Duplicates&lt;/h2&gt;

&lt;p&gt;When working with the &lt;code&gt;SPWebConfigModification&lt;/code&gt; API, the &lt;code&gt;name&lt;/code&gt; property should be set to an xPath expression that identifies the configuration change being made. This should be an expression relative to the &lt;code&gt;Path&lt;/code&gt; property. This prevents duplicate changes being made in the web.config. If an arbitrary name is used instead, then the system will not throw an error but may lead to duplicate entries.&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
SPWebService service = SPWebService.ContentService;

SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;

myModification.Path = "configuration/system.web/httpModules";

myModification.Name = "add[@name='myModule']";

myModification.Sequence = 0;
myModification.Owner = this.GetType().FullName;
myModification.Type = SPWebConfigModification.SPWebConfigModificationType.EnsureChildNode;
myModification.Value = "&amp;lt;add name='myModule' type='myModule, myAssembly' /&amp;gt;";

service.WebConfigModifications.Add(myModification);
service.Update();
service.ApplyWebConfigModifications();

&lt;/pre&gt;

&lt;h2&gt;Removing Entries&lt;/h2&gt;

&lt;p&gt;To ensure your entries can be removed via code (such on feature deactivate), it's a good idea to set the owner of the &lt;code&gt;SPWebConfigModification&lt;/code&gt; instance as in the example above. It's then possible to loop through the config settings and remove the entries that were previously set by the same codebase&lt;/p&gt;

&lt;pre class="brush: csharp"&gt;
SPWebApplication webApp = properties.Feature.Parent as SPWebApplication;
Collection&lt;SPWebConfigModification&gt; modsCollection = webApp.WebConfigModifications;
int count = modsCollection.Count;
for (int i = count-1; c &gt;= 0; i--)
{
 SPWebConfigModification mod = modsCollection[i];
 if (mod.Owner == this.GetType().FullName)
 {
  modsCollection.Remove(mod);
 }
}
webApp.Update();
webApp.Farm.Services.GetValue&lt;SPWebService&gt;().ApplyWebConfigModifications();
&lt;/pre&gt;&lt;img src="http://feeds.feedburner.com/~r/co/izpV/~4/3UCD77iL8PI" height="1" width="1"/&gt;</description><app:edited xmlns:app="http://www.w3.org/2007/app">2009-12-06T02:28:58.712Z</app:edited><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://www.thecodeking.co.uk/2009/11/working-with-spwebconfigmodification.html</feedburner:origLink></item></channel></rss>
