<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:blogger="http://schemas.google.com/blogger/2008" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;Ck8FSXw_eSp7ImA9WhBbFU8.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705</id><updated>2013-05-14T10:40:18.241+02:00</updated><category term="AOP" /><category term="LINQ" /><category term="WebServices" /><category term="Team Foundation Server" /><category term="REST" /><category term="Dependency Injection" /><category term="SQL Server" /><category term="AppFabric" /><category term="Continuous integration" /><category term="Castle" /><category term="Security" /><category term="SQL Service Broker" /><category term="Ajax" /><category term="ASP.NET" /><category term="ADO.NET" /><category term="C#" /><category term="JQuery" /><category term="Other" /><category term="WCF" /><category term="Enterprise Library" /><category term="WCFWebAPIs" /><category term="Certifications" /><category term="Spring.NET" /><category term="Code generation" /><category term="JSON" /><title>Javi's technical blog</title><subtitle type="html">Random thoughts on .NET and other technologies</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://javiercrespoalvez.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>26</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/JavisTechnicalBlog" /><feedburner:info uri="javistechnicalblog" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>JavisTechnicalBlog</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2FJavisTechnicalBlog" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FJavisTechnicalBlog" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2FJavisTechnicalBlog" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/JavisTechnicalBlog" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2FJavisTechnicalBlog" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2FJavisTechnicalBlog" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2FJavisTechnicalBlog" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><feedburner:browserFriendly>(Enter a personal message you would like to have appear at the top of your feed.)</feedburner:browserFriendly><entry gd:etag="W/&quot;D04NQXo6cSp7ImA9WhZaEkU.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-406007778696698263</id><published>2011-06-28T18:45:00.000+02:00</published><updated>2011-06-28T20:33:10.419+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-28T20:33:10.419+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WCFWebAPIs" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>ETags and optimistic concurrency control with WCF Web Apis</title><content type="html">&lt;p&gt;In my previous post I wrote about how to take advantage of ETags to implement HTTP cache validation with WcfWebApis, but this is not the only use of ETags, you can also use them to implement optimistic concurrency control over HTTP. The following workflow illustrates this feature:&lt;/p&gt; &lt;ol&gt; &lt;li&gt;The client wants to get a resource and for that it sends a GET request and the server answers with the resource representation and its ETag.  &lt;li&gt;The client decides to update the resource and for that it sends a PUT request with the modified resource representation along with the ETag from the previous step.  &lt;li&gt;The server checks the incoming ETag against the current resource representation ETag from its repository (i.e: Cache, DB).  &lt;ul&gt; &lt;li&gt;If they match, the server carries on with the resource update and returns a 200 HTTP status if it succeeds.  &lt;li&gt;If they don’t match, it’s because someone else has updated the resource in the meantime. Therefore the server invalidates the request and returns a 402 Precondition Failed status. (Concurrency error)&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;Now replace “GET” by “SELECT” and “PUT” by “UPDATE… WHERE” and this is exactly the same optimistic concurrency mechanism that you can usually find implemented in relational databases.&lt;/p&gt; &lt;p&gt;Enough of theory, we can implement step 3 from the workflow with a DelegatingChannel. The channel takes advantage of the ETag cache that I used in my previous post.&lt;/p&gt; &lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 600px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; EntityTagConcurrencyChannel : DelegatingChannel&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;{&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; ETagCache _eTagCache = ETagCacheProvider.Instance;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; EntityTagConcurrencyChannel(HttpMessageChannel innerChannel)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(innerChannel)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Task&amp;lt;HttpResponseMessage&amp;gt; SendAsync(HttpRequestMessage request, &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                                                  CancellationToken cancellationToken)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (request.Method == HttpMethod.Put &amp;amp;&amp;amp; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            request.Headers.IfNoneMatch.Any())&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            var etag = request.Headers.IfNoneMatch.First().ToString();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (etag != &lt;span style="color: #006080"&gt;"*"&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                var cached = _eTagCache.Get(request.RequestUri.ToString());&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; etag != cached&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                  ? Task.Factory.StartNew(() =&amp;gt; CreatePreconditionFailedResponse(),&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                                                    cancellationToken)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                  : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.SendAsync(request, cancellationToken);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.SendAsync(request, cancellationToken);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; HttpResponseMessage CreatePreconditionFailedResponse()&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpResponseMessage(HttpStatusCode.PreconditionFailed, &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                                        &lt;span style="color: #006080"&gt;"If-None-Match"&lt;/span&gt;);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;As per the HTTP specification, the special wildcard “*” value makes the server not to run the validation.   </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/406007778696698263/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2011/06/etags-and-optimistic-concurrency.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/406007778696698263?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/406007778696698263?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/3MqIFuB2lPI/etags-and-optimistic-concurrency.html" title="ETags and optimistic concurrency control with WCF Web Apis" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2011/06/etags-and-optimistic-concurrency.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cERHw4fip7ImA9WhZaEE8.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-7539808343928518648</id><published>2011-06-25T19:01:00.001+02:00</published><updated>2011-06-25T20:03:25.236+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-25T20:03:25.236+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WCFWebAPIs" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>ETags with WCF Web APIs Preview 4</title><content type="html">&lt;p&gt;&lt;a href="http://joseoncode.com/" target="_blank"&gt;Jose Romaniello&lt;/a&gt; wrote a very nice &lt;a href="http://joseoncode.com/2011/04/27/rest-and-the-http-cache-with-wcf-web-api/" target="_blank"&gt;blog post&lt;/a&gt; about to handle HTTP cache validation with ETags and the WCF Web APIs. For the ETags server implementation there are two different aspects to be considered: the code that checks if a resource has been modified based on the incoming request ETag value (this is handled by a DelegatingChannel in Jose’s implementation), and the part where the resource ETag is added to the response so the client can use this value to make further requests (In Jose’s implementation this is handled on case by case basis in every resource handler). I was interested to see if the second part could be handled in a generic and automated way by using some conventions, so the custom logic in the resource handler could be spared. So let’s get started!  &lt;p&gt; &lt;p&gt;First of all, let’s define the resource.&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ProductResource&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;{&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;int&lt;/span&gt; Id { get; set; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Name { get; set; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;float&lt;/span&gt; Price { get; set; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ETag { get; set; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br&gt;As in Jose’s post, for the ETag value we can use the DB version field for example. The resource handler goes as follows. &lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 400px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;[ServiceContract]&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ProductResourceHandler&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;{&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; ProductRepository _productRepository = &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ProductRepository();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    [WebGet(UriTemplate = &lt;span style="color: #006080"&gt;"{id}"&lt;/span&gt;)]&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; HttpResponseMessage&amp;lt;ProductResource&amp;gt; Get(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; id)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        var product = _productRepository.Get(id);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; product == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ? &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpResponseMessage&amp;lt;ProductResource&amp;gt;(HttpStatusCode.NotFound) &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                               : &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpResponseMessage&amp;lt;ProductResource&amp;gt;(product);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    [WebInvoke(UriTemplate = &lt;span style="color: #006080"&gt;"{id}"&lt;/span&gt;, Method = &lt;span style="color: #006080"&gt;"PUT"&lt;/span&gt;)]&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; ProductResource Put(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; id, ProductResource product)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        _productRepository.Save(product);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; product;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    [WebInvoke(UriTemplate = &lt;span style="color: #006080"&gt;"{id}"&lt;/span&gt;, Method = &lt;span style="color: #006080"&gt;"DELETE"&lt;/span&gt;)]&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; HttpResponseMessage Delete(&lt;span style="color: #0000ff"&gt;int&lt;/span&gt; id)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        var product = _productRepository.Get(id);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (product == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpResponseMessage&amp;lt;ProductResource&amp;gt;(HttpStatusCode.NotFound);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        _productRepository.Delete(product);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; HttpResponseMessage(HttpStatusCode.OK, &lt;span style="color: #006080"&gt;"Deleted"&lt;/span&gt;);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;The EntityTagResponseHandlerChannel handles the ETag injection to the responses. On top of that, when a PUT or DELETE request succeeds, the channel removes the ETag associated to the incoming url from the cache. This ensures that further GET request won’t get a stale version of the resource. &lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 550px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; EntityTagResponseHandlerChannel : DelegatingChannel&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; ETagCache _eTagCache = ETagCacheProvider.Instance;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;  &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; EntityTagResponseHandlerChannel(HttpMessageChannel innerChannel)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;         : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(innerChannel)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;  &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Task&amp;lt;HttpResponseMessage&amp;gt; SendAsync(HttpRequestMessage request, &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;                                                             CancellationToken cancellationToken)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.SendAsync(request, cancellationToken).ContinueWith(task =&amp;gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;         {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;             var response = task.Result;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (response.StatusCode != HttpStatusCode.OK) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; response;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;             var requestMethod = response.RequestMessage.Method;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (requestMethod == HttpMethod.Put || requestMethod == HttpMethod.Delete)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;             {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;                 _eTagCache.Remove(response.RequestMessage.RequestUri.ToString());&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;             }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;else&lt;/span&gt; &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (requestMethod == HttpMethod.Get || requestMethod == HttpMethod.Head)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;             {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;                 &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (SetETag(response))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;                 {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;                     _eTagCache.Add(response.RequestMessage.RequestUri.ToString(), &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt;                                     response.Headers.ETag.ToString());&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum28"&gt;  28:&lt;/span&gt;                 }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum29"&gt;  29:&lt;/span&gt;             }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum30"&gt;  30:&lt;/span&gt;  &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum31"&gt;  31:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; response;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum32"&gt;  32:&lt;/span&gt;         });&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum33"&gt;  33:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum34"&gt;  34:&lt;/span&gt;  &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum35"&gt;  35:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; SetETag(HttpResponseMessage response)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum36"&gt;  36:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum37"&gt;  37:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (response.Headers.ETag != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; || response.Content == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum38"&gt;  38:&lt;/span&gt;             &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum39"&gt;  39:&lt;/span&gt;         dynamic content = response.Content;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum40"&gt;  40:&lt;/span&gt;         response.Headers.ETag = ETagProvider.GetETag(content.ReadAs());&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum41"&gt;  41:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; response.Headers.ETag != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum42"&gt;  42:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum43"&gt;  43:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;Note that we check if the ETag has been previously been set (line 37) meaning that custom ETag handling logic in the resource handler overrides the Channel logic. &lt;br&gt;&lt;br&gt;The tricky part here is to get the ETag value from the resource associated to the response. The object contained in the response variable is a generic HttpResponseMessage&amp;lt;TResource&amp;gt; that contains the original resource. The problem is that, as the DelegatingChannels are non-generic objects, they can only reference the non-generic versions of the response entities (HttpResponseMessage, ObjectContent base classes) which don’t have access to the original resource object.&amp;nbsp; Since casting to the generic version is out of the question (this Channel should handle any resource type request), we take advantage of a dynamic variable to execute the generic ReadAs method that gives us the original resource entity (line 40).&lt;br/&gt;&lt;br/&gt;Finally the ETagProvider retrieves the ETag from the resource object if exists. &lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 350px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum1"&gt;   1:&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ETagProvider&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum2"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum3"&gt;   3:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;readonly&lt;/span&gt; ConcurrentDictionary&amp;lt;Type, PropertyInfo&amp;gt; ETagPropertyInfoByType = &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum4"&gt;   4:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; ConcurrentDictionary&amp;lt;Type, PropertyInfo&amp;gt;();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum5"&gt;   5:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;const&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ETagPropertyName = &lt;span style="color: #006080"&gt;"ETag"&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum6"&gt;   6:&lt;/span&gt;  &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum7"&gt;   7:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;internal&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; EntityTagHeaderValue GetETag(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; resource)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum8"&gt;   8:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum9"&gt;   9:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (resource == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum10"&gt;  10:&lt;/span&gt;         var resourceType = resource.GetType();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum11"&gt;  11:&lt;/span&gt;         PropertyInfo propertyInfo;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum12"&gt;  12:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!ETagPropertyInfoByType.TryGetValue(resourceType, &lt;span style="color: #0000ff"&gt;out&lt;/span&gt; propertyInfo))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum13"&gt;  13:&lt;/span&gt;         {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum14"&gt;  14:&lt;/span&gt;             propertyInfo = resourceType.GetProperty(ETagPropertyName);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum15"&gt;  15:&lt;/span&gt;             ETagPropertyInfoByType.AddOrUpdate(resourceType, propertyInfo, (t, p) =&amp;gt; p);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum16"&gt;  16:&lt;/span&gt;         }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum17"&gt;  17:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; GetETag(resource, propertyInfo);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum18"&gt;  18:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum19"&gt;  19:&lt;/span&gt;  &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum20"&gt;  20:&lt;/span&gt;     &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; EntityTagHeaderValue GetETag(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; resource, PropertyInfo propertyInfo)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum21"&gt;  21:&lt;/span&gt;     {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum22"&gt;  22:&lt;/span&gt;         &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; propertyInfo == &lt;span style="color: #0000ff"&gt;null&lt;/span&gt; ? &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum23"&gt;  23:&lt;/span&gt;                                     : &lt;span style="color: #0000ff"&gt;new&lt;/span&gt; EntityTagHeaderValue(String.Format(CultureInfo.InvariantCulture,&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum24"&gt;  24:&lt;/span&gt;                                                                 &lt;span style="color: #006080"&gt;"\"{0}\""&lt;/span&gt;,&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum25"&gt;  25:&lt;/span&gt;                                                                 propertyInfo.GetValue(resource, &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)));&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum26"&gt;  26:&lt;/span&gt;     }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #606060" id="lnum27"&gt;  27:&lt;/span&gt; }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;The ETag property is retrieved by using Reflection and a dictionary of PropertyInfos by type is used to improve performance.&lt;/br&gt;&lt;br /&gt;&lt;h3&gt;In closing&lt;/h3&gt;&lt;br /&gt;HTTP cache expiration could be implemented in a similar way by using for example a .NET attribute defining the resource MaxAge, then a DelegatingChannel would grab this value and add it to the associated response.&lt;br/&gt;&lt;br /&gt;Nevertheless, bear in mind that this is by no means production-ready code! My main purpose with this post was to show how the Wcf Web Apis infrastructure can be leveraged to implement HTTP protocol features such as cache validation.  </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/7539808343928518648/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2011/06/etags-with-wcf-web-apis-preview-4.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/7539808343928518648?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/7539808343928518648?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/BnlTnX4bD38/etags-with-wcf-web-apis-preview-4.html" title="ETags with WCF Web APIs Preview 4" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2011/06/etags-with-wcf-web-apis-preview-4.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ECSHs5eSp7ImA9WhZUF08.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-9105231759799417385</id><published>2011-06-10T17:54:00.001+02:00</published><updated>2011-06-10T18:01:09.521+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-06-10T18:01:09.521+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="AppFabric" /><title>AppFabric Cache: Setting MaxBufferSize in a SQL Sever-based cluster configuration</title><content type="html">&lt;p&gt;The AppFabric Cache limits by default the size of individual items to 8MB. If you've gone over that limit, you have probably got this error already:&lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;p&gt;&lt;em&gt;ErrorCode&amp;lt;ERRCA0016&amp;gt;:SubStatus&amp;lt;ES0001&amp;gt;:The connection was terminated, possibly due to server or network problems or serialized Object size is greater than MaxBufferSize on server. Result of the request is unknown.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;To increase the limit, you can override the default MaxBufferSize value in the cluster XML configuration file.&lt;/p&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;advancedProperties&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;      &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;transportProperties&lt;/span&gt; &lt;span style="color: #ff0000"&gt;maxBufferSize&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="10000000"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;advancedProperties&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;But what happens if you're using SQL Server as the AppFabric Cache cluster configuration store? If you take a look at the Config DB, you'll quickly realize that the data stored over there looks nothing like the original xml. So how can we change this setting?&lt;br/&gt;&lt;br /&gt;PowerShell to the rescue!&amp;nbsp; Use the command below to extract the configuration file that represents your cluster configuration. The command works regardless of the underlying configuration stored being used.&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;Export-CacheClusterConfig -File c:\config.xml &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Do the change in the file, stop the cluster, import the ammended config file and start the cluster again.&lt;br /&gt;&lt;div id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;Stop-CacheCluster &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;Import-CacheClusterConfig -File c:\config.xml -Force &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;Start-CacheCluster &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Hope this helps!  </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/9105231759799417385/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2011/06/appfabric-cache-setting-maxbuffersize.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/9105231759799417385?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/9105231759799417385?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/59uT0L3zFEU/appfabric-cache-setting-maxbuffersize.html" title="AppFabric Cache: Setting MaxBufferSize in a SQL Sever-based cluster configuration" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2011/06/appfabric-cache-setting-maxbuffersize.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0MHRXg_fyp7ImA9WhZQEE4.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-6414179479461612109</id><published>2011-04-16T18:05:00.001+02:00</published><updated>2011-04-17T11:10:34.647+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-04-17T11:10:34.647+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WCFWebAPIs" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>Tunnelling PUT and DELETE with WCF Web APIs Preview 4</title><content type="html">&lt;p&gt;PUT and DELETE are first class citizen HTTP methods in REST resource implementations but unfortunately not all clients support these methods and in fact the XHTML4 specification defines GET and POST as the only valid Form methods. Browsers can use Javascript and the XmlHttpRequest to get around this limitation, but other issues such as the fact that some firewalls block PUTs and DELETE requests, recommend having an alternative strategy to convey these methods semantics in the cleanest possible way.&lt;/p&gt; &lt;p&gt;Existing REST frameworks implement a tunnelling technique that solves this issue: clients make POST request and provide the “real” method somewhere in the request. For example, Ruby On Rails uses a hidden form field called &lt;em&gt;_method&lt;/em&gt; and users of the Google GData API store the real method in the &lt;em&gt;X-HTTP-Method-Override&lt;/em&gt; Custom HTTP header. &lt;/p&gt; &lt;p&gt;Implementing PUT and DELETE tunnelling is a very easy task thanks to the new extensibility point: Message Channels. Message Channels can influence what Resource Method is to be executed by the framework and that’s precisely what we’re going to do: &lt;/p&gt; &lt;div id="codeSnippetWrapper"&gt; &lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; HttpMethodTunnelChannel : DelegatingChannel&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;{&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; HttpMethodTunnelChannel(HttpMessageChannel innerChannel)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        : &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;(innerChannel)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; Task&amp;lt;HttpResponseMessage&amp;gt; SendAsync(HttpRequestMessage request, &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                                                           CancellationToken cancellationToken)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        request.SetOverrideMethodIfAny();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.SendAsync(request, cancellationToken);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;&lt;em&gt;SetOverrideMethodIfAny&lt;/em&gt; is a custom extension method of &lt;em&gt;HttpResponseMessage&lt;/em&gt;. &lt;br /&gt;&lt;div style="border-bottom: silver 1px solid; text-align: left; border-left: silver 1px solid; padding-bottom: 4px; line-height: 12pt; overflow-y: scroll; background-color: #f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 98.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; height: 400px; max-height: 350px; font-size: 8pt; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper"&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; HttpRequestMessageExtensions&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;{&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; SetOverrideMethodIfAny(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; HttpRequestMessage request)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        var method = request.GetOverrideMethod();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (method != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;) request.Method = method;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; HttpMethod GetOverrideMethod(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; HttpRequestMessage request)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        var method = HttpUtility.ParseQueryString(request.RequestUri.Query)[&lt;span style="color: #006080"&gt;"_method"&lt;/span&gt;];&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(method))&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            method = request.Headers&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                .Where(h =&amp;gt; h.Key == &lt;span style="color: #006080"&gt;"X-HTTP-Method-Override"&lt;/span&gt;)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                .SelectMany(h =&amp;gt; h.Value)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;                .FirstOrDefault();&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; MapMethod(method);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt; &lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;private&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; HttpMethod MapMethod(&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; method)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.IsNullOrEmpty(method)) &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.Compare(method, HttpMethod.Put.Method, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;) == 0)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; HttpMethod.Put;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.Compare(method, HttpMethod.Delete.Method, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;) == 0)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; HttpMethod.Delete;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.Compare(method, HttpMethod.Options.Method, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;) == 0)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; HttpMethod.Options;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (String.Compare(method, HttpMethod.Head.Method, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;) == 0)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; HttpMethod.Head;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;/div&gt;In the sample, the query string _method takes precedence over the custom HTTP Header. Bear in mind that the code above not only tunnels PUT and DELETE requests, clients could actually do weird things such as tunnelling GETs over POST or the non-recommended practice of tunnelling unsafe operations (i.e. DELETE) over safe requests (i.e.: GET) &lt;a href="http://stephenwalther.com/blog/archive/2009/01/21/asp.net-mvc-tip-46-ndash-donrsquot-use-delete-links-because.aspx" target="_blank"&gt;which could end up with Google deleting your data when it crawls your site!&lt;/a&gt; &lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: You can find a more complete implementation &lt;a href="https://gist.github.com/923863" target="_blank"&gt;here&lt;/a&gt;. The idea is that &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html" target="_blank"&gt;safe methods&lt;/a&gt; should not become unsafe when tunnelled and the other way around.&lt;/p&gt;Finally, let’s use the new fluent API to bind our message channel.&lt;br&gt;&lt;br /&gt;&lt;div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; Global : System.Web.HttpApplication&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;{&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Application_Start(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    {&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        var config = HttpHostConfiguration.Create().&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;            AddMessageHandlers(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(HttpMethodTunnelChannel));&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;&amp;nbsp;&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;        RouteTable.Routes.MapServiceRoute&amp;lt;ContactResource&amp;gt;(&lt;span style="color: #006080"&gt;"Contact"&lt;/span&gt;, config);&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: white; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;    }&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px"&gt;}&lt;/pre&gt;&lt;!--CRLF--&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;And that’s it! As you can see, I’ve just scratched the surface of Message Channels and you may have already realized their potential for implementing cross cutting concerns such as logging, exception handling or security for example.&lt;/div&gt;  </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/6414179479461612109/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2011/04/tunnelling-put-and-delete-with-wcf-web.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6414179479461612109?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6414179479461612109?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/Y-RpwktDFRk/tunnelling-put-and-delete-with-wcf-web.html" title="Tunnelling PUT and DELETE with WCF Web APIs Preview 4" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2011/04/tunnelling-put-and-delete-with-wcf-web.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8MRno_eip7ImA9WhRUEk8.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-6816342044576382385</id><published>2011-04-16T16:20:00.001+02:00</published><updated>2012-01-22T10:34:47.442+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-22T10:34:47.442+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WCFWebAPIs" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>WCF Web APIs: Embrace the Web</title><content type="html">&lt;p&gt;The new &lt;a href="http://wcf.codeplex.com/releases/view/64449" target="_blank"&gt;WCF Web APIs preview 4&lt;/a&gt; is available and so far I’m very impressed with the quality of the release and the new features.&amp;nbsp; Previous attempts by Microsoft to implement a HTTP/REST framework have been discouraging to say the least, but it seems that the technical debt they went into with the infamous WCF REST Starter Kit is being paid. &lt;/p&gt; &lt;p&gt;The REST Starter Kit library was built on top of a SOAP framework, so it was inevitable that the SOAP details would not leak all over the place. Things like the WCF Message class and its SOAP related stuff, (WS-Addressing headers, tight coupling with XML formats, etc) really get in the way once you want to do something more advanced than the simple Hello World app. &lt;/p&gt; &lt;p&gt;The new WCF Web APIs takes a completely different approach, instead of abstracting the web, it embraces it. Abstractions are good, otherwise we’d still be developing in assembler, but the web is one of the mediums that by only staying as close as possible to the metal you’ll be able to make the most of it. &lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/6816342044576382385/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2011/04/wcf-web-apis-embrace-web.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6816342044576382385?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6816342044576382385?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/ZLYjuHZnqMM/wcf-web-apis-embrace-web.html" title="WCF Web APIs: Embrace the Web" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2011/04/wcf-web-apis-embrace-web.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMMSHo7eyp7ImA9Wx9aFUw.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-8153742153981341588</id><published>2011-03-07T18:19:00.000+01:00</published><updated>2011-03-07T18:21:29.403+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-03-07T18:21:29.403+01:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="C#" /><title>C# Regions and the Single Responsibility Principle</title><content type="html">&lt;p&gt;I've been doing a few code reviews lately and I think I can formulate these two rules:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;If you find yourself needing to use C# Regions with different business terms/concepts in the same class, you've got a very good hint that you're breaking the SRP and that it's time to refactor out. &lt;/p&gt;&lt;/blockquote&gt; &lt;blockquote&gt; &lt;p&gt;If you find yourself needing to use C# regions &lt;b&gt;within a method&lt;/b&gt;, go take a break!&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Actually,&amp;nbsp; if regions weren't part of C#, I don't think they would be missed much.&lt;/p&gt;  </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/8153742153981341588/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2011/03/c-regions-and-single-responsibility.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8153742153981341588?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8153742153981341588?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/NGpqeFurSFQ/c-regions-and-single-responsibility.html" title="C# Regions and the Single Responsibility Principle" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2011/03/c-regions-and-single-responsibility.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MHQ3k-fip7ImA9Wx5WFE4.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-5427409817592290642</id><published>2010-09-24T18:07:00.001+02:00</published><updated>2010-09-25T20:30:32.756+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-25T20:30:32.756+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Security" /><category scheme="http://www.blogger.com/atom/ns#" term="REST" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>Securing WCF REST services for smartphone clients</title><content type="html">&lt;p&gt;In one of the projects that I’m working on we have to define the security model for calling REST services (WCF) from smartphone apps (iPhone/iPad, Android). The security requirements are the following:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Both the clients and servers are owned by the same organization so it’s basically the smartphone calling “home”.  &lt;li&gt;The data to be transferred is not sensitive, so we can safely skip confidentiality concerns.  &lt;li&gt;The services are read-only so integrity is ruled out as well.  &lt;li&gt;Even though data is not confidential, users need to be authenticated (so for example we can establish quotas per user).&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;As REST over HTTP is all about HTTP standards, let’s have a look at what standard methods we can use for authenticating our users&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;strong&gt;HTTP Basic&lt;/strong&gt;: The username and password are sent in clear text over the wire, this is not really an option unless you want to use HTTPS as well. As there is no need for confidentiality in our scenario, we’d rather not take the overhead of HTTPS on the smartphone devices which in some cases may be using slow internet connections.  &lt;li&gt;&lt;strong&gt;HTTP Digest&lt;/strong&gt;: The request is signed with a secret shared between the client and the server (password) and a salt (challenge) obtained by the client in a previous request to the server. The shared secret is not sent over the wire (no need for HTTPS), but an extra request is needed to get the challenge from the server .  &lt;li&gt;&lt;strong&gt;WSSE Username token&lt;/strong&gt;: This is an OASIS standard used by the SOAP WS-Security. The ATOM 1.0 protocol design committee, not having the possibility to use HTTP Basic or HTTP Digest, went for this option for providing an authentication mechanism to the ATOM API. Like the Digest method,&amp;nbsp; it uses the shared secret to sign some parts of the message. More info here: &lt;a href="http://www.xml.com/pub/a/2003/12/17/dive.html"&gt;http://www.xml.com/pub/a/2003/12/17/dive.html&lt;/a&gt;  &lt;li&gt;&lt;strong&gt;OAuth 1.0&lt;/strong&gt;: OAuth is an open standard for authorization delegation: You can authorize 3rd party sites to access, for example, your profile in Facebook or Twitter without having to hand out your credentials to those sites. In our case we don’t need credential delegation but OAuth defines another workflow, known as 2-legged authentication (as opposed to the 3-legged default one) which follows a similar approach of the HTTP Digest and WSSE: the request is signed and verified with the shared secret.&lt;/li&gt;&lt;/ul&gt;&lt;br&gt; &lt;h3&gt;WCF implementation&lt;/h3&gt; &lt;p&gt;IIS implements HTTP Basic and HTTP Digest but it's tightly coupled to the company Active Directory, so obviously this is not suitable for Internet scenarios. The WCF REST Starter kit defines some extensibility points that allow to implement custom authentication methods like it’s explained here for HTTP Basic:&lt;/p&gt;&lt;a href="http://weblogs.asp.net/cibrax/archive/2009/03/20/custom-basic-authentication-for-restful-services.aspx"&gt;http://weblogs.asp.net/cibrax/archive/2009/03/20/custom-basic-authentication-for-restful-services.aspx&lt;/a&gt;  &lt;p&gt;I've implemented HTTP Digest and WSSE UsernameToken methods (along with the HTTP Basic sample) by following that same approach. The code is available in github under the name &lt;a href="http://github.com/javicrespo/WcfRestAuth" target="_blank"&gt;WcfRestAuth&lt;/a&gt;. If you don’t use git, you can get the source code &lt;a href="http://github.com/javicrespo/WcfRestAuth/zipball/master" target="_blank"&gt;here&lt;/a&gt;. Any feedback will be welcome!&lt;/p&gt; &lt;p&gt;For OAuth and WCF you can check &lt;a href="http://github.com/bittercoder/DevDefined.OAuth" target="_blank"&gt;DevDefined.OAuth&lt;/a&gt;&lt;/p&gt;  </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/5427409817592290642/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2010/09/securing-wcf-rest-services-for.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/5427409817592290642?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/5427409817592290642?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/dNuWxe9ht1Q/securing-wcf-rest-services-for.html" title="Securing WCF REST services for smartphone clients" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2010/09/securing-wcf-rest-services-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D08ARno7fyp7ImA9Wx5XF0k.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-2063658107087778933</id><published>2010-09-17T18:16:00.000+02:00</published><updated>2010-09-17T19:50:47.407+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-17T19:50:47.407+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>Using soapUI to consume a WS-Addressing service</title><content type="html">&lt;p&gt;soapUI is a handy tool to test web services. You receive a WSDL document of an external service and you can use this tool do some quick testing before actually getting to write some code to consume the service.&lt;/p&gt; &lt;p&gt;If the service implements WS-Addressing you should know that when generating requests, by default soapUI 3.5 will only add the Action header (the SOAP RPC operation name)&lt;/p&gt; &lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;soapenv:Header&lt;/span&gt; &lt;span class="attr"&gt;xmlns:wsa&lt;/span&gt;&lt;span class="kwrd"&gt;="http://www.w3.org/2005/08/addressing"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;wsa:Action&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;http://myuri/IHello/SayHello&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;wsa:Action&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;soapenv:Header&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;When you send a request like that to a WCF service, you’ll get an exception like this from the server:&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;s:Fault&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;faultcode&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;a:DestinationUnreachable&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;faultcode&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;         &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;faultstring&lt;/span&gt; &lt;span class="attr"&gt;xml:lang&lt;/span&gt;&lt;span class="kwrd"&gt;="en-US"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;                  The message with To '' cannot be processed at the receiver, &lt;br /&gt;                  due to an AddressFilter mismatch at the EndpointDispatcher.  &lt;br /&gt;                  Check that the sender and receiver's EndpointAddresses agree.&lt;br /&gt;          &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;faultstring&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;s:Fault&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Indeed there was no “To” header in the request message. We can edit the WS-Address headers in soapUI though: just open the Message Editor window and click on the WS-A tab button at the bottom. You can set values for headers like MessageId or From but just setting the To value by clicking this checkbox will do the trick&lt;/p&gt;&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_rIotvlm4gjQ/TJOinABkSjI/AAAAAAAAAGM/ptsSz82UZo4/s1600-h/clip_image002%5B3%5D.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://lh3.ggpht.com/_rIotvlm4gjQ/TJOioZb6SDI/AAAAAAAAAGQ/CfR0CNvRQ5A/clip_image002_thumb.jpg?imgmax=800" width="244" height="18"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Now your request messages will look like this&lt;/p&gt;&lt;div class="csharpcode"&gt;&lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;soapenv:Header&lt;/span&gt; &lt;span class="attr"&gt;xmlns:wsa&lt;/span&gt;&lt;span class="kwrd"&gt;="http://www.w3.org/2005/08/addressing"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;wsa:Action&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;http://myUri/IHello/SayHello&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;wsa:Action&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;wsa:To&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;http://localhost/Hello/HelloWorld.svc&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;wsa:To&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;soapenv:Header&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Where the To header value is the service URI.&lt;/p&gt;&lt;p&gt;The WCF service won’t complaint anymore about WS-Addressing issues.&lt;/p&gt;  </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/2063658107087778933/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2010/09/using-soapui-to-consume-ws-addressing.html#comment-form" title="15 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/2063658107087778933?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/2063658107087778933?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/DDLHejFGnwM/using-soapui-to-consume-ws-addressing.html" title="Using soapUI to consume a WS-Addressing service" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_rIotvlm4gjQ/TJOioZb6SDI/AAAAAAAAAGQ/CfR0CNvRQ5A/s72-c/clip_image002_thumb.jpg?imgmax=800" height="72" width="72" /><thr:total>15</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2010/09/using-soapui-to-consume-ws-addressing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE8DR3o9eCp7ImA9Wx5XFks.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-2227776193916388294</id><published>2010-09-16T18:51:00.000+02:00</published><updated>2010-09-16T21:54:36.460+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-16T21:54:36.460+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Security" /><category scheme="http://www.blogger.com/atom/ns#" term="WebServices" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>Replay detection in a web farm with WCF</title><content type="html">&lt;p align="justify"&gt;If you are securing web services, replay attacks is one of the things that you should watch out for. Replayed messages can cause duplicate transactions and can be used to create DOS attacks. Note that replay messages don’t necessarily have to come from malicious users; in environments where exactly-once message delivery is not guaranteed, they are actually expected to happen.&lt;/p&gt; &lt;p align="justify"&gt;The countermeasures to detect these situations are basically these two:&lt;/p&gt; &lt;ul&gt; &lt;li&gt; &lt;div align="justify"&gt;&lt;strong&gt;Timestamping&lt;/strong&gt;: Incoming messages include a timestamp field that is checked by the server against its clock. If the timestamp from the client message differs by a predefined factor from the current server time, then the message is suspicious of being replayed an it’s discarded. With timestamping we can avoid replay attacks that happen over the server replay window maximum value (for example 5 minutes) but what&amp;nbsp; if the hacker manages to replay the message within the window? Nonces to the rescue.&lt;/div&gt; &lt;li&gt; &lt;div align="justify"&gt;&lt;strong&gt;Nonce tracking&lt;/strong&gt;. Incoming message includes a nonce (randomly generated string by the client). The server keeps track of the nonces arrived within the replay window. When a new message arrives with a timestamp that falls within the valid window, the server checks if the message nonce can be found in its nonce cache and&amp;nbsp; if it does, we have proof that the message has been replayed. &lt;em&gt;&lt;strong&gt;In a server farm scenario, all nodes in the farm should share the same nonce cache, otherwise in the worse-case scenario messages could be successfully replayed N-1 times, where N is the number of nodes in the farm&lt;/strong&gt;.&lt;/em&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt; &lt;blockquote&gt; &lt;p align="justify"&gt;&lt;em&gt;Note: It goes without saying that both Timestamp and Nonce must be signed otherwise they could (and they would) be tampered.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p align="justify"&gt;Now, WCF implements a replay detection mechanism &lt;a href="http://msdn.microsoft.com/en-us/library/ms733063.aspx" target="_blank"&gt;and provides a bunch of configuration options&lt;/a&gt; to tune the Timestamping and nonce tracking procedures (i.e: ReplayWindow, ReplayCacheSize for the nonce cache). &lt;/p&gt; &lt;p align="justify"&gt;However, there doesn’t seem to be any extensibility point for custom nonce cache implementations. Internally (thanks Reflector!), WCF uses the class NonceCache (declared as Internal and Sealed) which is a in-memory cache.&amp;nbsp; If you’re using IIS to host your services, you can imagine what happens to the cache when IIS pool is recycled!&lt;/p&gt; &lt;p align="justify"&gt;Interestingly enough, &lt;a href="http://msdn.microsoft.com/en-us/library/ff647945.aspx" target="_blank"&gt;the missing hook in WCF was available in WSE 3.0&lt;/a&gt;. In you look at that WSE article, you’ll see that for that sample, they used back then a DB table as a nonce cache; today I’d probably go for an AppFabric cache for a better performance and high availability, but this is a different story!&lt;/p&gt; &lt;p align="justify"&gt;Maybe in WCF 5.0?&lt;/p&gt; &lt;p align="justify"&gt;&lt;a href="http://social.msdn.microsoft.com/Forums/en/netfxnetcom/thread/09fe4fb3-425c-4726-9959-b8c7131cbe8b" target="_blank"&gt;I started a thread in the msdn forums regarding this.&lt;/a&gt;&lt;/p&gt;  </content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/2227776193916388294/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2010/09/replay-detection-in-web-farm-with-wcf.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/2227776193916388294?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/2227776193916388294?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/mdAISxsWwcA/replay-detection-in-web-farm-with-wcf.html" title="Replay detection in a web farm with WCF" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2010/09/replay-detection-in-web-farm-with-wcf.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkMGQ3c8eyp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-8007209115250908290</id><published>2009-03-02T21:52:00.003+01:00</published><updated>2010-09-12T13:20:22.973+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:20:22.973+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SQL Service Broker" /><title>Using SQL Service Broker in NET applications</title><content type="html">&lt;p&gt;I've been doing some work with SQL Service Broker lately and I thought I could speak about my experience with it. I was interested in the possibility of using &lt;a href="http://www.nservicebus.com/" target="_blank"&gt;NServiceBus&lt;/a&gt; or any other popular implementation of a Enterprise Service Bus in .NET (&lt;a href="http://code.google.com/p/masstransit/" target="_blank"&gt;MassTransit&lt;/a&gt;, &lt;a href="http://ayende.com/Blog/archive/2008/12/17/rhino-service-bus.aspx" target="_blank"&gt;RhinoServiceBus&lt;/a&gt;) with an underlying transport different from Msmq and I thought SQL Service Broker could be a good candidate for the replacement.&lt;/p&gt;This implementation exercise shouldn't be a very complicated  task taking into account the great deal of extensibility of a framework like NServiceBus (you just need to implement an interface called ITransport to start using your own transport layer along with the bus), but unfortunately up to this point of time there is no API implementation for Service Broker in .NET framework so things get a bit trickier. Actually, while dealing with the implementation of a custom API for Service Broker I've hit some limitations/design decisions which, in my opinion, make SQL Broker not the best option for the transport layer of an Enterprise Service Bus framework.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;div&gt;&lt;b&gt;Distributed Transactions&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;I don't want to get into the details about how SQL Service Broker works, but if you have ever used it, you know that messages are retrieved from queues using the TSQL instruction &lt;a href="http://msdn.microsoft.com/en-us/library/ms186963.aspx" target="_blank"&gt;RECEIVE&lt;/a&gt; which is a not blocking call but you can combine it with the &lt;a href="http://msdn.microsoft.com/en-us/library/ms187331.aspx" target="_blank"&gt;WAITFOR&lt;/a&gt; command for the blocking effect so you avoid polling the queue for dealing with new coming messages. The main problem with WAITFOR instruction is that it sets a transaction savepoint which makes the current transaction not suitable for enlistment; putting it in other words the message handling from the queue cannot be used in the context of a distributed transaction.&lt;br /&gt;&lt;br /&gt;So what's the big deal? Actually, I read in msdn forums that SQL broker team wants to discourage the use of distributed transactions because of their performance hit. Besides, you might argue that you can get by without DT keeping all the work related to the message handling in the same database and so there is no need for enlistment. I'm afraid this covers some scenarios but it falls short in others, you have to bear in mind that:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;Not every transactional resource is a SQL Server instance, it doesn't even need to be a SQL engine at all  &lt;/li&gt;&lt;li&gt;Even if all your transactional resources are SQL Server instance because of scalability you might have to keep queues in a different instance from where your mainstream/business data is.  &lt;/li&gt;&lt;li&gt;Regarding security you might have to use different sql user accounts to handle messages and handle application data&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;For all these scenarios distributed transactions are needed to provide reliable message handling and avoid situations like repeated or lost messages...Can you imagine a bank system where messages that increase/decrease account balance could be handled twice or not handled at all?&lt;/p&gt; &lt;p&gt;There is an alternative provided by SQL Broker that could help to get around this limitation (apart from polling)  called External Activation which in few words is sort of a SQL trigger where custom logic can be placed to be executed upon messages arrival to a queue. Then the trick is to use a second queue to store notifications of new coming messages so the consumer application reads and waits from this event queue out of transaction and when a new message arrives it doesn't need to use WAITFOR to go to the main queue to receive the real message within a transaction. I think that this overcomplicates things as you have to handle two queues for what you could do with one and you have to make sure that both queues stay in sync so for example you don't face situations where there are messages outstanding in the main queue and available consumers to handle them but the messages don't get served because the event queue is empty.&lt;/p&gt; &lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Poison messages handling&lt;/b&gt;&lt;/p&gt; &lt;p&gt;An aspect that has to be always taken into account while developing a messaging solutions is the poison messages handling and the replayable message strategy. A valid strategy would be that, on the event of error during message handling, retry up to n times and after it goes over the limit the message can be sent to a dead/error message queue.&lt;/p&gt; &lt;p&gt;But what do we do when there is an error while handling the message, for example an external subsystem needed for processing the message is down for some time? A straight forward answer would be to rollback the current transaction so all inconsistent business work would be undone and the current message would come back to the queue so it could be handled again later when maybe the subsystem would come back (you can keep counters at message level for the retries to identify poison messages).&lt;/p&gt;Well this strategy clashes with the way SQL Service Broker deals with poison messages: A queue is disabled upon 5 consecutive times transaction rollbacks when RECEIVE is used... Once the queue is disabled it cannot be used for processing until an user with administrator right enables it back. This automatic poison message detection it's not message bound, it can't be disabled and the number of consecutive times can't even be changed!&lt;br /&gt;To sum up, on one hand we should always try to commit the transaction to avoid this behavior to be triggered but on the other hand we don't want to leave our business data in a inconsistent state, which leads us to split up the transaction in two: one for the message and the other for the business logic; pretty much we are back to square one with the risk of repeated/lost messages...&lt;br /&gt;&lt;br /&gt;There are a couple of ways around that behavior though, one of them is another sort of a trigger where custom logic can be placed to be executed upon queue disabled event. The other one is to follow the strategy explained &lt;a href="http://msdn.microsoft.com/en-us/library/ms171592.aspx" target="_blank"&gt;here&lt;/a&gt;, which in few words consists of creating a transaction savepoint (bye bye distributed transaction again) before receive is executed and rollback from that transaction savepoint in case of error, so technically the receive statement is not rollbacked.&lt;br /&gt;&lt;p&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Wrapping up&lt;/b&gt;&lt;/p&gt;Despite the issues above, I think that this has been a good experience as I have got to know better SQL Broker and I've had the chance to dig a bit into NServiceBus internals and understand a bit more how it works under the hood.&lt;br /&gt;The general idea that I get of SQL Broker is that it can be a good solution in an applications where the message handling business logic is included in the database, but for .NET applications I'd rather go for MSMQ queues which, on top of providing an API implementation in .NET framework, don't suffer from the problems that I've talked about.&lt;br /&gt;&lt;p&gt;I'm no expert in SQL Broker though, so if I'm missing something, don't hesitate to say it, I'll appreciate it!&lt;/p&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjaviercrespoalvez.com%2f2009%2f03%2fusing-sql-service-broker-in-net.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjaviercrespoalvez.com%2f2009%2f03%2fusing-sql-service-broker-in-net.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;  &lt;/div&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/8007209115250908290/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2009/03/using-sql-service-broker-in-net.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8007209115250908290?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8007209115250908290?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/m824K-kBedo/using-sql-service-broker-in-net.html" title="Using SQL Service Broker in NET applications" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>5</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2009/03/using-sql-service-broker-in-net.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8FRXg8fyp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-6555578377070408543</id><published>2009-02-28T09:47:00.002+01:00</published><updated>2010-09-12T13:26:54.677+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:26:54.677+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Other" /><title>Moving this blog to a custom domain</title><content type="html">&lt;p&gt;I’ve moved this Blogger blog to the custom domain that you can see in your navigation bar, the former blogspot url will keep redirecting to the new domain though.&lt;/p&gt;&lt;p&gt;You may already know that a new domain means a new PageRank, and as I have already noticed in the traffic figures of this site, a poorer PageRank :) (you can read about this subject &lt;a href="http://www.consumingexperience.com/2007/08/domain-name-change-search-engine.html" target="_blank"&gt;here&lt;/a&gt;).&lt;/p&gt;&lt;p&gt;So my advice is that if you have a blog engine subdomain url  (blogger, wordpress, etc) and you are thinking of going for your own custom domain, the sooner the better!&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/6555578377070408543/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2009/02/moving-this-blog-to-custom-domain.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6555578377070408543?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6555578377070408543?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/ylluGbyoSSM/moving-this-blog-to-custom-domain.html" title="Moving this blog to a custom domain" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2009/02/moving-this-blog-to-custom-domain.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck8AQ30yeCp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-3373657009666169907</id><published>2009-02-09T20:14:00.001+01:00</published><updated>2010-09-12T13:27:22.390+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:27:22.390+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><title>ASP.NET Custom Button Controls Source Code</title><content type="html">&lt;p&gt;I’ve uploaded the source code of the &lt;a href="http://javiercrespoalvez.com/2008/12/aspnet-confirmation-button-using-jquery.html" target="_blank"&gt;Confirmation Button control&lt;/a&gt; &lt;a href="http://sites.google.com/site/javicrespotech/Home/ConfirmButtonSample.zip" target="_blank"&gt;here&lt;/a&gt; and the &lt;a href="http://javiercrespoalvez.com/2009/01/aspnet-multiple-validation-group-button.html" target="_blank"&gt;Multiple Validation Group Button control&lt;/a&gt; &lt;a href="http://sites.google.com/site/javicrespotech/Home/MultipleValidationGroupButtonSample.zip" target="_blank"&gt;here&lt;/a&gt;. Besides, for the former I have fixed a bug regarding ASP.NET validation and I have extended the original javascript file to support confirmation popups on html link clicks, and for the latter I have created a separate library project with the custom controls and their associated javascript embedded.&lt;/p&gt; &lt;p&gt;Any feedback will be welcomed!&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/3373657009666169907/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2009/02/aspnet-custom-button-controls-source.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/3373657009666169907?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/3373657009666169907?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/8cIKVI8Wxyg/aspnet-custom-button-controls-source.html" title="ASP.NET Custom Button Controls Source Code" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2009/02/aspnet-custom-button-controls-source.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4BR3g7fSp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-32927838058682564</id><published>2009-01-11T21:58:00.001+01:00</published><updated>2010-09-12T13:29:16.605+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:29:16.605+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><title>ASP.NET Multiple Validation Group Button</title><content type="html">&lt;p&gt;In ASP.NET validation controls, the Validation Group allows to break down the set of page validation controls into different units that can be executed independently from each other. Then, a single validation group can be specified at button level so a particular action is glued to a validation controls subset. There are some situations though, where you might be interested in binding a button to multiple validation groups, one of these situations is described in &lt;a href="http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=102994" target="_blank"&gt;this feedback entry at Microsoft Connect site&lt;/a&gt;.&lt;/p&gt;That was back in 2005 when the Validation Group concept was a brand new upcoming feature in .NET 2.0, which by that time was still in beta version. Well, despite the fact that guys from Microsoft seemed to be receptive to the suggestion, it's 2009, ASP.NET is in it 3.5 version and we all know that this feature hasn't quite made it :(. The workaround suggested is to call &lt;em&gt;Page.Validate(group)&lt;/em&gt; in server-side but then it means that we'd need to ditch client-side validation which I'm not very happy about.&lt;br /&gt;&lt;br /&gt;So let's pick up this suggestion and create a new asp.net button control that includes a coma delimited validation group list property.&lt;br /&gt;&lt;div&gt; &lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; MultipleValidationGroupButton: Button&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// Gets or sets the validation group list&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// comma delimited.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// &amp;lt;value&amp;gt;The validation group list.&amp;lt;/value&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// Empty string represents validation controls that&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// don't define validation group property&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; ValidationGroupList&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  { &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;      get &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      { &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; ViewState[&lt;span style="color: #006080"&gt;"ValidationGroupList"&lt;/span&gt;] &lt;span style="color: #0000ff"&gt;as&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;      set &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      { &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          ViewState[&lt;span style="color: #006080"&gt;"ValidationGroupList"&lt;/span&gt;] = &lt;span style="color: #0000ff"&gt;value&lt;/span&gt;; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnPreRender(EventArgs e)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;      &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!String.IsNullOrEmpty(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ValidationGroupList))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.CausesValidation = &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;          &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; script = String.Format(&lt;span style="color: #006080"&gt;"ValidateGroups('{0}','{1}');"&lt;/span&gt;, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;              &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ClientID, &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ValidationGroupList);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;          &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (Page.IsAsyncPostBack())&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;              ScriptManager.RegisterStartupScript(Page, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Page), &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ClientID, script, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;          &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;              Page.ClientScript.RegisterStartupScript(&lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Page), &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ClientID, script, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;     &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.OnPreRender(e);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// Validates the groups.&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  &lt;span style="color: #008000"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; ValidateGroups()&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;  {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;      &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!String.IsNullOrEmpty(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ValidationGroupList))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;      {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;          &lt;span style="color: #0000ff"&gt;string&lt;/span&gt;[] list = &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ValidationGroupList.Split(&lt;span style="color: #006080"&gt;','&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;          &lt;span style="color: #0000ff"&gt;foreach&lt;/span&gt; (&lt;span style="color: #0000ff"&gt;string&lt;/span&gt; item &lt;span style="color: #0000ff"&gt;in&lt;/span&gt; list)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;          {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;              Page.Validate(item);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;          }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;      }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;  }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;The server side implementation is pretty straightforward: we check if the &lt;em&gt;ValidationGroupList&lt;/em&gt; propety has been set and if so we disable the regular ASP.NET validation mechanism (&lt;em&gt;CausesValidation=false&lt;/em&gt;) and we register the call to the script that will actually do the job (For the client-side registration I use the &lt;em&gt;Page.IsAsyncPostBack&lt;/em&gt; partial method already implemented while creating &lt;a href="http://javicrespotech.blogspot.com/2008/12/aspnet-confirmation-button-using-jquery.html" target="_blank"&gt;my jQuery ConfirmationButton&lt;/a&gt;). The purpose of &lt;em&gt;ValidateGroups&lt;/em&gt; method is to remove the need of hardcoding the validation groups in code behind to enforce server side validation, so instead of doing this:&lt;/p&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Button_Click(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;   Page.Validate(&lt;span style="color: #006080"&gt;"Group1"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;   Page.Validate(&lt;span style="color: #006080"&gt;"Group2"&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;   Page.Validate(&lt;span style="color: #006080"&gt;"Group3"&lt;/span&gt;); &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;   &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;   &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (Page.IsValid)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;   { &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;       &lt;span style="color: #008000"&gt;//Button Actions&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;   }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;We don’t need to scatter our validation groups in both markup and code-behind because we can do this:&lt;/p&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; Button_Click(&lt;span style="color: #0000ff"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;   &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Button.ValidateGroups();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;   &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (Page.IsValid)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;   { &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;       &lt;span style="color: #008000"&gt;//Button Actions&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;   }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;And to end with, server-side wise, this is how we define our button in ASP.NET markup language.&lt;/p&gt;&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;cc:MultipleValidationGroupButton&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="btn"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt;&lt;br /&gt;       &lt;span style="color: #ff0000"&gt;ValidationGroupList&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Group1,Group2"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;onclick&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Button_Click"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Click"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now it's time to code the javascript function that performs validation on button click. For the implementation, I've used some of the syntactic sugar that jQuery offers but as I'm not using a great deal of things of it you could potentially rewrite this function with plain javascript without much complexity, although I must say that after you start using jQuery (if you haven't yet), you will never want to go back to plain javascript again!&lt;/p&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; ValidateGroups(buttonId, validationGroupList) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #008000"&gt;//Bind the logic to the specified button with jQuery&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    $(&lt;span style="color: #006080"&gt;"#"&lt;/span&gt; + buttonId).click(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(e) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; list = validationGroupList.split(&lt;span style="color: #006080"&gt;','&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//Loop through the entire set of page validators&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        $.each(Page_Validators, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; ((&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.validationGroup &amp;amp;&amp;amp; ExistsGroup(list, &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.validationGroup)) &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            ||(!&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.validationGroup &amp;amp;&amp;amp; ExistsGroup(list, &lt;span style="color: #006080"&gt;''&lt;/span&gt;))) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                ValidatorValidate(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.validationGroup);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;                Page_IsValid = Page_IsValid &amp;amp;&amp;amp; &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.isvalid;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        });&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//Reflect validation in ValidationSummary's if there are any in the page&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        $.each(list, &lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            ValidationSummaryOnSubmit(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        });&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//If Page_IsValid is false the execution flow will be interrupted&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; Page_IsValid;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    });&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; ExistsGroup(list, group) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; found = &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;for&lt;/span&gt; (i = 0; i &amp;lt; list.length; i++) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (list[i] == group) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            found = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;break&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; found;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, serif; line-height: normal; white-space: normal; font-size: 16px; "&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span class="Apple-style-span" style="font-family: Georgia, serif; line-height: normal; white-space: normal; font-size: 16px; "&gt;And that’s it, the implementation is ready but before we wrap it up, there are a few things that are worth mentioning: The second clause in the if statement is there to support the scenario where we would potentially want to combine “ungrouped” with “grouped” validation controls and in that situation we’d define our control like this:&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;cc:MultipleValidationGroupButton&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="btn"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt;&lt;br /&gt;       &lt;span style="color: #ff0000"&gt;ValidationGroupList&lt;/span&gt;&lt;span style="color: #0000ff"&gt;=",Group1"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;onclick&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Button_Click"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="Click"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Finally, you may have noticed that I've used extensively the ASP.NET validation client-side API (&lt;em&gt;ValidatorValidate&lt;/em&gt;, &lt;em&gt;Page_Validators&lt;/em&gt;, etc), if you want to have more details about this API I recommend you using our friend Reflector to get acquainted to this library (System.Web assembly, Resources folder, WebUIValidation.js resource), that helped me a lot.&lt;/p&gt;Hope this helps!&lt;br /&gt;&lt;br /&gt;&lt;b&gt;UPDATE: &lt;/b&gt;I've uploaded the code for this post &lt;a href="http://sites.google.com/site/javicrespotech/Home/MultipleValidationGroupButtonSample.zip" target="_blank"&gt;here&lt;/a&gt;.&lt;br /&gt;I've created a library project with ASP.NET custom controls for Button, ImageButton and LinkButton; the associated javascript code is embedded in that project (apart from jQuery js file).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2009%2f01%2faspnet-multiple-validation-group-button.html"&gt;&lt;img alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2009%2f01%2faspnet-multiple-validation-group-button.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/32927838058682564/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2009/01/aspnet-multiple-validation-group-button.html#comment-form" title="16 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/32927838058682564?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/32927838058682564?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/wZwEgWatVlc/aspnet-multiple-validation-group-button.html" title="ASP.NET Multiple Validation Group Button" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>16</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2009/01/aspnet-multiple-validation-group-button.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YESX86fSp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-4205363731246981026</id><published>2008-12-14T22:19:00.001+01:00</published><updated>2010-09-12T13:31:48.115+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:31:48.115+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JQuery" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><title>ASP.NET Confirmation Button using JQuery</title><content type="html">&lt;p&gt;Quite often in business applications the use of confirmation modal popups is required in order to get confirmation from the user of a specific action he’s going to carry out. In web environment the “gorgeous” built-in javascript confirm function is a valid option, but we are living in the XXI century and we can do much better! Particularly with JQuery and the &lt;a href="http://www.ericmmartin.com/projects/simplemodal/"&gt;SimpleModal&lt;/a&gt; plug-in we can achieve something like this with very little effort:&lt;/p&gt;&lt;a href="http://lh6.ggpht.com/_rIotvlm4gjQ/SUU8zBo09tI/AAAAAAAAADs/edFV7yEr96c/s1600-h/Confirmation%5B9%5D.jpg"&gt;&lt;img title="Confirmation" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="147" alt="Confirmation" src="http://lh3.ggpht.com/_rIotvlm4gjQ/SUU8zVEs-4I/AAAAAAAAADw/Gv8uAob0qX0/Confirmation_thumb%5B5%5D.jpg?imgmax=800" width="425" border="0" /&gt;&lt;/a&gt;&lt;p&gt;So, let's get started! First of all we’ll download jQuery js file, SimpleModal js file and css file and add references to them in our master page:&lt;/p&gt; &lt;div&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;script&lt;/span&gt; &lt;span style="color: #ff0000"&gt;src&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="/Sample/Scripts/jquery-1.2.6.js"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="text/javascript"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;script&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;script&lt;/span&gt; &lt;span style="color: #ff0000"&gt;src&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="/Sample/Scripts/SimpleModal/jquery.simplemodal.js"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="text/javascript"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;script&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;link&lt;/span&gt; &lt;span style="color: #ff0000"&gt;type&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='text/css'&lt;/span&gt; &lt;span style="color: #ff0000"&gt;href&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='/Sample/Scripts/SimpleModal/css/confirm.css'&lt;/span&gt; &lt;span style="color: #ff0000"&gt;rel&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='stylesheet'&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Then we can create the actual html that will be used as modal popup. The html will be reused in any call to the jQuery plugin so we’ll put it in the master page anywhere within the body tag. &lt;div&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;id&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='confirm'&lt;/span&gt; &lt;span style="color: #ff0000"&gt;style&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='display: none'&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;class&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='header'&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:Literal&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="ConfirmLiteral"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="&amp;lt;%$ Resources:Global, Confirm %&amp;gt;"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt; &lt;span style="color: #ff0000"&gt;class&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='message'&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;p&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;class&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='buttons'&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;class&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='no modalClose'&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:Literal&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="NoLiteral"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="&amp;lt;%$ Resources:Global, No %&amp;gt;"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt; &lt;span style="color: #ff0000"&gt;class&lt;/span&gt;&lt;span style="color: #0000ff"&gt;='yes'&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;                &lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;asp:Literal&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="YesLiteral"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                    &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="&amp;lt;%$ Resources:Global, Yes %&amp;gt;"&lt;/span&gt;&lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color: #800000"&gt;div&lt;/span&gt;&lt;span style="color: #0000ff"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;If you don’t need to localize the popup, of course you can get rid of the resources and the Literal controls. Now we can create the javascript function that uses the plugin to show the modal popup.&lt;/p&gt;&lt;div&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; confirm(message, callbackYes) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;   $(&lt;span style="color: #006080"&gt;'#confirm'&lt;/span&gt;).modal({&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        close:&lt;span style="color: #0000ff"&gt;false&lt;/span&gt;, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        overlayId:&lt;span style="color: #006080"&gt;'confirmModalOverlay'&lt;/span&gt;,&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        containerId:&lt;span style="color: #006080"&gt;'confirmModalContainer'&lt;/span&gt;, &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        onShow: &lt;span style="color: #0000ff"&gt;function&lt;/span&gt; (dialog) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            dialog.data.find(&lt;span style="color: #006080"&gt;'.message'&lt;/span&gt;).append(message);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #008000"&gt;// if the user clicks "yes"&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            dialog.data.find(&lt;span style="color: #006080"&gt;'.yes'&lt;/span&gt;).click(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; () {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                &lt;span style="color: #008000"&gt;// call the callback&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;                &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; ($.isFunction(callbackYes)) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                    callbackYes.apply();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;                }  &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                &lt;span style="color: #008000"&gt;// close the dialog&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;                $.modal.close();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            });&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;We already have the means to show the popup but we still need to trigger it on button clicked.&lt;/p&gt;&lt;div&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;var&lt;/span&gt; Page_IsValid = &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;function&lt;/span&gt; SetConfirmation(buttonId, message)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    $(&lt;span style="color: #006080"&gt;"#"&lt;/span&gt; + buttonId).click(&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;(e) {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//We keep the original click event so&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//it can be executed as a callback&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;var&lt;/span&gt; target = $(e.target);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #008000"&gt;//We prevent the form from posting back&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        e.preventDefault();&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(Page_IsValid)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            confirm(message,&lt;span style="color: #0000ff"&gt;function&lt;/span&gt;() {target.click();});&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    });&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;The SimpleModal plugin provides asynchronous and non-blocking functionally (not like the builtin javascript confirm) and that means that we need to prevent the original button’s click event from happening (e.preventDefault();) but at the same time we need to keep it as a callback function to be used in case the user confirms the action to be executed (e.target.click();). &lt;/p&gt;&lt;p&gt;If we you are using ASP.NET validators you might want to show the confirmation pop up only the page is valid (Page_IsValid), there is no point of asking for confirmation if the action cannot be carried out anyways! The variable initialization outside the function guarantees that our function won’t break if there is no ASP.NET validator in the page.&lt;/p&gt;&lt;p&gt;Well, client-side wise we are done, here it goes a usage sample.&lt;/p&gt;&lt;div&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;SetConfirmation(&lt;span style="color: #006080"&gt;'&amp;lt;%= myButton.ClientID %&amp;gt;'&lt;/span&gt;,&lt;span style="color: #006080"&gt;'Are you sure of this?'&lt;/span&gt;);&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Let’s focus on server-side now, is there anything we can do? Well, we can create a asp.net control that hides the javascript event subscription to the consumer, so dropping this line in the Page/UserControl markup would be enough to have the confirmation button functionality all in a single place.&lt;/p&gt;&lt;div&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color: #800000"&gt;sample:ConfirmButton&lt;/span&gt; &lt;span style="color: #ff0000"&gt;ID&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="actionButton"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;runat&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="server"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Text&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="&amp;lt;%$ Resources:Global, Action %&amp;gt;"&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt; &lt;span style="color: #ff0000"&gt;OnClick&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="actionButton_Click"&lt;/span&gt; &lt;span style="color: #ff0000"&gt;Message&lt;/span&gt;&lt;span style="color: #0000ff"&gt;="&amp;lt;%$ Resources:Global, ConfirmationMessage %&amp;gt;"&lt;/span&gt; &lt;span style="color: #0000ff"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Here goes the implementation of the ConfirmButton control&lt;/p&gt;&lt;div&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; ConfirmButton : Button&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; Message&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        get;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        set;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt; &lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;protected&lt;/span&gt; &lt;span style="color: #0000ff"&gt;override&lt;/span&gt; &lt;span style="color: #0000ff"&gt;void&lt;/span&gt; OnPreRender(EventArgs e)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;base&lt;/span&gt;.OnPreRender(e);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (!String.IsNullOrEmpty(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Message))&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;string&lt;/span&gt; script = String.Format(&lt;span style="color: #006080"&gt;"SetConfirmation('{0}','{1}');"&lt;/span&gt;, &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ClientID, &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.Message);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;if&lt;/span&gt; (Page.IsAsyncPostBack())&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                ScriptManager.RegisterStartupScript(Page, &lt;span style="color: #0000ff"&gt;typeof&lt;/span&gt;(Page), &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ClientID, script, &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;            &lt;span style="color: #0000ff"&gt;else&lt;/span&gt;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;                Page.ClientScript.RegisterStartupScript(type, &lt;span style="color: #0000ff"&gt;this&lt;/span&gt;.ClientID, script , &lt;span style="color: #0000ff"&gt;true&lt;/span&gt;);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;A few things to point out in the implementation: the javascript call is only rendered if a message text has been assigned to the control, which means that we could potentially use the ConfirmButton as our regular button and provide the confirmation message only when needed.  The second thing is that we could extract a helper method from the logic in the OnPreRender method, so we could use this helper method to set confirmations programmatically upon any sort of button control (Button, ImageButton, LinkButton). Finally, note that the ScriptManager has to be used to register the javascript in the page when the control is rendered as a part of an UpdatePanel partial postback. The following page extension method is defined to identify those scenarios.&lt;/p&gt;&lt;div&gt;&lt;div style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;&lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;class&lt;/span&gt; PageExtensions&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;{&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;    &lt;span style="color: #0000ff"&gt;public&lt;/span&gt; &lt;span style="color: #0000ff"&gt;static&lt;/span&gt; &lt;span style="color: #0000ff"&gt;bool&lt;/span&gt; IsAsyncPostBack(&lt;span style="color: #0000ff"&gt;this&lt;/span&gt; Page page)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        var result = &lt;span style="color: #0000ff"&gt;false&lt;/span&gt;;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        var scriptManager = ScriptManager.GetCurrent(page);&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;if&lt;/span&gt;(scriptManager != &lt;span style="color: #0000ff"&gt;null&lt;/span&gt;)&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        {&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;            result = scriptManager.IsInAsyncPostBack;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;        }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;        &lt;span style="color: #0000ff"&gt;return&lt;/span&gt; result;&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: white; border-bottom-style: none"&gt;    }&lt;/pre&gt;&lt;pre style="padding-right: 0px; padding-left: 0px; font-size: 8pt; padding-bottom: 0px; margin: 0em; overflow: visible; width: 100%; color: black; border-top-style: none; line-height: 12pt; padding-top: 0px; font-family: consolas, 'Courier New', courier, monospace; border-right-style: none; border-left-style: none; background-color: #f4f4f4; border-bottom-style: none"&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;And that's it, I hope this helps!&lt;/p&gt;&lt;b&gt;UPDATE: &lt;/b&gt;You can find the code of this post &lt;a href="http://sites.google.com/site/javicrespotech/Home/ConfirmButtonSample.zip?attredirects=0"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;p&gt;Besides, I've added some code to enable confirmation popup on link click and I've fixed a bug regarding validation.&lt;/p&gt;&lt;b&gt;UPDATE #2:&lt;/b&gt;I've updated the javascript code in order to fix an issue that I ran into when using the confirmation buttons with Update Panels (The javascript event handler binder was getting executed on every partial post back which was causing some issues with the popup callback. Check out &lt;a href="http://sites.google.com/site/javicrespotech/Home/ConfirmButtonSample.zip?attredirects=0"&gt;the implementation&lt;/a&gt; for more details, all the changes I did are documented in the js file)&lt;br /&gt;&lt;p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f12%2faspnet-confirmation-button-using-jquery.html"&gt;&lt;img alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f12%2faspnet-confirmation-button-using-jquery.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/4205363731246981026/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/12/aspnet-confirmation-button-using-jquery.html#comment-form" title="13 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/4205363731246981026?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/4205363731246981026?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/9Azjd8NmdKI/aspnet-confirmation-button-using-jquery.html" title="ASP.NET Confirmation Button using JQuery" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://lh3.ggpht.com/_rIotvlm4gjQ/SUU8zVEs-4I/AAAAAAAAADw/Gv8uAob0qX0/s72-c/Confirmation_thumb%5B5%5D.jpg?imgmax=800" height="72" width="72" /><thr:total>13</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/12/aspnet-confirmation-button-using-jquery.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YDRns4cSp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-3575707341406910354</id><published>2008-12-08T23:41:00.009+01:00</published><updated>2010-09-12T13:32:57.539+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:32:57.539+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Team Foundation Server" /><category scheme="http://www.blogger.com/atom/ns#" term="Continuous integration" /><title>Team Build notification on test failed</title><content type="html">&lt;p&gt;A nice feature in a Continuous Integration environment is the ability to notify developers (or even managers yuk!) when a build breaks. The command Biisubscribe in TFS 2008 allows to hook up email alerts on build completion, for example this is how we can configure &lt;a href="http://www.codeplex.com/VSTSGuidance/Wiki/View.aspx?title=How%20to%20receive%20notification%20when%20a%20build%20has%20failed&amp;amp;referringTitle=Build%20Practices%20at%20a%20Glance"&gt;email notifications on build failure due to compilation errors&lt;/a&gt;:&lt;/p&gt;&lt;pre style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 8pt; PADDING-BOTTOM: 0px; MARGIN: 0em; OVERFLOW: visible; WIDTH: 100%; COLOR: black; BORDER-TOP-STYLE: none; LINE-HEIGHT: 12pt; PADDING-TOP: 0px; FONT-FAMILY: consolas, 'Courier New', courier, monospace; BORDER-RIGHT-STYLE: none; BORDER-LEFT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; BORDER-BOTTOM-STYLE: none"&gt;bissubscribe /eventType BuildCompletionEvent /address myemail@domain.com&lt;br /&gt;/deliveryType EmailPlaintext /server tfsserver1&lt;br /&gt;/filter "TeamProject = &lt;span style="color:#006080;"&gt;'MyTeamProject'&lt;/span&gt; AND CompletionStatus=&lt;span style="color:#006080;"&gt;'Failed'&lt;/span&gt;“&lt;/pre&gt;&lt;p&gt;If you are running tests as a part of the build process though, you might want to take it to the next level and send notifications when any of your tests has failed. Tests are one of the most important pieces of a Continuous integration environment and as such they deserve to be taken in consideration in the notification process :)&lt;/p&gt;In TFS 2008 “Failed” builds are builds that have failed during compilation time while “Partial Succeeded” builds are builds that have gone through the compilation process correctly but have failed in any of the post build actions… such as the test runner! So we have all the info needed to modify the filter from the previous command and get notifications when our tests fail :&lt;br /&gt;&lt;br /&gt;&lt;pre style="PADDING-RIGHT: 0px; PADDING-LEFT: 0px; FONT-SIZE: 8pt; PADDING-BOTTOM: 0px; MARGIN: 0em; OVERFLOW: visible; WIDTH: 100%; COLOR: black; BORDER-TOP-STYLE: none; LINE-HEIGHT: 12pt; PADDING-TOP: 0px; FONT-FAMILY: consolas, 'Courier New', courier, monospace; BORDER-RIGHT-STYLE: none; BORDER-LEFT-STYLE: none; BACKGROUND-COLOR: #f4f4f4; BORDER-BOTTOM-STYLE: none"&gt;bissubscribe /eventType BuildCompletionEvent /address myemail@domain.com&lt;br /&gt;/deliveryType EmailPlaintext /server tfsserver1&lt;br /&gt;/filter "TeamProject = &lt;span style="color:#006080;"&gt;'MyTeamProject'&lt;/span&gt; AND&lt;br /&gt;       (CompletionStatus=&lt;span style="color:#006080;"&gt;'Failed'&lt;/span&gt; OR CompletionStatus=&lt;span style="color:#006080;"&gt;'Partially Succeeded'&lt;/span&gt;)“ &lt;/pre&gt;&lt;p&gt;Hope this helps!&lt;/p&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f12%2fteam-build-notification-on-test-failed.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f12%2fteam-build-notification-on-test-failed.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/3575707341406910354/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/12/team-build-notification-on-test-failed.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/3575707341406910354?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/3575707341406910354?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/gAlGVLJl4Iw/team-build-notification-on-test-failed.html" title="Team Build notification on test failed" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/12/team-build-notification-on-test-failed.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UFR30_eyp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-8080596857609943595</id><published>2008-09-25T12:23:00.008+02:00</published><updated>2010-09-12T13:33:36.343+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:33:36.343+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Castle" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>Singleton WCF Proxy</title><content type="html">In WCF, creating a proxy is a heavy operation, so if you are experiencing performance slowdown you should definitely look at this area. One of the possible solutions to tackle this problem is to reuse your proxies across your application threads, either implementing a singleton or a pool, but in any case bear in mind that proxy reusability is only advisable in some scenarios (see &lt;a href="http://blogs.msdn.com/wenlong/archive/2007/10/26/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared.aspx"&gt;this&lt;/a&gt; and &lt;a href="http://blogs.msdn.com/wenlong/archive/2007/10/27/performance-improvement-of-wcf-client-proxy-creation-and-best-practices.aspx"&gt;this&lt;/a&gt; for the considerations).&lt;br /&gt;Ok, so let's say that we want to go for a singleton proxy and we use Castle as a DI container to handle the proxy instances.&lt;br /&gt;In theory the implementation would be as easy as this&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="TestService"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="WCFTest.Contracts.ITestService, WCFTest.Contracts"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="WCFTest.Proxies.TestProxy, WCFTest.Proxies"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;lifestyle&lt;/span&gt;&lt;span class="kwrd"&gt;="singleton"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;Where ITestService is the WCF contract and TestProxy is the proxy for that contract... End of the story? Not quite. The problem here arises when for any reason the channel associated to the proxy gets faulted. You probably already know that &lt;a href="http://jeffbarnes.net/portal/blogs/jeff_barnes/archive/2007/04/24/wcf-your-proxy-can-only-fault-once.aspx"&gt; a faulted proxy can no longer connect to a service&lt;/a&gt; and in order to connect again to it there is no option than throwing away the faulted proxy instance and using a new one.&lt;br /&gt;So it seems that the singleton approach doesn't suit our needs; we need to find a way of recreating proxy instances only when a proxy is in faulted state, something like &lt;a href="http://bloggingabout.net/blogs/erwyn/archive/2006/12/09/WCF-Service-Proxy-Helper.aspx"&gt;this approach&lt;/a&gt; but fit in our DI container. Good news is that Castle gives the possibility to &lt;a href="http://castleproject.org/container/documentation/trunk/usersguide/lifestyles.html"&gt;define custom lifestyle managers for our instances&lt;/a&gt;; we just need to implement the ILifestyleManager interface (or like in the following code snippet, the abstract class AbstractLifestyleManager) and provide the expected behavior.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;/// Singleton WCF Proxy Lifestyle Manager&lt;/span&gt;&lt;br /&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SingletonWCFProxyLifestyleManager : AbstractLifestyleManager&lt;br /&gt;{&lt;br /&gt;   &lt;span class="preproc"&gt;#region&lt;/span&gt; properties&lt;br /&gt;   &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; instance;&lt;br /&gt;   &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span class="preproc"&gt;#region&lt;/span&gt; overriden methods&lt;br /&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// Resolves the specified instance from the context.&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;param name="context"&amp;gt;The context.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;returns&amp;gt;The resolved object&amp;lt;/returns&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; Resolve(Castle.MicroKernel.CreationContext context)&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;lock&lt;/span&gt; (&lt;span class="kwrd"&gt;base&lt;/span&gt;.ComponentActivator)&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="rem"&gt;//If the instance does not exists it is resolved&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.instance == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;           {&lt;br /&gt;               &lt;span class="kwrd"&gt;this&lt;/span&gt;.instance = &lt;span class="kwrd"&gt;base&lt;/span&gt;.Resolve(context);&lt;br /&gt;           }&lt;br /&gt;           &lt;span class="kwrd"&gt;else&lt;/span&gt;&lt;br /&gt;           {&lt;br /&gt;               ICommunicationObject communicationObject = &lt;span class="kwrd"&gt;this&lt;/span&gt;.instance &lt;span class="kwrd"&gt;as&lt;/span&gt; ICommunicationObject;&lt;br /&gt;               &lt;span class="rem"&gt;//If the proxy is in faulted state, it's aborted and&lt;/span&gt;&lt;br /&gt;               &lt;span class="rem"&gt;//a new proxy is created&lt;/span&gt;&lt;br /&gt;               &lt;span class="kwrd"&gt;if&lt;/span&gt; (communicationObject != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp;&lt;br /&gt;                   communicationObject.State == CommunicationState.Faulted)&lt;br /&gt;               {&lt;br /&gt;                   &lt;span class="kwrd"&gt;try&lt;/span&gt;&lt;br /&gt;                   {&lt;br /&gt;                       communicationObject.Abort();&lt;br /&gt;                   }&lt;br /&gt;                   &lt;span class="kwrd"&gt;catch&lt;/span&gt; { }&lt;br /&gt;&lt;br /&gt;                   &lt;span class="kwrd"&gt;this&lt;/span&gt;.instance = &lt;span class="kwrd"&gt;base&lt;/span&gt;.Resolve(context);&lt;br /&gt;               }&lt;br /&gt;           }&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.instance;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// Releases unmanaged and - optionally - managed resources&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Dispose()&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.instance != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;base&lt;/span&gt;.Release(&lt;span class="kwrd"&gt;this&lt;/span&gt;.instance);&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// Releases the specified instance.&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="rem"&gt;/// &amp;lt;param name="instance"&amp;gt;The instance.&amp;lt;/param&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Release(&lt;span class="kwrd"&gt;object&lt;/span&gt; instance)&lt;br /&gt;   {&lt;br /&gt;&lt;br /&gt;   }&lt;br /&gt;   &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;Then we need to change the objects configuration file to use our custom implementation.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="TestService"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="WCFTest.Contracts.ITestService, WCFTest.Contracts"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="WCFTest.Proxies.TestProxy, WCFTest.Proxies"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;lifestyle&lt;/span&gt;&lt;span class="kwrd"&gt;="custom"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;customLifestyleType&lt;/span&gt;&lt;span class="kwrd"&gt;="WCFTest.Common.SingletonWCFProxyLifestyleManager, WCFTest.Common"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;Well, I hope that if you are using Castle to manage singleton WCF proxies, this post will be helpful.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f09%2fsingleton-wcf-proxy.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f09%2fsingleton-wcf-proxy.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/8080596857609943595/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/09/singleton-wcf-proxy.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8080596857609943595?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8080596857609943595?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/PoY0_9FIv-M/singleton-wcf-proxy.html" title="Singleton WCF Proxy" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>4</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/09/singleton-wcf-proxy.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UASX48fSp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-3770613807739657916</id><published>2008-07-23T20:37:00.007+02:00</published><updated>2010-09-12T13:34:08.075+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:34:08.075+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ADO.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Certifications" /><title>ADO.NET 3.5 certification exam results</title><content type="html">Back in April I blogged about my experience sitting for &lt;a href="http://javicrespotech.blogspot.com/2008/04/adonet-35-certification-exam.html"&gt;the new ADO.NET 3.5 exam beta&lt;/a&gt;. Well, Microsoft published last week the results for this exam and for &lt;a href="http://www.microsoft.com/learning/en/us/exams/70-562.mspx"&gt;ASP.NET 3.5&lt;/a&gt; one too, and I'm glad to say that I passed; here it goes my new logo :)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://bp3.blogger.com/_rIotvlm4gjQ/SIy1uHYNczI/AAAAAAAAACk/nedU14cDNAA/s1600-h/MCTS(rgb)_1101.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_rIotvlm4gjQ/SIy1uHYNczI/AAAAAAAAACk/nedU14cDNAA/s320/MCTS(rgb)_1101.gif" border="0" alt="" id="BLOGGER_PHOTO_ID_5227753071329506098" /&gt;&lt;/a&gt;&lt;br /&gt;These exams should be live shortly, so if you are interested in taking them, you might want to check out &lt;a href="http://blogs.msdn.com/gerryo/"&gt;Gerry's blog&lt;/a&gt; for the latest news.&lt;br /&gt;Btw, I highly recommend taking &lt;a href="http://vishaljoshi.blogspot.com/2005/11/microsoft-beta-exams.html"&gt;beta exams&lt;/a&gt;: they help to keep up to and discover new technologies and they have the advantage of being free of charge!</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/3770613807739657916/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/07/adonet-35-certification-exam-results.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/3770613807739657916?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/3770613807739657916?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/5Do0Nl1f73s/adonet-35-certification-exam-results.html" title="ADO.NET 3.5 certification exam results" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://bp3.blogger.com/_rIotvlm4gjQ/SIy1uHYNczI/AAAAAAAAACk/nedU14cDNAA/s72-c/MCTS(rgb)_1101.gif" height="72" width="72" /><thr:total>5</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/07/adonet-35-certification-exam-results.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UNQnY_eip7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-2101747307881781947</id><published>2008-07-07T20:05:00.006+02:00</published><updated>2010-09-12T13:34:53.842+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:34:53.842+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Team Foundation Server" /><title>TFS wish list</title><content type="html">I've been using TFS 2008 for a while, and despite the new good features (easier installation, offline support, better build management, built-in continuous integration, etc), I'm a little bit disappointed to see that some limitations existent in the previous TFS 2005 haven't been solved yet in this new release.&lt;br /&gt;Don't get me wrong; I think that TFS is a great product but, moving forward, this would be my wish list for the following TFS version, &lt;a href="http://msdn.microsoft.com/en-us/vstudio/bb725993.aspx"&gt;codename Rosario&lt;/a&gt;.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Server Side Check-in policies&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/team_foundation/archive/2005/04/15/408700.aspx"&gt;Checkin policies&lt;/a&gt; are a very nice feature in TFS; for example you can enforce that before anyone checks a changeset in, he has to associate it with a Work item, or he's had to build the solution and run FxCop, etc... The concept is good, but I don't like the way that it has been implemented: Checkin policies are enforced at &lt;strong&gt;client side&lt;/strong&gt; rather than at &lt;strong&gt;server side&lt;/strong&gt; and this has some bad implications, for example the inconvenience of deploying custom checkin policies.&lt;br /&gt;TFS explorer comes along with some policies but as you may have expected you can create your own custom policies; actually you might want to check the policies that &lt;a href="http://msdn.microsoft.com/en-us/tfs2008/bb980963.aspx"&gt;TFS 2008 Power tools&lt;/a&gt; provides before creating a new one.&lt;br /&gt;So far so good, the catch is that after getting one way or another your custom policy, in order to enforce it, you have to make sure that everyone in your team deploys it in his workstation or it won't be run when they check in and, on top of that, they will get a nasty policy loading error :( As you can see &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1987073&amp;amp;SiteID=1"&gt;here&lt;/a&gt;, there are people out there that have the same frustration...&lt;br /&gt;I've been focusing in the inconvenience of deployment that this client-side model implies, but what about security? So what if a developer decides to change any of the policies implementation to disable check-in validation?... Well, you might be wondering why somebody would want to do that, but if check-in policies were enforced at server side you wouldn't be wondering.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;TFS application tier running in a 64bit box&lt;/strong&gt;&lt;br /&gt;There is not much to say about this, the header text is self explanatory :)&lt;br /&gt;Even if you go for a non single server deployment where you could use a x64 for the data tier (SQL Server), TFS application tier still needs to be installed in a x32 bit machine.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;Branching: carry source history to the branch&lt;/strong&gt;&lt;br /&gt;As Brendan Lawlor pointed out &lt;a href="http://blog.decaresystems.ie/index.php/2007/04/18/more-limitations-of-tfs-branching/"&gt;here&lt;/a&gt;, when a branch is created in TFS 2005, its history starts from its creation point of time so the branch doesn't "remember" any of the changes that were made on its source.&lt;br /&gt;This means, for example, that comparing a changeset from the branch against a change made back in time on the head becomes a non straightforward task, especially if you happen to be in a situation where nested branches are required.&lt;br /&gt;Unfortunately, after a simple test in TFS 2008, you will notice that this problem hasn't been solved yet.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;strong&gt;TFS event subscription GUI tool&lt;/strong&gt;&lt;br /&gt;It would be great if TFS came along with a proper GUI tool to handle subscriptions for events remotely, something like this &lt;a href="http://www.codeplex.com/tfseventsubscription"&gt;open source tool&lt;/a&gt; provides but not only limited to work item events.&lt;br /&gt;Even for something so simple like sending a notification email when a build fails the TFS Project Alerts screen is useless so you have to end up using the &lt;a href="http://www.codeplex.com/VSTSGuidance/Wiki/View.aspx?title=How%20to%20receive%20notification%20when%20a%20build%20has%20failed&amp;amp;referringTitle=Build%20Practices%20at%20a%20Glance"&gt;bissubscribe command tool&lt;/a&gt;, which by the way can only be run locally on the TFS application server. &lt;/li&gt;&lt;/ol&gt;That was my list; feel free to post your own thoughts and comments about it.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f07%2ftfs-wish-list.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f07%2ftfs-wish-list.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/2101747307881781947/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/07/tfs-wish-list.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/2101747307881781947?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/2101747307881781947?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/2NuvJwAB4Ts/tfs-wish-list.html" title="TFS wish list" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>5</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/07/tfs-wish-list.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEYDQX88eip7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-649751404535355212</id><published>2008-06-08T14:47:00.013+02:00</published><updated>2010-09-12T13:49:30.172+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:49:30.172+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Castle" /><category scheme="http://www.blogger.com/atom/ns#" term="AOP" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><category scheme="http://www.blogger.com/atom/ns#" term="Enterprise Library" /><title>Dependency Injection in WCF Services Part 4</title><content type="html">In the &lt;a href="http://javicrespotech.blogspot.com/2008/05/dependency-injection-in-wcf-services_17.html"&gt;last post of these series&lt;/a&gt;, I showed a first approach on how to use Castle Interceptors along with WCF Castle Facility to apply cross-cutting concerns in the Service Layer. The Log sample interceptor that I used for this last post was hopefully enough to get the flavour, but I think that a more compelling sample is needed to demonstrate what these interceptors are really capable of.&lt;br /&gt;I won't leave the Enterprise Library though, but instead of the Logging Application Block I'll use the Validation Application Block for this demo.&lt;br /&gt;&lt;br /&gt;Let's take the sample that I've been using in these series and add a Save function in the Customer Service.&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DISample.Service&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerService:ICustomerService&lt;br /&gt;  {&lt;br /&gt;      &lt;span class="preproc"&gt;#region&lt;/span&gt; properties&lt;br /&gt;      &lt;span class="kwrd"&gt;private&lt;/span&gt; ICustomerDataAccess customerDataAccess;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; ICustomerDataAccess CustomerDataAccess&lt;br /&gt;      {&lt;br /&gt;          get { &lt;span class="kwrd"&gt;return&lt;/span&gt; customerDataAccess; }&lt;br /&gt;          set { customerDataAccess = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;      }&lt;br /&gt;      &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class="preproc"&gt;#region&lt;/span&gt; ICustomerService Members&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer GetCustomer(&lt;span class="kwrd"&gt;long&lt;/span&gt; id)&lt;br /&gt;      {&lt;br /&gt;          &lt;span class="kwrd"&gt;return&lt;/span&gt; CustomerDataAccess.GetCustomer(id);&lt;br /&gt;      }&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer SaveCustomer(Customer customer)&lt;br /&gt;      {&lt;br /&gt;          &lt;span class="kwrd"&gt;return&lt;/span&gt; customerDataAccess.SaveCustomer(customer);&lt;br /&gt;      }&lt;br /&gt;      &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;And the unrealistically simple Customer class goes as follows&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DISample.Entity&lt;br /&gt;{&lt;br /&gt;  [DataContract]&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Customer&lt;br /&gt;  {&lt;br /&gt;      [DataMember]&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; CustomerId { get; set; }&lt;br /&gt;      [DataMember]&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; String Name { get; set; }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;Now we need to meet the requirement that for saving a Customer its Name must be at least 5 characters long and it cannot be longer than 35 characters... The Validation Application Block gets into the game!&lt;br /&gt;&lt;br /&gt;The Validation Application Block added value is that it provides a central repository of rules that can be used across the entire application layers so we don't end up coding the same rule in UI, Service, Data Access...&lt;br /&gt;&lt;br /&gt;The rules can be defined either in configuration files or through .NET attributes; for this sample I'll use the latter, particularly, the StringLengthValidator through its attribute.&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DISample.Entity&lt;br /&gt;{&lt;br /&gt;  [DataContract]&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Customer&lt;br /&gt;  {&lt;br /&gt;      [DataMember]&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; CustomerId { get; set; }&lt;br /&gt;    &lt;br /&gt;      [StringLengthValidator(5, 35)]&lt;br /&gt;      [DataMember]&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; String Name { get; set; }&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;The validator is already declared, but we still need to kick it off. The Enterprise Library provides some API helper methods to instatiate validators so as to fire them, for now we'll put that code in the Service implementation.&lt;pre class="csharpcode"&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerService:ICustomerService&lt;br /&gt;{&lt;br /&gt;    ....&lt;br /&gt;    &lt;span class="preproc"&gt;#region&lt;/span&gt; ICustomerService Members&lt;br /&gt;    ......&lt;br /&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer SaveCustomer(Customer customer)&lt;br /&gt;    {&lt;br /&gt;        ValidationResults validation = Validation.ValidateFromAttributes&amp;lt;Customer&amp;gt;(customer);&lt;br /&gt;        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!validation.IsValid)&lt;br /&gt;            &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException();&lt;br /&gt;&lt;br /&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; customerDataAccess.SaveCustomer(customer);&lt;br /&gt;    }&lt;br /&gt;    &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;}&lt;/pre&gt;And the validation requirement is already fulfilled with this code. If we follow this approach though, we would need to produce a similar code snippet for every method in the service and for each parameter that a method receives. In other words, this looks like a situation where an interceptor would be more than welcome :)&lt;br /&gt;&lt;br /&gt;Let's remove the validation code from the Save method and create the ValidationInterceptor class.&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DISample.Interceptor&lt;br /&gt;{&lt;br /&gt;  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ValidationInterceptor:IInterceptor&lt;br /&gt;  {&lt;br /&gt;      &lt;span class="preproc"&gt;#region&lt;/span&gt; IInterceptor Members&lt;br /&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Intercept(IInvocation invocation)&lt;br /&gt;      {&lt;br /&gt;          &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (&lt;span class="kwrd"&gt;object&lt;/span&gt; argument &lt;span class="kwrd"&gt;in&lt;/span&gt; invocation.Arguments)&lt;br /&gt;          {&lt;br /&gt;              &lt;span class="kwrd"&gt;if&lt;/span&gt; (argument != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;br /&gt;              {&lt;br /&gt;                  Validator validator = ValidationFactory.CreateValidator(argument.GetType());&lt;br /&gt;                  ValidationResults result = validator.Validate(argument);&lt;br /&gt;                  &lt;span class="kwrd"&gt;if&lt;/span&gt; (!result.IsValid)&lt;br /&gt;                      &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException();&lt;br /&gt;              }&lt;br /&gt;            &lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;As easy as it looks; input parameters are available through the Arguments property of the IInvocation interface so we just need to loop through them and use Enterprise Library Helper methods to fire the validators.&lt;br /&gt;&lt;br /&gt;You may have noticed that I haven't been very informational throwing an InvalidOperationException with no message; however it would be pretty straightforward to create a custom Exception that will carry the information that the Enterprise Library ValidationResult class provides.&lt;br /&gt;&lt;br /&gt;We are almost done, the only thing left is to declare the validation interceptor through Castle configuration file&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&lt;/span&gt; ?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerService"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.CustomerService, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;interceptors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;interceptor&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;${ValidationInterceptor}&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;interceptor&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;interceptors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="ValidationInterceptor"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Interceptor.ValidationInterceptor, DISample.Interceptor"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerDataAccess"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.ICustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;br /&gt;             &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.CustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;So before any method of the Customer class gets call, our interceptor will verify the correctness of the input parameters according to the rules defined through the Validation Application Block. No wonder that there is room for many improvements in that code, but the point that I was trying to make is that the task of apply cross cutting concerns gets much simpler using Castle Interceptors and Enterprise Library Application blocks.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f06%2fdependency-injection-in-wcf-services.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f06%2fdependency-injection-in-wcf-services.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/649751404535355212/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/06/dependency-injection-in-wcf-services.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/649751404535355212?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/649751404535355212?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/twbclfFFDvw/dependency-injection-in-wcf-services.html" title="Dependency Injection in WCF Services Part 4" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/06/dependency-injection-in-wcf-services.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QMRHk-fip7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-8073004784918248640</id><published>2008-05-22T22:00:00.011+02:00</published><updated>2010-09-12T13:36:25.756+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:36:25.756+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="SQL Server" /><category scheme="http://www.blogger.com/atom/ns#" term="Code generation" /><title>Unique Index Schema Information in SQL Server</title><content type="html">Unique indexes along foreign key constraints are used to model One-To-One relationships in Database model design. In fact, when it comes to the DB design, the only difference between a One-To-One relationship and a One-To-Many relationship is that Unique index. For Data Access code generation purposes the existence of the unique index will effectively tell you, for example if you are generating navigation properties, whether to create a simple entity type navigation (One-To-One) or an entity array type navigation (One-To-Many) between the two entities that take part in the data base relationship.&lt;br /&gt;&lt;br /&gt;In ADO.NET the &lt;a href="http://msdn.microsoft.com/en-us/library/ms254969.aspx"&gt;GetSchema methods&lt;/a&gt; can be used to get Schema information from different Data base provider types; unfortunately for SQL Server Databases unique index information is not provided with that API. Don't panic though, one way or another SQL Server hast to store the unique index information in its catalog tables so after digging into the master database views list for a while, we bump into the table sys_indexes and its is_unique column. An index can be applied upon many columns therefore we'll need to join with sys.index_columns and sys.columns in order to get the column name as well.&lt;br /&gt;&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; c.[name] &lt;span class="kwrd"&gt;as&lt;/span&gt; column_name, a.[name] &lt;span class="kwrd"&gt;as&lt;/span&gt; index_name, is_unique&lt;br /&gt;&lt;span class="kwrd"&gt;FROM&lt;/span&gt; sys.indexes a &lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; sys.index_columns b&lt;br /&gt;&lt;span class="kwrd"&gt;ON&lt;/span&gt; a.object_id = b.object_id &lt;span class="kwrd"&gt;AND&lt;/span&gt; a.index_id = b.index_id&lt;br /&gt;&lt;span class="kwrd"&gt;INNER&lt;/span&gt; &lt;span class="kwrd"&gt;JOIN&lt;/span&gt; sys.columns c&lt;br /&gt;&lt;span class="kwrd"&gt;ON&lt;/span&gt; b.object_id = c.object_id &lt;span class="kwrd"&gt;and&lt;/span&gt; b.column_id = c.column_id&lt;br /&gt;&lt;span class="kwrd"&gt;WHERE&lt;/span&gt; a.object_id = OBJECT_ID(N&lt;span class="str"&gt;'dbo.yourTable'&lt;/span&gt;)&lt;/pre&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2funique-index-schema-information-in-sql.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2funique-index-schema-information-in-sql.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/8073004784918248640/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/05/unique-index-schema-information-in-sql.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8073004784918248640?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/8073004784918248640?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/RY5k6MfLIiU/unique-index-schema-information-in-sql.html" title="Unique Index Schema Information in SQL Server" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/05/unique-index-schema-information-in-sql.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEQFQn86cSp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-5588110575247026541</id><published>2008-05-17T13:15:00.006+02:00</published><updated>2010-09-12T13:51:53.119+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:51:53.119+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection" /><category scheme="http://www.blogger.com/atom/ns#" term="Castle" /><category scheme="http://www.blogger.com/atom/ns#" term="AOP" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><category scheme="http://www.blogger.com/atom/ns#" term="Enterprise Library" /><title>Dependency Injection in WCF Services Part 3</title><content type="html">In the &lt;a href="http://javicrespotech.blogspot.com/2008/05/dependency-injection-in-wcf-services.html"&gt;first post of these series&lt;/a&gt;, I explained the problems you may run into when applying Dependency Injection in your distributed service layer, and in the &lt;a href="http://javicrespotech.blogspot.com/2008/05/dependency-injection-in-wcf-services_03.html"&gt;second one&lt;/a&gt; I put the theory in practice using &lt;a href="http://www.castleproject.org/container/facilities/trunk/wcf/index.html"&gt;Castle Windsor WCF Facility&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now that our DI container instantiates our services, we can take advantage of other features not necessarily related to Dependency Injection available in the container. Particularly in this post I'll drift away a bit from dependency injection and I'll focus on the interception capabilities that Castle Windsor framework offers.&lt;br /&gt;&lt;br /&gt;Let's take the sample that I've been using for these series and say for example that we want to use Enterprise Library Application Loggin Block so as to log every method execution in our service object.&lt;br /&gt;A simple implementation would be to include the logging call in the service implementation.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DISample.Service&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerService:ICustomerService&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; properties&lt;br /&gt;       &lt;span class="kwrd"&gt;private&lt;/span&gt; ICustomerDataAccess customerDataAccess;&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; ICustomerDataAccess CustomerDataAccess&lt;br /&gt;       {&lt;br /&gt;           get { &lt;span class="kwrd"&gt;return&lt;/span&gt; customerDataAccess; }&lt;br /&gt;           set { customerDataAccess = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; ICustomerService Members&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer GetCustomer(&lt;span class="kwrd"&gt;long&lt;/span&gt; id)&lt;br /&gt;       {&lt;br /&gt;           Logger.Write(&lt;span class="str"&gt;"GetCustomer Start"&lt;/span&gt;);&lt;br /&gt;           Customer customer = CustomerDataAccess.GetCustomer(id);&lt;br /&gt;           Logger.Write(&lt;span class="str"&gt;"GetCustomer End"&lt;/span&gt;);&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; customer;&lt;br /&gt;       }&lt;br /&gt; &lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;So we are leaving the logging responsability to the service class itself... That doesn't sound quite right, does it? The service responsability is to interact with the Data Access layer and/or carry out business process but logging is a cross cutting concern that has nothing to do with the actual service implemenation. Besides, for the sake of code cleanignless and reusability, in my Service code I don't want stuff that is not related to the Service main purpose.&lt;br /&gt;&lt;br /&gt;Then, how we can possibly achieve logging in our service object leaving the logging calls out of our service implementation? Well, we might use &lt;a href="http://en.wikipedia.org/wiki/Decorator_pattern"&gt;the Decorator pattern&lt;/a&gt; for that. This pattern gives the ability to extend the functionality of a class without changing its orginal implementation.&lt;br /&gt;Let's create the CustomerServiceLogginDecorator logging decorator in order to include logging capabilities to our service.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DISample.Service&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerServiceLoggingDecorator:ICustomerService&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; properties&lt;br /&gt;       &lt;span class="kwrd"&gt;private&lt;/span&gt; ICustomerService customerService;&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; ICustomerService CustomerService&lt;br /&gt;       {&lt;br /&gt;           get { &lt;span class="kwrd"&gt;return&lt;/span&gt; customerService; }&lt;br /&gt;           set { customerService = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; ICustomerService Members&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer GetCustomer(&lt;span class="kwrd"&gt;long&lt;/span&gt; customerId)&lt;br /&gt;       {&lt;br /&gt;           Logger.Write(&lt;span class="str"&gt;"GetCustomer Start"&lt;/span&gt;);&lt;br /&gt;           Customer customer = CustomerService.GetCustomer(customerId);&lt;br /&gt;           Logger.Write(&lt;span class="str"&gt;"GetCustomer End"&lt;/span&gt;);&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; customer;&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;Notice that the decorator implements the same interface that our service implementation; that's the whole point of the Decorator pattern. The service consumers use the service through its interface (ICustomerService) and it's through the DI container that we specify a particular service implementation for that interface. Therefore, we can create our decorator as a service frontend and inject the actual service implementation into the decorator.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerService"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.&lt;span style="color:#ff0000;"&gt;CustomerServiceLoggingDecorator&lt;/span&gt;, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerServiceImpl"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.CustomerService, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerDataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.ICustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.CustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;Notice as well that, since the decorator uses ICustomerService interface as dependency, the underlying implementation of the service remains hidden and therefore we can use the DI container to inject as many ICustomerService decorators as we wish upon the real service implementation. Let's imagine that we want to add an exception decorator...&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerService"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.&lt;span style="color:#ff0000;"&gt;CustomerServiceExceptionDecorator&lt;/span&gt;, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerServiceLogging"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.&lt;span style="color:#ff0000;"&gt;CustomerServiceLoggingDecorator&lt;/span&gt;, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerServiceImpl"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.CustomerService, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerDataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.ICustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.CustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;Ok, so we got it, there are no longer cross cutting concerns in my service implementation but probably you´ll have already realized that this solution is not the best either. If we carried on with this approach we'd need to create a decorator for each cross cutting concern in each service, it means that we could end up with a number of decorator classes up to (number of Services)*(number of cross cutting concerns) = let´s call this idea off now!&lt;br /&gt;&lt;br /&gt;Well, it looks like the Decorator Pattern can be the way but we need something to remove from us the burden of creating for a single aspect a bunch of service specific decorators. Fortunately, castle framework comes to our rescue and offers us &lt;a href="http://www.castleproject.org/container/documentation/trunk/usersguide/interceptors.html"&gt;the Interceptor functionality&lt;/a&gt; which allows to create independent and reusable cross cutting concern implementations.&lt;br /&gt;Let´s create our reusable logging interceptor.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Castle.Core.Interceptor;&lt;br /&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Microsoft.Practices.EnterpriseLibrary.Logging;&lt;br /&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; DISample.Interceptor&lt;br /&gt;{&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; LogginInterceptor:IInterceptor&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; IInterceptor Members&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Intercept(IInvocation invocation)&lt;br /&gt;       {&lt;br /&gt;           Logger.Write(invocation.Method.Name + &lt;span class="str"&gt;" Start"&lt;/span&gt;);&lt;br /&gt;           invocation.Proceed();&lt;br /&gt;           Logger.Write(invocation.Method.Name + &lt;span class="str"&gt;" End"&lt;/span&gt;);&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;And to start using it, we just have to define it in the castle configuration file.&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerService"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.CustomerService, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;interceptors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;interceptor&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;${LoginInterceptor}&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;interceptor&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;     &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;interceptors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="LoginInterceptor"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Interceptor.LoginInterceptor, DISample.Interceptor"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerDataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.ICustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.CustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;That's great, isn't it? We define independent interceptors that can be applied upon any class regardless of its type; Castle will take care of the call flow an interception for us.&lt;br /&gt;&lt;br /&gt;To that's it, we have used Castle framework to apply cross cutting concerns in our WCF Service... But that's not what WCF Custom Behaviours are for? Yes, Custom Behaviours get injected in the WCF call stack and in there you can implement some aspects not related to your service implementation like logging, catching, transaction handling, etc. Besides the &lt;a href="http://msdn.microsoft.com/en-us/library/aa480453.aspx"&gt;Enterprise Library 3.1&lt;/a&gt; comes along with a set of Custom Behaviors for WCF that are nothing more that thin wrappers upon the Application Blocks like the &lt;a href="http://msdn.microsoft.com/en-us/library/cc309334.aspx"&gt;Validation Block Custom Behavior&lt;/a&gt;. Then, why would we want to build Castle Interceptors if we can use the Enterprise Library WCF custom Behaviors?.&lt;br /&gt;&lt;br /&gt;Thinking in terms of the overall application and not only about the service layer, you might decide to apply cross cutting concerns to your web layer, your controller layer, your data access layer, etc. and for that WCF Custom Behaviours have no use. The bottom line is that if you want to use a unique homogeneous mechanish to handle cross cutting concers across all your application layers, WCF Custom Behaviours are not the solution!&lt;br /&gt;&lt;br /&gt;Having said that, in the next post of these series I'll show how to implement a more sophisticated Interceptor than the Logging one I explained in this post; Particularly I'll show what it takes to implement an equivalent of the Enterprise Library WCF Validation Custom Behaviour in a Castle Interceptor.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fdependency-injection-in-wcf-services_17.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fdependency-injection-in-wcf-services_17.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/5588110575247026541/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/05/dependency-injection-in-wcf-services_17.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/5588110575247026541?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/5588110575247026541?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/zcFgL34lMb8/dependency-injection-in-wcf-services_17.html" title="Dependency Injection in WCF Services Part 3" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/05/dependency-injection-in-wcf-services_17.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMCQHozcCp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-1800364193211564221</id><published>2008-05-10T12:20:00.008+02:00</published><updated>2010-09-12T13:54:21.488+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:54:21.488+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="JSON" /><category scheme="http://www.blogger.com/atom/ns#" term="WebServices" /><category scheme="http://www.blogger.com/atom/ns#" term="Ajax" /><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>JSON services in ASP.NET Ajax</title><content type="html">Lately the use of client centric development model in .NET is getting increasingly popular. In contrast to the traditional server model where html tags are rendered in server side and then sent to the browser, the client centric approach consist of the use of asynchronous HTTP requests to retrieve data from server side and then do the html rendering in client side code.&lt;br /&gt;&lt;br /&gt;The main advantage of this client centric approach is that the communication between the browser and the server gets much lighter; the browser doesn't need to post the page to get information from the server, it rather issues asynchronous calls to Web Services, which implement the JSON protocol, for retrieving the data. You might be wondering why XML-SOAP or other XML based RPC protocols are not used instead of that JSON...&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/JSON"&gt;JSON&lt;/a&gt; is a non-markup based language which has some limitations comparing to XML languages (i.e: lack of namespaces) but that simplicity makes it lighter, easier to handle by browsers, and overall more performant and more suitable for this web client scenario.&lt;br /&gt;&lt;br /&gt;Unfortunately there is a catch :( ; since the rendering is done in client side, you'd better forget about using your automatically rendered ASP.NET controls and be prepared to start messing around extensively with javascript code for the rendering... No need to go through that pain though, there are some third party client based controls that implement rendering through javascript libraries, particularly you might want to check what &lt;a href="http://www.codeplex.com/AjaxDataControls"&gt;this open source control library&lt;/a&gt; can offer you.&lt;br /&gt;&lt;br /&gt;Well, now that we have gone through the theory, how can we put that in practice in ASP.NET? How can we implement and consume a JSON service?&lt;br /&gt;ASP.NET Ajax framework provides some built-in mechanisms to handle JSON communication and serialization automatically.&lt;br /&gt;These mechanisms are &lt;strong&gt;Page Methods&lt;/strong&gt;, &lt;strong&gt;Ajax Web Services&lt;/strong&gt; and &lt;strong&gt;Ajax WCF Services&lt;/strong&gt; and I'm going to spend the rest of this post to do a brief walkthrough on them.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Page methods&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;A page method is a static function marked as a web method and declared within the page code behind. This function can be called from javascript code through a predefined class/keyword called &lt;strong&gt;PageMethods&lt;/strong&gt;. Let's take a look in a sample step by step.&lt;br /&gt;&lt;br /&gt;First the Page method execution has to be enabled in the asp.net ScriptManager.&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManager&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;="scriptManager"&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt; &lt;span class="attr"&gt;EnablePageMethods&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;Now it's time to implement the static web method in the page's code behind.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;partial&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; _Default : System.Web.UI.Page&lt;br /&gt;{&lt;br /&gt;   [WebMethod]&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; String ToUpper(&lt;span class="kwrd"&gt;string&lt;/span&gt; name)&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;return&lt;/span&gt; name.ToUpper();&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;Finally, the method is consumed from a script included in the page. As I said before the call execution follows an asynchronous pattern, therefore in the sample below if the operation succeds the resulting string in upper case is passed to the OnSucceded method, otherwise the OnFailed method receives the .NET exception.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; ToUpper(name)&lt;br /&gt;{&lt;br /&gt;   PageMethods.ToUpper(name, OnSuccedeed, OnFailed);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; OnSuccedeed(res)&lt;br /&gt;{&lt;br /&gt;   alert(res);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; OnFailed(error)&lt;br /&gt;{&lt;br /&gt;   &lt;span class="rem"&gt;// Alert user to the error.&lt;/span&gt;&lt;br /&gt;   alert(error.get_message());&lt;br /&gt;}&lt;/pre&gt;&lt;strong&gt;&lt;div&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/div&gt;Web Services&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;One of the main differences between Page Methods and Ajax Web Services is that Page Methods can only be used by a single Page and Web Services can be used from as many pages as it’s needed. Needlees to say, both Ajax Web Services and Page Methods use JSON as communication protocol. Let's rework the previous example to use Web Services.&lt;br /&gt;&lt;br /&gt;First the HTTP Handler that will serve AJAX Web services requests and responses needs to be included in the web.config file.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;httpHandlers&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;remove&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.asmx"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;verb&lt;/span&gt;&lt;span class="kwrd"&gt;="*"&lt;/span&gt; &lt;span class="attr"&gt;path&lt;/span&gt;&lt;span class="kwrd"&gt;="*.asmx"&lt;/span&gt; &lt;span class="attr"&gt;validate&lt;/span&gt;&lt;span class="kwrd"&gt;="false"&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=1.0.61025.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;Next step is to create a web service, which I'll call StringHandler.asmx. The Web Service's class needs to be marked with the ScriptService attribute and ToUpper web method to be implemented.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; JsonServicesSample&lt;br /&gt;{&lt;br /&gt;   [ScriptService]&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; StringHandler : System.Web.Services.WebService&lt;br /&gt;   {&lt;br /&gt;       [WebMethod]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ToUpper(String input)&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; input.ToUpper();&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;We are getting there, now it's just to include the server through the ScriptManager...&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManager&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;="ScriptManager1"&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ServiceReference&lt;/span&gt;&lt;br /&gt;         &lt;span class="attr"&gt;Path&lt;/span&gt;&lt;span class="kwrd"&gt;="~/StringHandler.asmx"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManager&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;and everything is ready to retrieve data from the client script.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; ToUpper(name)&lt;br /&gt;{&lt;br /&gt;   JsonServicesSample.StringHandler&lt;br /&gt;   .ToUpper(name, OnSuccedeed, OnFailed);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; OnSuccedeed(res)&lt;br /&gt;{&lt;br /&gt;   alert(res);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; OnFailed(error)&lt;br /&gt;{&lt;br /&gt;   &lt;span class="rem"&gt;// Alert user to the error.&lt;/span&gt;&lt;br /&gt;   alert(error.get_message());&lt;br /&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;strong&gt;WCF Services&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The .NET 3.5 framework release came along with some fixes and extensions upon the early WCF .NET 3.0 version; one of those extensions is the webHttpBinding binding which implements JSON serialization and communication protocol.&lt;br /&gt;So for those who use VS2008 and .NET 3.5 let's rework the sample for the last time.&lt;br /&gt;&lt;br /&gt;First of all the service implementation has to be changed to include the WCF contract attributes; for the sake of simplicity I won't create a separate interface for the contract, I'd rather apply the contract attributes in the implementation itself.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;namespace&lt;/span&gt; JsonServicesSample&lt;br /&gt;{&lt;br /&gt;   [ServiceContract&lt;br /&gt;       (Namespace=&lt;span class="str"&gt;"JsonServices.Contract.Sample"&lt;/span&gt;)]&lt;br /&gt;   [AspNetCompatibilityRequirements(&lt;br /&gt;           RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]&lt;br /&gt;   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; StringHandler : System.Web.Services.WebService&lt;br /&gt;   {&lt;br /&gt;       [OperationContract]&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ToUpper(String input)&lt;br /&gt;       {&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; input.ToUpper();&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;On top of the WCF contract attributes, the &lt;strong&gt;AspNetCommpatibilityRequirements&lt;/strong&gt; attribute is provided. That attribute will allow the WCF service to have access to the HTTP context (i.e.: ASP.NET Session variable) and besides, it will tell the runtime to ensure at Service Host creation time that all the enpoints defined for the JSON contract use the Web http binding.&lt;br /&gt;Now it's time to define the service and its endpoint in Web.config file, notice that the AspNetCompatibilityRequirements attribute needs to be defined at the ServiceHost level as well.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;behaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpointBehaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;behavior&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="StringHandlerBehavior"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;               &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;enableWebScript&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;behavior&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;endpointBehaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;behaviors&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;serviceHostingEnvironment&lt;/span&gt; &lt;span class="attr"&gt;aspNetCompatibilityEnabled&lt;/span&gt;&lt;span class="kwrd"&gt;="true"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="JsonServicesSample.StringHandler"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;           &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;endpoint&lt;/span&gt; &lt;span class="attr"&gt;address&lt;/span&gt;&lt;span class="kwrd"&gt;=""&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;behaviorConfiguration&lt;/span&gt;&lt;span class="kwrd"&gt;="StringHandlerBehavior"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;binding&lt;/span&gt;&lt;span class="kwrd"&gt;="webHttpBinding"&lt;/span&gt;&lt;br /&gt;                 &lt;span class="attr"&gt;contract&lt;/span&gt;&lt;span class="kwrd"&gt;="JsonServicesSample.StringHandler"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.serviceModel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;Since the service will be deployed in a IIS environment, the StringHandler.svc is created.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span&gt;&amp;lt;%@ServiceHost&lt;br /&gt;  Service="JsonServicesSample.StringHandler" %&amp;gt;&lt;/span&gt;&lt;/pre&gt;The server configuration tasks are done, now the service reference needs to be included in the page's Script Manager&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManager&lt;/span&gt; &lt;span class="attr"&gt;ID&lt;/span&gt;&lt;span class="kwrd"&gt;="ScriptManager1"&lt;/span&gt; &lt;span class="attr"&gt;runat&lt;/span&gt;&lt;span class="kwrd"&gt;="server"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;asp:ServiceReference&lt;/span&gt;&lt;br /&gt;         &lt;span class="attr"&gt;Path&lt;/span&gt;&lt;span class="kwrd"&gt;="~/StringHandler.svc"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Services&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;asp:ScriptManager&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;And everything is ready to start using the service from client side script code.&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; ToUpper(name)&lt;br /&gt;{&lt;br /&gt;   JsonServices.Contract.Sample.StringHandler&lt;br /&gt;   .ToUpper(name, OnSuccedeed, OnFailed);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; OnSuccedeed(res)&lt;br /&gt;{&lt;br /&gt;   alert(res);&lt;br /&gt;}&lt;br /&gt;&lt;span class="kwrd"&gt;function&lt;/span&gt; OnFailed(error)&lt;br /&gt;{&lt;br /&gt;   &lt;span class="rem"&gt;// Alert user to the error.&lt;/span&gt;&lt;br /&gt;   alert(error.get_message());&lt;br /&gt;}&lt;/pre&gt;You may have already noticed that instead of using the service .NET class namespace (JsonServicesSample) as we did in the Web Services sample, this proxy uses JsonService.Contract.Sample, but what the ** is that? Well if you go back to the StringHandler implementation you'll notice that the ServiceContract defines a namespace...&lt;br /&gt;&lt;pre class="csharpcode"&gt;[ServiceContract&lt;br /&gt;(Namespace=&lt;span class="str"&gt;"JsonServices.Contract.Sample"&lt;/span&gt;)]&lt;/pre&gt;So the bottom line is that &lt;strong&gt;WCF client-side proxys use the contract namespace in contrast with Ajax Web services which use the .NET class namespace instead.&lt;/strong&gt;.&lt;br /&gt;And that's it, our WCF service and client are ready. Before finishing though, it's worth mentioning the &lt;strong&gt;WebScriptServiceHostFactory&lt;/strong&gt; Service Host Factory and how it can help us to remove configuration from Json WCF services.&lt;br /&gt;Comparing to the Web service solution, in WCF sample an additional step was taken in order to define the service and endpoint configuration. If you want to keep it simple and skip that step you can do it using the WebScriptServiceHostFactory Service Host factory. This factory creates ServiceHosts with the default services, endpoints and behaviours suitable for this Json web environment so explicit configuration is no longer needeed&lt;br /&gt;In order to achieve it, if we look at the sample then, the service factory is declared in the .svc file...&lt;br /&gt;&lt;pre class="csharpcode"&gt;&lt;span&gt;&amp;lt;%@ServiceHost&lt;br /&gt;  Service="JsonServicesSample.StringHandler"&lt;br /&gt;  Factory="System.ServiceModel.Activation.WebScriptServiceHostFactory"%&amp;gt;&lt;/span&gt;&lt;/pre&gt;...so the WCF configuration can be now wiped out from the web.config file.&lt;br /&gt;&lt;br /&gt;That's all folks! I hope that if you weren't familiar with this subject this rather long post has given you an idea of what it takes to implement basic Json services in ASP.NET.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fjson-services-in-aspnet-ajax.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fjson-services-in-aspnet-ajax.html&amp;amp;&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/1800364193211564221/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/05/json-services-in-aspnet-ajax.html#comment-form" title="7 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/1800364193211564221?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/1800364193211564221?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/VMttZdTJobw/json-services-in-aspnet-ajax.html" title="JSON services in ASP.NET Ajax" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>7</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/05/json-services-in-aspnet-ajax.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUGRng8eSp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-6339035034018055280</id><published>2008-05-03T15:49:00.014+02:00</published><updated>2010-09-12T13:50:27.671+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:50:27.671+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection" /><category scheme="http://www.blogger.com/atom/ns#" term="Castle" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>Dependency Injection in WCF Services Part 2</title><content type="html">In the &lt;a href="http://javicrespotech.blogspot.com/2008/05/dependency-injection-in-wcf-services.html"&gt;first post of these series&lt;/a&gt;, I explained the problems you may run into when applying Dependency Injection in your distributed service layer and some of the available solutions to get them around, mainly focusing WCF services. Let's finish off with the theory and put one of those solutions in practice, shall we? In this post I'll rework the sample that I used in my previous post to show the Service Locator pattern in order to use Dependency Injection instead. As in the project that I'm currently working on we are using Castle, I'll use WCF Castle facility to do the service injection.&lt;br /&gt;&lt;br /&gt;Let's take then my Service Locator sample&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerService:ICustomerService&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; ICustomerService Members&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer GetCustomer(&lt;span class="kwrd"&gt;long&lt;/span&gt; id)&lt;br /&gt;       {&lt;br /&gt;           ICustomerDataAccess da;&lt;br /&gt;           da = Global.Container.Resolve&amp;lt;ICustomerDataAccess&amp;gt;();&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; da.GetCustomer(id);&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;   }&lt;/pre&gt;and rework it to use Dependency Injection&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerService:ICustomerService&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; properties&lt;br /&gt;       &lt;span class="kwrd"&gt;private&lt;/span&gt; ICustomerDataAccess customerDataAccess;&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; ICustomerDataAccess CustomerDataAccess&lt;br /&gt;       {&lt;br /&gt;           get { &lt;span class="kwrd"&gt;return&lt;/span&gt; customerDataAccess; }&lt;br /&gt;           set { customerDataAccess = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;br /&gt;       }&lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; ICustomerService Members&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer GetCustomer(&lt;span class="kwrd"&gt;long&lt;/span&gt; id)&lt;br /&gt;       {&lt;br /&gt;      &lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; CustomerDataAccess.GetCustomer(id);&lt;br /&gt;       }&lt;br /&gt;  &lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;   }&lt;/pre&gt;You can notice that with those changes our service class is no longer dependant on the DI container for resolving the CustomerDataAccess implementation like it is in the Service Locator example. Instead, the Data access dependency is a property that can be injected by an external agent, which can be whatever DI container we want to use or even a simple factory... Let's focus on this sample though!&lt;br /&gt;&lt;br /&gt;The next step is to create a Castle configuration file called "Objects.xml" where both service and data access objects are defined.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&lt;/span&gt; ?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerService"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.ICustomerService, DISample.Service"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.Service.CustomerService, DISample.Service"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;="CustomerDataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;service&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.ICustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;br /&gt;              &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="DISample.DataAccess.CustomerDataAccess, DISample.DataAccess"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;component&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt; &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;components&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;As you can see there is no need to connect the DataAccess dependency to the Service object in the configuration file; Castle automatically wires it up.&lt;br /&gt;&lt;br /&gt;Now that the Service code is ready for injection and the objects are defined in a configuration file, it's time to use the WCF facility to do the actual service injection.&lt;br /&gt;In order to install the dependency injection behavior, Castle facility uses a a custom WCF ServiceHost. Then, for a non-IIS 6.0 environment and asuming that the service and the endpoint configuration are located in an external configuration file, our WCF host creation would look something like this.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;WindsorContainer container = &lt;span class="kwrd"&gt;new&lt;/span&gt; WindsorContainer(&lt;span class="str"&gt;"Objects.xml"&lt;/span&gt;);&lt;br /&gt;Uri uri = &lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;"net.tcp://localhost/DISample"&lt;/span&gt;);&lt;br /&gt;WindsorServiceHost host = &lt;span class="kwrd"&gt;new&lt;/span&gt; WindsorServiceHost(container.Kernel, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(CustomerService), uri);&lt;br /&gt;host.Open();&lt;/pre&gt;We instantiate the Windsor container with our object configuration file so as to be used by the custom service host... and that's all for non-IIS6.0 hosts!&lt;br /&gt;&lt;br /&gt;As you may already know, ServiceHost instatiatation model for WCF services host under II6.0 is different: We don't explictly create the ServiceHost; instead ServiceHosts are created by a ServiceHostFactory on each HTTP request.&lt;br /&gt;WCF castle facility provides a custom ServiceHostFactory that can be specified for its use in IIS6 .svc service files. Let's change the default CustomerService.svc accordingly.&lt;pre class="csharpcode"&gt;&lt;span&gt;&amp;lt;%@ ServiceHost Service="CustomerService"&lt;br /&gt;Factory="Castle.Facilities.WcfIntegration.WindsorServiceHostFactory, Castle.Facilities.WcfIntegration" %&amp;gt;&lt;/span&gt;&lt;/pre&gt;Where the value of attribute Service must match either the id of our service in Castle configuration file or the service type itself.&lt;br /&gt;Are we missing anything? We haven't created the Windsor Container yet, have we?. Like I said before in II6.0 environments ServiceHosts are created by http request, but would it be wise to apply the same approach for creating the WindsorContainer? I don't think so! Don't panic though, WCF facility has already covered that. Since we are in a web environment, we can use the Global.asax Application_Start event to create our Windsor Container and then register it through an available method in the custom ServiceHostFactory.&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 13px; white-space: pre;"&gt;&lt;span class="Apple-style-span"  &gt;&lt;span class="Apple-style-span" style="font-size: 16px; white-space: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Global : System.Web.HttpApplication&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Application_Start(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;br /&gt;       {&lt;br /&gt;           WindsorContainer container = &lt;span class="kwrd"&gt;new&lt;/span&gt; WindsorContainer(&lt;span class="str"&gt;"Objects.xml"&lt;/span&gt;);&lt;br /&gt;           WindsorServiceHostFactory.RegisterContainer(container.Kernel);&lt;br /&gt;       }&lt;br /&gt;   }&lt;/pre&gt;We are done! What's next then? One of the things that I pointed out &lt;a href="http://javicrespotech.blogspot.com/2008/05/dependency-injection-in-wcf-services.html"&gt;in the first post of this series&lt;/a&gt; is that no AOP features can be applied upon objects that are not handled by the DI container... That's no longer a problem for us!&lt;br /&gt;In the &lt;a href="http://javicrespotech.blogspot.com/2008/05/dependency-injection-in-wcf-services_17.html"&gt;next post of these series&lt;/a&gt; I'll show how we can use castle interceptors to apply cross cutting concerns upon service objects.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fdependency-injection-in-wcf-services_03.html"&gt;&lt;img alt="kick it on DotNetKicks.com" src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fdependency-injection-in-wcf-services_03.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/6339035034018055280/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/05/dependency-injection-in-wcf-services_03.html#comment-form" title="6 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6339035034018055280?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/6339035034018055280?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/cH4fnV0r5_c/dependency-injection-in-wcf-services_03.html" title="Dependency Injection in WCF Services Part 2" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>6</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/05/dependency-injection-in-wcf-services_03.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0QAQ307fCp7ImA9Wx5XEkQ.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-5114530709625080319</id><published>2008-05-01T18:50:00.037+02:00</published><updated>2010-09-12T13:35:42.304+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-09-12T13:35:42.304+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection" /><category scheme="http://www.blogger.com/atom/ns#" term="WebServices" /><category scheme="http://www.blogger.com/atom/ns#" term="Castle" /><category scheme="http://www.blogger.com/atom/ns#" term="Spring.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="WCF" /><title>Dependency Injection in WCF Services</title><content type="html">To use &lt;a href="http://www.martinfowler.com/articles/injection.html#FormsOfDependencyInjection"&gt;Dependency Injection&lt;/a&gt; in a distributed service layer is not a trivial task. Either if you use Web Services or WCF, your services are created by the .NET engine, so somehow you need to find a way to inject your Dependency Injection Container in there.&lt;br /&gt;&lt;br /&gt;You might as well let the engine create your service and then use the &lt;a href="http://www.martinfowler.com/articles/injection.html#UsingAServiceLocator"&gt;Service Locator pattern&lt;/a&gt; to hook up the underlying layer.&lt;br /&gt;In the following code snippet we use &lt;a href="http://www.castleproject.org/"&gt;Castle container&lt;/a&gt; as a Service Locator to retrieve the Data Access Layer instance that is used from our WCF service.&lt;pre class="csharpcode"&gt;    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomerService:ICustomerService&lt;br /&gt;   {&lt;br /&gt;       &lt;span class="preproc"&gt;#region&lt;/span&gt; ICustomerService Members&lt;br /&gt;       &lt;span class="kwrd"&gt;public&lt;/span&gt; Customer GetCustomer(&lt;span class="kwrd"&gt;long&lt;/span&gt; id)&lt;br /&gt;       {&lt;br /&gt;           ICustomerDataAccess da;&lt;br /&gt;           da = Global.Container.Resolve&amp;lt;ICustomerDataAccess&amp;gt;();&lt;br /&gt;           &lt;span class="kwrd"&gt;return&lt;/span&gt; da.GetCustomer(id);&lt;br /&gt;       }&lt;br /&gt;&lt;br /&gt;       &lt;span class="preproc"&gt;#endregion&lt;/span&gt;&lt;br /&gt;   }&lt;/pre&gt;In the above example, you'll notice that apart from using &lt;a href="http://www.martinfowler.com/articles/injection.html#ServiceLocatorVsDependencyInjection"&gt;a slightly different pattern&lt;/a&gt; for creating the Data Access object, the service instantiation is not handled by our DI container and this has some bad implications. Some DI containers, such as Castle or Spring.NET, offer &lt;a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;AOP&lt;/a&gt; features but those features can only be applied upon objects instantiated by the container. So the bottom line is that in this scenario we can't use those AOP frameworks upon our service objects.&lt;br /&gt;&lt;br /&gt;So for some scenarios Service Locator pattern could be just alright, but what if we still want to go for a pure Dependency Injection pattern in our service layer? How can we get around the service creation problem?&lt;br /&gt;&lt;br /&gt;If you are using Web Services I'm afraid you don't have many options. Comparing to WCF, Web services is not a very configurable technology and the only way to intercept requests is to replace the ASP.NET default HttpHandler with a custom one, which handles the requests/responses and the service object creation. Good news are that if you are using &lt;a href="http://www.springframework.net/"&gt;Spring.NET&lt;/a&gt;, you don't need to create the handler yourself; there is a &lt;a href="http://www.springframework.net/doc-latest/reference/html/webservices.html"&gt;custom HttpHandler implementation&lt;/a&gt; in the framework that you can use for that purpose.&lt;br /&gt;&lt;br /&gt;If you are using WCF in your service layer, congratulations :) WCF is a highly configurable technology and in fact it provides AOP features through the injection of &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163302.aspx"&gt;custom behaviors&lt;/a&gt;. Using this extensibility &lt;a href="http://orand.blogspot.com/"&gt;Oran&lt;/a&gt; gives us the solution to our problem &lt;a href="http://orand.blogspot.com/2006/10/wcf-service-dependency-injection.html"&gt;here&lt;/a&gt;. As you can read in that post, for creating new service instances WCF uses a factory, which implements IInstanceProvider ... Great news are that we can create a custom behavior that replaces the default IInstanceProvider factory implementation with our own implementation, and in there we can hook up our DI Container.&lt;br /&gt;To cut a long story short, Oran creates an IInstanceProvider implementation that uses Spring.NET container for service objects creation.&lt;br /&gt;&lt;br /&gt;If you are not using Spring.NET, don't panic :) there are also implementations available &lt;a href="http://www.ayende.com/Blog/archive/2007/06/12/WCF-Windsor-Integration.aspx"&gt;for Castle&lt;/a&gt; (created by &lt;a href="http://www.ayende.com/"&gt;Ayende&lt;/a&gt;) and &lt;a href="http://weblogs.asp.net/cibrax/archive/2007/12/13/wcf-dependency-injection-behavior.aspx"&gt;for ObjectBuilder&lt;/a&gt; (created by &lt;a href="http://weblogs.asp.net/cibrax/default.aspx"&gt;Pablo M. Cibraro&lt;/a&gt;) that follow similar approaches than Oran's. Even if you are using Spring.NET, you might as well use &lt;a href="http://plainoldstan.blogspot.com/2008/03/source-code-for-amendments-to-oran.html"&gt;Stan's ammendments&lt;/a&gt; to Oran's solution.&lt;br /&gt;&lt;br /&gt;To sum up, in this post we have explored some different options to implement Dependency Injection in our Service Layer depending on the distributed technology (WebServices and WCF) and on the DI container (Spring.NET, Castle..) used.&lt;br /&gt;&lt;br /&gt;In the &lt;a href="http://javicrespotech.blogspot.com/2008/05/dependency-injection-in-wcf-services_03.html"&gt;next post of these series&lt;/a&gt;, I'll put these concepts in practice using the WCF Dependency Injection Castle facility.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dotnetkicks.com/kick/?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fdependency-injection-in-wcf-services.html"&gt;&lt;img src="http://www.dotnetkicks.com/Services/Images/KickItImageGenerator.ashx?url=http%3a%2f%2fjavicrespotech.blogspot.com%2f2008%2f05%2fdependency-injection-in-wcf-services.html&amp;amp;bgcolor=3E700F&amp;amp;cbgcolor=CAF99B" border="0" alt="kick it on DotNetKicks.com" /&gt;&lt;/a&gt;</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/5114530709625080319/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/05/dependency-injection-in-wcf-services.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/5114530709625080319?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/5114530709625080319?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/hDSNCod-JV8/dependency-injection-in-wcf-services.html" title="Dependency Injection in WCF Services" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/05/dependency-injection-in-wcf-services.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEACSH04eyp7ImA9WxdTFEw.&quot;"><id>tag:blogger.com,1999:blog-5608490812663757705.post-9177220554612219265</id><published>2008-04-29T19:56:00.001+02:00</published><updated>2008-05-10T12:52:49.333+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-10T12:52:49.333+02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ADO.NET" /><category scheme="http://www.blogger.com/atom/ns#" term="Certifications" /><category scheme="http://www.blogger.com/atom/ns#" term="LINQ" /><title>ADO.NET 3.5 Certification exam</title><content type="html">A few days ago I sat for the beta exam &lt;a href="http://www.microsoft.com/learning/exams/70-561.mspx"&gt;70-561 .NET Framework 3.5 ADO.NET&lt;/a&gt;. This is the second exam that I've taken for the new .NET 3.5 certifications generation; at the end of last year I took &lt;a href="http://www.microsoft.com/learning/exams/70-503.mspx"&gt;70-503 WCF's exam&lt;/a&gt; and I recently got the &lt;a href="http://blogs.msdn.com/gerryo/archive/2008/04/14/exams-live-today.aspx"&gt;results&lt;/a&gt; with a happy end for me :)&lt;br /&gt;&lt;br /&gt;In 70-561 exam besides traditional topics such as ADO.NET connected data(Commands, DataReaders, etc) and ADO.NET disconnected data (DataSets, DataTables, etc), there is plenty of new stuff that you'd better be familiar with if you want to pass! One of those things is LINQ and LINQ to SQL, which I didn't find particularly difficult maybe cause I've had the chance to work with it.&lt;br /&gt;&lt;br /&gt;If you are not familiar with LINQ to SQL, my buddy &lt;a href="http://www.sidarok.com/web/blog/index.php"&gt;Sidar&lt;/a&gt; came up with a great &lt;a href="http://www.sidarok.com/web/blog/content/2008/04/21/a-brief-introduction-to-linq-to-sql.html"&gt;introduction post&lt;/a&gt; and Scott Guthrie has a very nice &lt;a href="http://weblogs.asp.net/scottgu/archive/2007/05/19/using-linq-to-sql-part-1.aspx"&gt;series of posts&lt;/a&gt; that you don't want to miss out.&lt;br /&gt;&lt;br /&gt;Another new topic, (at least for me) was Synchronization services. Maybe it's because I've never used it, but questions about Synchronization Services were by far the most difficult for me! You can find &lt;a href="http://www.syncguru.com/Projects.aspx"&gt;here&lt;/a&gt; a bunch of demos for the Synchronization framework that you might find useful.&lt;br /&gt;&lt;br /&gt;The last but not the least is the Entity Framework which is still in beta... That's one of the disadvantages of taking beta exams, you are sometimes supposed to have knowledge and experience in technologies that haven't been available long enough... I won't complain though, beta exams do have some advantages (Did I mention that they are free?:)) You can find some code samples for EF Beta 3 version in &lt;a href="http://www.codeplex.com/adonetsamples/"&gt;CodePlex&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The beta period for this exam and ASP.NET exam have been extended until the 5th of May, so if you haven't sat for it yet and you want to take it, hurry up and check &lt;a href="http://blogs.msdn.com/gerryo/archive/2008/04/02/asp-net-and-ado-net-beta-exams-extended.aspx"&gt;Gerry's certification blog&lt;/a&gt;!</content><link rel="replies" type="application/atom+xml" href="http://javiercrespoalvez.com/feeds/9177220554612219265/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://javiercrespoalvez.com/2008/04/adonet-35-certification-exam.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/9177220554612219265?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/5608490812663757705/posts/default/9177220554612219265?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/JavisTechnicalBlog/~3/J3OsYhKUxuI/adonet-35-certification-exam.html" title="ADO.NET 3.5 Certification exam" /><author><name>Javi</name><uri>http://www.blogger.com/profile/11872722615399930636</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://javiercrespoalvez.com/2008/04/adonet-35-certification-exam.html</feedburner:origLink></entry></feed>
