<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1561696658668544884</id><updated>2012-01-11T07:45:16.463-08:00</updated><category term='asp.net'/><category term='xml'/><category term='jquery javascript'/><category term='linq-to-sql'/><category term='web services'/><category term='sql server'/><title type='text'>A Digital Era</title><subtitle type='html'>Moving from Coder to Craftsman</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-3623434198939085155</id><published>2010-04-01T12:52:00.000-07:00</published><updated>2010-04-01T12:55:45.706-07:00</updated><title type='text'>A Quick Post on Internationalization</title><content type='html'>I haven't posted here in quite a while. Since that's the case, I thought I'd start things off with a quick laundry list of things to consider when you're dealing with localization in ASP.NET.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Absolutely and brutally minimize the number of images you have that contain text. Doing so will make your life a billion percent easier since you won't have to get a new set of images for every friggin' language.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Be very wary of css positioning that relies on things always remaining the same size. If those things contain text, they will not remain the same size, and you will then need to go back and fix your designs.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If you use character types in your sql tables, make sure that any of those that might receive international input are unicode (nchar, nvarchar, ntext). For that matter, I would just standardize on using the unicode versions.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If you're building SQL queries dynamically, make sure that you include the N prefix before any quoted text if there's any chance that text might be unicode. If you end up putting garbage in a SQL table, check to see if that's there.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Make sure that all your web pages definitively state that they are in a unicode format.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;See Joel's article on Unicode - &lt;a href="http://joelonsoftware.com/articles/Unicode.html"&gt;The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;You're going to be using resource files a lot for this project. That's good - ASP.NET 2.0 has great support for such. You'll want to look into the App_LocalResources and App_GlobalResources folder as well as GetLocalResourceObject, GetGlobalResourceObject, and the concept of meta:resourceKey. Chapter 30 of Professional ASP.NET 2.0 has some great content regarding that. The 3.5 version of the book may well have good content there as well, but I don't own it.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Think about fonts. Many of the standard fonts you might want to use aren't unicode capable. I've always had luck with Arial Unicode MS, MS Gothic, MS Mincho. I'm not sure about how cross-platform these are, though. Also, note that not all fonts support all of the Unicode character definition. Again, test, test, test.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Start thinking now about how you're going to get translations into this system. Go talk to whoever is your translation vendor about how they want data passed back and forth for translation. Think about the fact that, through your local resource files, you will likely be repeating some commonly used strings through the system. Do you normalize those into global resource files, or do you have some sort of database layer where only one copy of each text used is generated. In our recent project, we used resource files which were generated from a database table that contained all the translations and the original, english version of the resource files.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Test. Generally speaking I will test in German, Polish, and an Asian language (Japanese, Chinese, Korean). German and Polish are wordy and nearly guaranteed to stretch text areas, Asian languages use an entirely different set of characters which tests your unicode support.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-3623434198939085155?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/3623434198939085155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=3623434198939085155' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/3623434198939085155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/3623434198939085155'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2010/04/quick-post-on-internationalization.html' title='A Quick Post on Internationalization'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-1936072620051019544</id><published>2009-07-15T19:55:00.001-07:00</published><updated>2009-07-15T20:02:06.475-07:00</updated><title type='text'>Apple Disables iTunes for Palm Pre</title><content type='html'>So I &lt;span _fcktemp="1"&gt;&lt;/span&gt;don't actually own a Pre - but I &lt;span _fcktemp="1"&gt;&lt;/span&gt;still think its fairly lame for Apple to produce a special release of iTunes whose only purpose is to disable Palm Pre syncing.&lt;br /&gt;&lt;p style="margin-right: 0px;" dir="ltr"&gt;&lt;a href="http://www.engadget.com/2009/07/15/itunes-8-2-1-brings-pres-music-syncing-capability-to-a-halt/"&gt;http://www.engadget.com/2009/07/15/itunes-8-2-1-brings-pres-music-syncing-capability-to-a-halt/&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin-right: 0px;" dir="ltr"&gt;(I’m not posting heavy content this week, due to vacation. This blog will be back next week with the continuation of my prior article.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-1936072620051019544?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/1936072620051019544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=1936072620051019544' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/1936072620051019544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/1936072620051019544'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2009/07/apple-disables-itunes-for-palm-pre.html' title='Apple Disables iTunes for Palm Pre'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-311149064444073053</id><published>2009-07-08T18:08:00.001-07:00</published><updated>2009-07-08T18:08:58.819-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='asp.net'/><category scheme='http://www.blogger.com/atom/ns#' term='web services'/><title type='text'>Using ASP.NET AJAX and Web Services to Show Progress on Long Tasks, part 1 – Breaking the Task Up</title><content type='html'>&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;One of the most powerful and compelling reasons to develop something as a application that runs natively on the user&amp;rsquo;s machine, as opposed to a web application, is responsiveness. The ability to give feedback about an action the user is taking, even if it requires a fair amount of computational time, and even to allow the user to cancel that action is a pretty useful ability. Even as javascript and XML-HTTP have enabled us to craft more responsive user interfaces to the user, the issue of responsiveness to run-longing actions is one that needs to be addressed. Fortunately, those same tools have given us the ability to bridge even that gap.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This series of articles will show how to use ASP.NET AJAX and jQuery to take a long-running task that can be broken up into elements and use that to provide the user with a dialog that provides them feedback on their progress. The particular example used will be running a large number of queries against some slow data source &amp;ndash; it is naturally preferable that a faster way of running the queries be found, and the reader is asked to please excuse me for solving this problem and not that one in this series.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;The Task&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In order to accomplish this, we need to be able to break the task up into chunks. Determining what these chunks are is a task in and of itself. The size of the chunks is important - you&amp;rsquo;ll be calling them multiple times, so you want to pick a size that is large enough to be meanginful and not be overwhelmed by the overhead of the web service calls you&amp;rsquo;ll be making, and that is small enough that the interface will still feel responsive. You&amp;rsquo;ll also need to build a way to determine what the total number of chunks to return are.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once this is done, wrap this logic in your business layer in whatever way you want to do. In this example, we&amp;rsquo;ll assume that there is a class like the following:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;public interface BusinessObject&lt;br /&gt;{&lt;br /&gt;    // Returns the total number of operations required to &lt;br /&gt;    // finish this task.&lt;br /&gt;    public int GetNumberOfOperations();&lt;br /&gt;&lt;br /&gt;    // Performs some of the operations against a set of &lt;br /&gt;    // operations that may be empty. If nothing was done, &lt;br /&gt;    // return false. Otherwise, return true.&lt;br /&gt;    public bool PerformOperation();&lt;br /&gt;}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;This code is an example interface, of course, your business object should more closely resemble your model.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Web Service&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Having broken up your task, you&amp;rsquo;ll need to expose those two methods of the interface as a web service. One of the beautifal things about ASP.NET AJAX is that you can easily access web services that have been decorated with the special System.Web.Script.Services.ScriptService attribute through javascript, on the client. I&amp;rsquo;ll give more details on how to do that in the next article. For the meantime, you&amp;rsquo;re web session will look something like the following:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;using System;&lt;br /&gt;using System.Collections;&lt;br /&gt;using System.ComponentModel;&lt;br /&gt;using System.Data;&lt;br /&gt;using System.Diagnostics;&lt;br /&gt;using System.Web;&lt;br /&gt;using System.Web.Services;&lt;br /&gt;&lt;br /&gt;[WebService(Namespace = "http://tempuri.org/")]&lt;br /&gt;[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]&lt;br /&gt;[System.Web.Script.Services.ScriptService]&lt;br /&gt;public class TaskService : System.Web.Services.WebService &lt;br /&gt;{&lt;br /&gt;    public TaskService()&lt;br /&gt;    {&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [WebMethod(EnableSession=true)]&lt;br /&gt;    public int GetNumberOfSteps()&lt;br /&gt;    {&lt;br /&gt;        IBusinessObject obj = (IBusinessObject)Session["businessObject"];&lt;br /&gt;        return obj.GetNumberOfOperations();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    [WebMethod(EnableSession = true)]&lt;br /&gt;    public bool PerformOperation()&lt;br /&gt;    {&lt;br /&gt;        IBusinessObject obj = (IBusinessObject)Session["businessObject"];&lt;br /&gt;        return obj.PerformOperation();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;You&amp;rsquo;ll note that each of the methods above are decorated with EnableSession=true. This gives the service access to the same Session state as the rest of your ASP.NET application. In this case, I&amp;rsquo;m pretending an instance IBusinessObject has been stuffed into the session. In a real world application, you might want to make sure the current user actually has permissions to do the bulky task that they&amp;rsquo;re about to do.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Caveats&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The caveats about this process are, actually, enough to make this only useful in some pretty rarified situations. For the one thing, you don&amp;rsquo;t actually generally want to do long-running tasks on your web server. Particularly if those long-running tasks are exposed to the outside world and might be called on by every person in the internet. Remember that these tasks, when run, are going to take up one of the worker threads of your ASP.NET pool and that there are a limited number of these. Thus, it is easily possible to take this to a level where your server will collapse underneath the load.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In the end, you might well be better served moving the operation off to another server (perhaps the database) as a scheduled task. You could then use this trick to refresh the status of that operation, instead.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Since I&amp;rsquo;m trying to solely concentrate on the trick in this series, I&amp;rsquo;m not going to go into that. But keep in mind the business object could easily get a StartOperation method to add the operation to the queue and a CheckOperation method to see how the operation is going.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I hope this at least whets your appetite. In the next article, I&amp;rsquo;ll show how to implement this into a web page using javascript and jQuery.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-311149064444073053?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/311149064444073053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=311149064444073053' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/311149064444073053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/311149064444073053'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2009/07/using-aspnet-ajax-and-web-services-to.html' title='Using ASP.NET AJAX and Web Services to Show Progress on Long Tasks, part 1 – Breaking the Task Up'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-7326914559336485982</id><published>2009-07-02T11:26:00.001-07:00</published><updated>2009-07-02T11:26:09.384-07:00</updated><title type='text'>Posting Schedule</title><content type='html'>&lt;p&gt;One thing I&amp;rsquo;ve been trying to do with this blog is to use it more frequently. This particular blog has always been meant as a means for discussing my thoughts on software development topics and to show what I&amp;rsquo;ve been doing in terms of actually writing code. So in many ways, I&amp;rsquo;m attempting to use this blog to serve as a portfolio of sorts of the work I&amp;rsquo;ve done and my thinking regarding that work. There&amp;rsquo;s a longer entry about software craftsmanship and maintaining a portfolio that may come in the future.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In the meantime, however, I&amp;rsquo;ve decided I want to keep posting to this blog on a fairly regular basis. In this case, I thought I would start out with weekly entries. As it happens, the next six entries I&amp;rsquo;d like to add to this blog have already been conceived of based on work I&amp;rsquo;m currently doing or work I will soon be doing. So, here&amp;rsquo;s the schedule I&amp;rsquo;m going to try to keep to. Note that all dates are Wednesdays &amp;ndash; this seems to currently work as a good day to write an entry, but I reserve the right to post at any time during the weke.&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;7/8/2009 &amp;ndash; Using ASP.NET AJAX and Web Services to Show Progress on Long Tasks, part 1 &amp;ndash; Breaking the Task Up&lt;/li&gt;&lt;br /&gt;&lt;li&gt;7/15/2009 - &lt;em&gt;No Entry. This is the week of my birthday. I will, further, be attending a LARP convention for the Camarilla and running a game there.&lt;/em&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;7/22/2009&lt;em&gt; &amp;ndash; &lt;/em&gt;Using ASP.NET AJAX and Web Services to Show Progress on Long Tasks, part 2 &amp;ndash; Displaying the Progress in the User Interface&lt;/li&gt;&lt;br /&gt;&lt;li&gt;7/29/2009 &amp;ndash; Authentication and Authorization using SAML, part 1 &amp;ndash; The Overall Process&lt;/li&gt;&lt;br /&gt;&lt;li&gt;8/5/2009 - Authentication and Authorization using SAML, part 2 &amp;ndash; The SAML Document&lt;/li&gt;&lt;br /&gt;&lt;li&gt;8/12/2009 &amp;ndash; Authentication and Authorization using SAML, part 3 - Dealing with X.509 Certificates&lt;/li&gt;&lt;br /&gt;&lt;li&gt;8/19/2009 &amp;ndash; Authentication and Authorization using SAML, part 4 &amp;ndash; Putting It All Together in Code&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;After that, I&amp;rsquo;ll figure out what the next set of entries will be. Hopefully there&amp;rsquo;s stuff in there that people will find interesting to read.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Thanks,&lt;/p&gt;&lt;br /&gt;&lt;p&gt;John&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-7326914559336485982?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/7326914559336485982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=7326914559336485982' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7326914559336485982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7326914559336485982'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2009/07/posting-schedule.html' title='Posting Schedule'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-6732795079832398054</id><published>2009-07-01T16:35:00.001-07:00</published><updated>2009-07-01T16:52:25.953-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery javascript'/><title type='text'>jQuery</title><content type='html'>&lt;span xmlns=''&gt;&lt;p&gt;One of the biggest challenges of developing for web applications has always been cross-browser javascript support. Different browsers would or would not support pieces of the DOM object model, or would implement them in different ways. The issues have been getting gradually better since the Netscape/Microsoft war ended and relevant W3C specifications came out. There are still, though, issues between Internet Explorer and Mozilla (and, presumably, other browsers). One example of this is in the way the browser divides up HTML content into the ChildNodes collection. Any element of the DOM that can support children supports the ChildNodes collection, which is meant to be a way to get at the children of a particular node.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The problem, though, is that Mozilla and Internet Explorer divide up content differently. The issue basically comes down to whitespace – Mozilla divides whitespace used in the markup into separate children, while Internet Explorer ignores it. I make no attempt to figure out which is, standards-wise, the correct approach. I will say that it seems more right to ignore whitespace, since when rendering HTML whitespace is pretty much ignored. And that treating it as significant seems to encourage compressed, poorly laid out code.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;That said – I'm not in charge of the design of Mozilla's javascript rendering engine (and no, I'm not going to submit patches to an open source project just because I object to the way whitespace is dealt with. I don't have &lt;em&gt;that&lt;/em&gt; much free time, thanks. And besides, the version which treats whitespace as significant is still out there in the wild and needs to be dealt with. In the past this has led to some complex javascript code. For instance, the following code block. In this case, I'm taking a collection of DIVs, each of which contain a SELECT and a TEXTBOX and pulling out the entered values. The values are then thrown to a web service, exposed through ASP.NET AJAX. Due to the fact that this DIV is cloned repeatedly on the page through user action, assigning ids to the nodes was not a particularly feasible option.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;    &lt;br /&gt;var newItemFormContainer = $get("newItemForm");&lt;br /&gt;if (Sys.Browser.name == "Microsoft Internet Explorer") {&lt;br /&gt;    var newItemCount = &lt;br /&gt;        newItemFormContainer.childNodes.length;&lt;br /&gt;} else { &lt;br /&gt;    var newItemCount = &lt;br /&gt;        newItemFormContainer.childNodes.length - 1;&lt;br /&gt;}&lt;br /&gt;for (var i = 0; i &lt; newItemCount; i++) {&lt;br /&gt;    var itemText;&lt;br /&gt;    var scaleId;&lt;br /&gt;    if (Sys.Browser.name == "Microsoft Internet Explorer") {&lt;br /&gt;        itemText = &lt;br /&gt;            newItemFormContainer.childNodes[i].childNodes[0].&lt;br /&gt;            childNodes[1].value;&lt;br /&gt;        scaleId = &lt;br /&gt;            newItemFormContainer.childNodes[i].childNodes[4].&lt;br /&gt;            childNodes[1].value;&lt;br /&gt;    } else {&lt;br /&gt;        itemText = &lt;br /&gt;            newItemFormContainer.childNodes[i + 1].childNodes[0].&lt;br /&gt;            childNodes[2].value;&lt;br /&gt;        scaleId = &lt;br /&gt;            newItemFormContainer.childNodes[i + 1].childNodes[8].&lt;br /&gt;            childNodes[3].value;&lt;br /&gt;    }&lt;br /&gt;    if (scaleId == "") {&lt;br /&gt;        scaleId = null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (itemText != null &amp;&amp; itemText.trim() != "") {&lt;br /&gt;        GeneseeSurvey.SurveyDesign.ManageSurveysService.&lt;br /&gt;            CreateItemAndAddToSurvey(itemText, scaleId, success, &lt;br /&gt;            surveyServiceCallFailure, i);    &lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;This is not particular a great solution. For one thing, it requires a conditional statement that is dependent on what browser the user is using. This can get messy and hard to maintain if there are other browsers with incompatibilities.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I would argue, though, that this code is bad from a design standpoint. Dipping into the childNodes collections as I was doing in the above example requires that you have extensive knowledge of the way the HTML page lays out user interface of the form DIVs. If that user interface is changed without the javascript being changed, the code will cease to function. Furthermore, the code is hard to follow – human eyes glaze over when they see you getting the second element of the zeroth element of the ith element. It would be very difficult to step back through the code and figure out what the developer was trying to do. So, refactoring this code would be a great thing. The problem being, though, that javascript will make it difficult to do this in a better fashion.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Lucky for us, a lot of other developers have had this problem in the past. And as developers are wont to do when they have a problem, a group of developers solved the problem by adding a new layer of abstraction. In this case they solved the issue by inventing &lt;a href='http://www.jquery.com'&gt;jQuery&lt;/a&gt;. jQuery is a javascript library which adds a powerful set of querying capabilities which enable you to get at elements in an entirely new fashion. It also provides a powerful set of animation capabilities which enable you to make better user interfaces. That's for another blog entry, however.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;With jQuery, you now have the capability to take an element of the DOM (or the entire document) and conduct a search based on a class name, an element name, an element id, or by the relationship of the target node to the current node. You are, further, not limited to creating one-level searches. For example, if you have a textarea underneath a div that has a class of 'textareacontainer', which is underneath a div which is the first child of the current div (which we'll assume has an id of 'firstDiv'), you can find it with the following piece of code:&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;span style='font-family:Courier New; font-size:10pt'&gt;&lt;span style='color:blue'&gt;var&lt;/span&gt; textarea = $(&lt;span style='color:#a31515'&gt;"#firstDiv div:firstChild .textareacontainer textarea:first"&lt;/span&gt;);&lt;/span&gt;&lt;br /&gt;   &lt;/p&gt;&lt;p&gt;This will return a collection that has a single element. One gotcha of jQuery is that this will not be a collection of DOM objections. jQuery wraps all search results in its own object, which lets you then do further jQuery queries against the results. jQuery does provide a host of functions to manipulate common elements of the underlying DOM object. I could get the value of the textarea with &lt;a href='http://docs.jquery.com/Attributes/val'&gt;textarea.val()&lt;/a&gt;, for instance. If I needed the DOM object, though, I could use &lt;a href='http://docs.jquery.com/Core/get'&gt;textarea.get(0)&lt;/a&gt; and then do what I have to do.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Another thing that jQuery provides as part of its wrapper around DOM objects is the ability to iterate through the collection and carry out user code. This is provided through the each method, which takes as an argument a callback function which is executed once for each DOM element in the collection. Given this information, the following is the refactoring of the first javascript code block I had.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;var newItemForms = $("#newItemForm &gt; div");&lt;br /&gt;newItemCount = newItemForms.length&lt;br /&gt;newItemForms.each(function(i) {&lt;br /&gt;    var itemText = $("textarea:first", this).val();&lt;br /&gt;    var scaleId = $(".selectScaleDropdown:first", this).val();&lt;br /&gt;&lt;br /&gt;    if (scaleId == "") {&lt;br /&gt;        scaleId = null;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    if (itemText != null &amp;&amp; itemText.trim() != "") {&lt;br /&gt;        GeneseeSurvey.SurveyDesign.ManageSurveysService.&lt;br /&gt;            CreateItemAndAddToSurvey(itemText, scaleId, success, &lt;br /&gt;            surveyServiceCallFailure, i);&lt;br /&gt;    }&lt;br /&gt;});&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;I maintain that this code is significantly easier to read and much, much easier to maintain than the prior code.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;It should be noted at this point that Microsoft has committed themselves to delivering jQuery with Visual Studio. If you are developing with Visual Studio 2008 SP1, then you may already have access to it – I'm not, to be honest, entirely sure (see below). They have also delivered intellisense around it, though I haven't worked with that yet. For more information, see &lt;a href='http://weblogs.asp.net/scottgu/archive/2008/09/28/jquery-and-microsoft.aspx'&gt;Scott Guthrie's announcement&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;If you are developing with Telerik, they have also begun shipping jQuery with their components. This is how I ended up getting jQuery into my web application, since we make fairly heavy use of the Telerik 2009 Q1 controls. It does, require a bit of a patch to get the $() functionality to work. See &lt;a href='http://blogs.telerik.com/atanaskorchev/posts/08-11-06/asp_net_ajax_controls_and_jquery.aspx'&gt;Atanas Korchev's blog post regarding this&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I fully intend to refactor a good portion of our javascript code to use jQuery. This will take some time since I need to develop new features as well, but I think the savings in the end will more than make up for the cost. Naturally, newly developed javascript code will make use of jQuery.&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-6732795079832398054?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/6732795079832398054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=6732795079832398054' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6732795079832398054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6732795079832398054'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2009/07/jquery.html' title='jQuery'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-6279916441083678091</id><published>2009-06-29T17:40:00.001-07:00</published><updated>2009-06-29T17:54:17.189-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linq-to-sql'/><title type='text'>LINQ-to-SQL &amp; Side-Effects</title><content type='html'>&lt;p&gt;So the project I'm currently working on relies fairly heavily on LINQ-to-SQL. Thus far it is has been an absolutely delightful experience, though one in which I have spent quite a lot of time passing DataContext derivatives into my business layer objects. I've been doing this because I was under the impression that the only way to register an object to be posted back to the database or removed from the database is through the InsertOnSubmit, InsertAllOnSubmit, DeleteOnSubmit, and DeleteAllOnSubmit methods on the DataContext object. &lt;/p&gt;  &lt;p&gt;As it turns out, this is not entirely true. I discovered this when I attempted to do a copy of an object which has a property that points to another LINQ-to-SQL managed object. One possibility with this code is that the item being used as a conditional for the branch may not exist. In this case, we don't want to copy the Branching object.&lt;/p&gt;  &lt;p&gt;The code, thus, was this:&lt;/p&gt;  &lt;pre&gt;&lt;code&gt;&lt;br /&gt;Public Function CreateCopy(ByVal db As SteamDatabaseDataContext, _&lt;br /&gt;    ByVal surveyItemMapping As Dictionary(Of Integer, SurveyItem)) _&lt;br /&gt;    As Branching&lt;br /&gt;&lt;br /&gt;    Dim copy As New Branching()&lt;br /&gt;    copy.ExcludeFlag = ExcludeFlag&lt;br /&gt;    copy.ParameterValue = ParameterValue&lt;br /&gt;   &lt;br /&gt;    If (surveyItemMapping.ContainsKey(SurveyItemID)) Then&lt;br /&gt;         copy.SurveyItem = surveyItemMapping(SurveyItemID) ' BAD!&lt;br /&gt;    Else&lt;br /&gt;         Throw New ArgumentException(String.Format("The survey item that branch {0} is" + _&lt;br /&gt;              "based on does not exist within the surveyItemMapping parameter.", BranchID))&lt;br /&gt;    End If&lt;br /&gt;&lt;br /&gt;    copy.ParamType = ParamType&lt;br /&gt;    If (ParamType = 1) Then&lt;br /&gt;         If (surveyItemMapping.ContainsKey(Convert.ToInt32(Parameter))) Then&lt;br /&gt;              copy.Parameter = surveyItemMapping(Convert.ToInt32(Parameter)).SurveyItemID&lt;br /&gt;         Else&lt;br /&gt;              Return Nothing&lt;br /&gt;         End If&lt;br /&gt;    Else&lt;br /&gt;         copy.Parameter = Parameter&lt;br /&gt;    End If&lt;br /&gt;&lt;br /&gt;    db.Branchings.InsertOnSubmit(copy)&lt;br /&gt;    Return copy&lt;br /&gt;End Function&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Thus, if the branch is not valid, it should return nothing and not reach the db.Branchings.InsertOnSubmit(copy) call. When I executed this against a survey with a branch, though, it became quickly apparent that the code was, in fact, registering the new Branch to be inserted into the database. This actually caused a crash, since Parameter would be null and the database schema is set to not allow this.&lt;/p&gt;&lt;p&gt;It turns out, that the problem is the assignment to the SurveyItem property above (see comment). Setting the SurveyItem property of the new Branching object immediately marks the object as to be inserted. When we change the code to the following:&lt;/p&gt;&lt;blockquote&gt;copy.SurveyItemID = surveyItemMapping(SurveyItemID).SurveyItemID&lt;br /&gt;&lt;/blockquote&gt;&lt;p&gt;The code works find and the Branching object is abandoned.&lt;/p&gt;&lt;p&gt;Thus, it appears that a side-effect of assinging such a property is that the object is registered for an Insert. I wasn’t aware of this side-effect and it cost me a lot of debugging time. This is definitely an object lesson in understanding the side effects of property sets. Its also a lesson to me to, when designing my own code, &lt;i&gt;minimize&lt;/i&gt; those side effects.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-6279916441083678091?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/6279916441083678091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=6279916441083678091' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6279916441083678091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6279916441083678091'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2009/06/linq-to-sql-side-effects_29.html' title='LINQ-to-SQL &amp;amp; Side-Effects'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-6354148341593317316</id><published>2009-06-18T09:25:00.000-07:00</published><updated>2009-06-18T09:27:12.102-07:00</updated><title type='text'>jQuery</title><content type='html'>So I've been working with jQuery for the past few weeks - this is an open-source javascript library that was included with the Telerik controls we purchased. It is also, I believe, included with Visual Studio, or will be in a future release. Let me tell you, it makes things a lot easier. One example - moving table rows up or down in the table. This is actually quite difficult to do in Firefox (IE provides a non-standard method to do it for you) - the only way to do it that I've found is to clone the affected table row, remove the old one from the table and add the new one. I hate cloning objects. I'm not going to include the code on how to do this, because I didn't write it. But here's a link - http://www.w3hobbyist.com/web-designing/moving-table-rows-up-and-down-with-javascript/&lt;br /&gt;&lt;br /&gt;Once I figured out that this was going to be hard to do, I thought I would try to do it in jQuery. I hit the documentation site for jQuery (http://docs.jquery.com/) and found the answer really quickly. In the examples below, pretend that tableRow is the row of the table that needs to be moved.&lt;br /&gt;&lt;br /&gt;Moving an item down in the table:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;     $(targetRow).insertAfter($(targetRow).next())&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Moving an item up in the table:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    if (targetRow.rowIndex &gt; 1) {&lt;br /&gt;        $(targetRow).insertBefore($(targetRow).prev());&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;That is,actually, pretty amazing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-6354148341593317316?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/6354148341593317316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=6354148341593317316' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6354148341593317316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6354148341593317316'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2009/06/jquery.html' title='jQuery'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-6584694135628108709</id><published>2009-02-23T12:24:00.000-08:00</published><updated>2009-02-23T12:32:16.995-08:00</updated><title type='text'>VB.NET XML Literals</title><content type='html'>So for our current project, we're working in VB.NET 9.0 - I won't go into our methodology or reasons for switching. That said, I've found that I'm not a huge fan of the language so far. It literally feels more difficult to express myself in than C#. While I acknowledge that this could well be because of the learning curve any new language involves, I find myself yearning for semi-colons and curly braces.&lt;br /&gt;&lt;br /&gt;That said - the single thing I've found so far that VB.NET does better than C# is building web server controls in ASP.NET. This is because of the feature that, when I first read about it, I shunned - XML Literals. What this is is the ability to express XML documents or fragments in VB.NET directly, without having to go through the XML object models that the .NET framework provides.&lt;br /&gt;&lt;br /&gt;I'll admit - when I first saw this feature, I chuckled a little to myself and then moved on. We had, after all, done this before - ASP was all about this sort of embedded code. Also, I couldn't see why I would want to create XML documents like that in the middle of my code. And, in most scenarios, I'm still reasonably sure I wouldn't. That said, why don't you tell me what you think the more readable code is:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)&lt;br /&gt;        Dim itemContainer = New HtmlGenericControl("div")&lt;br /&gt;        itemContainer.Attributes.Add("class", "radioButtonItemControl")&lt;br /&gt;        itemContainer.Attributes.Add("id", String.Format("item_{0}", Me.ItemId))&lt;br /&gt;&lt;br /&gt;        Dim textContainer = New HtmlGenericControl("div")&lt;br /&gt;        textContainer.Attributes.Add("class", "radioButtonItemControlText")&lt;br /&gt;        itemContainer.Controls.Add(textContainer)&lt;br /&gt;        If (FlagBlankItem And Not HasValidUserResponse) Then&lt;br /&gt;            Dim flagSpan = New HtmlGenericControl("span")&lt;br /&gt;            textContainer.Controls.Add(flagSpan)&lt;br /&gt;            flagSpan.Attributes.Add("class", "error")&lt;br /&gt;            flagSpan.InnerHtml = "*"&lt;br /&gt;        End If&lt;br /&gt;        textContainer.Controls.Add(New HtmlGenericControl("span") With {.InnerText = Label})&lt;br /&gt;        textContainer.Controls.Add(New HtmlGenericControl("span") With {.InnerText = Text})&lt;br /&gt;&lt;br /&gt;        ' Figure out if we need to set one of the scales as checked.&lt;br /&gt;        Dim resp As Integer&lt;br /&gt;        If (UserResponses.Count &gt; 0) Then&lt;br /&gt;            Int32.TryParse(UserResponses(0), resp)&lt;br /&gt;        End If&lt;br /&gt;&lt;br /&gt;        ' Write out the scale&lt;br /&gt;        Dim scaleContainer = New HtmlGenericControl("div")&lt;br /&gt;        scaleContainer.Attributes.Add("class", "radioButtonItemControlScale")&lt;br /&gt;        itemContainer.Controls.Add(scaleContainer)&lt;br /&gt;        Dim idx As Integer = 1&lt;br /&gt;        For Each s As SerializedScale In Scale&lt;br /&gt;            Dim scaleItem = New HtmlGenericControl("div")&lt;br /&gt;            scaleContainer.Controls.Add(scaleItem)&lt;br /&gt;            Dim scaleRadioButton = New HtmlInputRadioButton() With {.Name = ID, .ID = String.Format("{0}_{1}", UniqueID, idx), .Value = s.Value.ToString(), .Checked = (resp = s.Value)}&lt;br /&gt;            scaleRadioButton.Attributes.Add("onclick", "doRadioButtonClick(this);")&lt;br /&gt;            scaleItem.Controls.Add(scaleRadioButton)&lt;br /&gt;            Dim scaleLabel = New HtmlGenericControl("label")&lt;br /&gt;            scaleItem.Controls.Add(scaleLabel)&lt;br /&gt;            scaleLabel.Attributes.Add("for", String.Format("{0}_{1}", UniqueID.Replace("$", "_"), idx))&lt;br /&gt;            scaleLabel.InnerText = s.Text&lt;br /&gt;&lt;br /&gt;            idx = idx + 1&lt;br /&gt;        Next&lt;br /&gt;&lt;br /&gt;        itemContainer.RenderControl(writer)&lt;br /&gt;    End Sub&lt;br /&gt;&lt;br /&gt;vs&lt;br /&gt;&lt;br /&gt;    Protected Overrides Sub RenderContents(ByVal writer As HtmlTextWriter)&lt;br /&gt;        Dim controlXhtml As XElement = _&lt;br /&gt;        &amp;lt;div class="hierarchyItemControl" id=&amp;lt;%= String.Format("item_{0}", ItemId) %&amp;gt;&amp;gt;&lt;br /&gt;            &amp;lt;div class="hierarchyItemControlText"&amp;gt;&lt;br /&gt;                &amp;lt;span&amp;gt;&amp;lt;%= Label %&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;                &amp;lt;span&amp;gt;&amp;lt;%= Text %&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;            &amp;lt;/div&amp;gt;&lt;br /&gt;            &amp;lt;%= GetScaleXHtml() %&amp;gt;&lt;br /&gt;        &amp;lt;/div&amp;gt;&lt;br /&gt;        writer.Write(controlXhtml)&lt;br /&gt;    End Sub&lt;br /&gt;&lt;br /&gt;    Private Function GetScaleXHtml() As XElement&lt;br /&gt;        Dim scaleDiv As XElement = _&lt;br /&gt;            &amp;lt;div class="hierarchyItemControlScale"&amp;gt;&lt;br /&gt;                &amp;lt;%= From s In Scale _&lt;br /&gt;                    Select &amp;lt;div&amp;gt;&lt;br /&gt;                               &amp;lt;input type="radio" id=&amp;lt;%= String.Format("{0}_{1}", UniqueID, s.Value) %&amp;gt; name=&amp;lt;%= ID %&amp;gt; value=&amp;lt;%= s.Value %&amp;gt;/&amp;gt;&lt;br /&gt;                               &amp;lt;label for=&amp;lt;%= String.Format("{0}_{1}", UniqueID, s.Value) %&amp;gt;&amp;gt;&amp;lt;%= s.Text %&amp;gt;&amp;lt;/label&amp;gt;&lt;br /&gt;                           &amp;lt;/div&amp;gt; %&amp;gt;&lt;br /&gt;            &amp;lt;/div&amp;gt;&lt;br /&gt;&lt;br /&gt;        Return scaleDiv&lt;br /&gt;    End Function&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;(Note that these two controls are doing two slightly different things, but they are close enough to illustrate my point)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-6584694135628108709?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/6584694135628108709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=6584694135628108709' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6584694135628108709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/6584694135628108709'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2009/02/vbnet-xml-literals.html' title='VB.NET XML Literals'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-7369239016567249878</id><published>2008-11-13T09:01:00.000-08:00</published><updated>2008-11-13T09:02:01.962-08:00</updated><title type='text'>LINQ-to-SQL Issue</title><content type='html'>So I've been working with LINQ-to-SQL for weeks now. And, as I've been saying all along, I've found it a perfectly delightful process that has really increased my productivity. Which isn't to say that I don't have any problems with it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;At the moment, for instance, I'm running head-long into a wall. I have several defined Entity classes (which map to database tables on a one-to-one basis). Since the LINQ designer adds these as partial classes, that leaves me free to add business logic to these entity classes.&lt;br /&gt;&lt;br /&gt;Which is all well and good until you realize the following - to do pretty much anything to the entity classes, you're likely going to need to instigate database changes. If you want to add something to a list that is stored by the entity class, for instance, you'll need to be sure that that new object (which is likely in itself an entity class) is persisted to the database. If you make changes within your method, you'll want to make sure those changes are persisted to the database.&lt;br /&gt;&lt;br /&gt;The LINQ-to-SQL way to persist changes is a derivative of System.Data.Linq.DataContext. It provides a method (SubmitChanges) which can be used to persist any changes made to loaded Entity classes to the database. It also provides access to a series of Table(of TEntity) properties, each one of which represents a type of Entity class tracked by that DataContext derivative. You use these to register new entities to be persisted (InsertOnSubmit, InsertAllOnSubmit) or to remove entities that are no longer needed (DeleteOnSubmit, DeleteAllOnSubmit).&lt;br /&gt;&lt;br /&gt;In my opinion, the methods that are making these changes should be responsible for making sure those changes persist. Certainly, the code calling these methods can't possibly know about new entities that may have been added by the method.&lt;br /&gt;&lt;br /&gt;The problem, though, is that there is no way to get to the DataContext object that created an Entity from within the scope of that Entity. No reference to the creating DataContext is held within the entity. There are no events or virtual methods that can be implemented to capture when an entity is being created, and stick a reference to the DataContext into the entity.&lt;br /&gt;&lt;br /&gt;This means that if I want to include business logic methods inside my entities, I have to include a reference to the DataContext derivative that created the entity in its parameter list. And there's no way for me to actually check and make sure that the entity is actually being tracked by the DataContext derivative passed in - which could lead to some odd bugs down the line.&lt;br /&gt;&lt;br /&gt;The other alternative is to put all my business logic in the DataContext derivative - which strikes me as bad because then I'm separating the functionality from the data the functionality operates against.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Bleh. In the end, I'll just end up adding a DataContext derivative parameter. But it annoys me that I have to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-7369239016567249878?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/7369239016567249878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=7369239016567249878' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7369239016567249878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7369239016567249878'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2008/11/linq-to-sql-issue.html' title='LINQ-to-SQL Issue'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-8409140565099824398</id><published>2008-10-03T07:23:00.001-07:00</published><updated>2008-10-03T07:23:50.914-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='linq-to-sql'/><title type='text'>Why I Love LINQ-to-SQL</title><content type='html'>The task: given a Scale which may contain one or many ScaleTexts and are thus reflected in the SQL database as a Scales and ScaleTexts table with ScaleTexts having a ScaleId foreign key reference, create the Scale in the database.&lt;br /&gt;&lt;br /&gt;The old method: Generate and execute SQL to create a scale in the database and save its id. Methodically go through each of the ScaleTexts and generate and execute SQL to create a ScaleText in the database.&lt;br /&gt;&lt;br /&gt;The LINQ method (given items as an IEnumerable(of string) that contains the scale texts for the new scale, and Db represents the DataContext derived object for the project):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Dim scale = New Scale() With {.Name = String.Format("{0} - {1}", items.First(), items.Last())}&lt;br /&gt;Dim englishId = GetEnglishLanguageId()&lt;br /&gt;For i As Integer = 0 To items.Count() - 1&lt;br /&gt;    scale.ScaleTexts.Add(New ScaleText() With {.ScaleLabel = items.ElementAt(i), _ &lt;br /&gt;                                               .ScaleOrder = i + 1, _ &lt;br /&gt;                                               .ScaleValue = i + 1, _ &lt;br /&gt;                                               .LangID = englishId})&lt;br /&gt;Next&lt;br /&gt;&lt;br /&gt;Db.ScaleTexts.InsertAllOnSubmit(scale.ScaleTexts)&lt;br /&gt;Db.Scales.InsertOnSubmit(scale)&lt;br /&gt;Db.SubmitChanges()&lt;br /&gt;&lt;br /&gt;Return scale&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To me, this is so much better. I'm not having to move my head from writing VB.NET code to writing Transact-SQL, I can stay within the object model I've been working with all along and just expect the DataContext object to handle actually updating the database. All of my code is compile-time checked, rather having to wait until run-time to find out if I messed up a SQL statement.&lt;br /&gt;&lt;br /&gt;Yum.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-8409140565099824398?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/8409140565099824398/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=8409140565099824398' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/8409140565099824398'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/8409140565099824398'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2008/10/why-i-love-linq-to-sql.html' title='Why I Love LINQ-to-SQL'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-5350539080005694822</id><published>2008-10-03T07:21:00.000-07:00</published><updated>2008-10-03T07:22:33.820-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>Case Sensitive SQL</title><content type='html'>&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;Huh.&lt;br /&gt;&lt;br /&gt;Never thought this would be the case, but it looks like there is a case where Transact-SQL is case-sensitive. &lt;br /&gt;&lt;br /&gt;Consider the following example, pulled from &lt;A href="http://netbard.livejournal.com/206329.html"&gt;http://netbard.livejournal.com/206329.html&lt;/A&gt;:&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;P dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;FONT face=Courier&gt;select col.value('@ID'&lt;/FONT&gt;&lt;FONT face=Courier&gt;, 'nvarchar(max)')&lt;br /&gt;from XmlImport (NOLOCK)&lt;br /&gt;cross apply ImportDocument.nodes('/Project/Text') as tab(col) &lt;br /&gt;where XmlImportId = 21&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;When run, this generates a list of ID attributes in the XML document - just like you would expect.&lt;br /&gt;&lt;br /&gt;Now consider this statement (I'll mark the only change in red):&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;P&gt;&lt;FONT face=Courier&gt;select col.value(&lt;/FONT&gt;&lt;FONT face=Courier&gt;'@ID'&lt;/FONT&gt;&lt;FONT face=Courier&gt;, 'nvarchar(max)')&lt;br /&gt;from XmlImport (NOLOCK)&lt;br /&gt;cross apply ImportDocument.&lt;FONT color=#ff0000&gt;Nodes&lt;/FONT&gt;('/Project/Text') as tab(col) &lt;br /&gt;where XmlImportId = 21&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;P dir=ltr&gt;Now Transact-SQL is not case-sensitive. This should work as well as the first version. Instead, you get the following error:&lt;/P&gt;&lt;P&gt;&lt;/P&gt;&lt;BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px"&gt;&lt;P dir=ltr&gt;&lt;FONT face=Courier&gt;Table-valued function 'Nodes' cannot have a column alias.&lt;/FONT&gt;&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;P dir=ltr&gt;If you fix the case of the 'Nodes' section, it works fine.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This is, in my opinion, very lame. A language shouldn't be part case sensitive, part case insensitive. Bad! Pick a side of the road, and stay on it!&lt;br /&gt;&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-5350539080005694822?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/5350539080005694822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=5350539080005694822' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/5350539080005694822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/5350539080005694822'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2008/10/case-sensitive-sql.html' title='Case Sensitive SQL'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-4817835663032394111</id><published>2008-10-03T07:20:00.000-07:00</published><updated>2008-10-03T07:21:46.088-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql server'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><title type='text'>Querying XML in a Tabular Format</title><content type='html'>So, SQL Server 2005 provides some remarkable access to XML documents stored within XML column types of a table. The most interesting that I've found so far is that you can take the XML document stored in a column and run a query against that that will return it in tabular format. You can then use that and join it to other tables in order to make your updates.&lt;br /&gt;&lt;br /&gt;To do this, you need to figure out the XQuery to get a rowset of nodes that you want to query against. Pretending that we have XML document:&lt;br /&gt;&lt;br /&gt;&lt;span style="margin-right: 20px; font-family: courier;"&gt;&lt;br /&gt; &amp;lt;Projects&amp;gt;&lt;br /&gt;   &amp;lt;Project&amp;gt;&lt;br /&gt;     &amp;lt;Text ID="116" TypeID="2" Request="DoNotChange" Response=""&amp;gt;&lt;br /&gt;         &amp;lt;en_us&amp;gt;Alpha&amp;lt;/en_us&amp;gt;&lt;br /&gt;     &amp;lt;/Text&amp;gt;&lt;br /&gt;     &amp;lt;Text ID="117" TypeID="2" Request="DoNotChange" Response=""&amp;gt;&lt;br /&gt;       &amp;lt;en_us&amp;gt;Beta&amp;lt;/en_us&amp;gt;&lt;br /&gt;     &amp;lt;/Text&amp;gt;&lt;br /&gt; &amp;lt;/Projects&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A possible XQuery to get all the Text nodes might be '/Projects/Project/Text'. You then need to cross your original SQL query that will get the xml document in order to get the list of all Text. So:&lt;br /&gt;&lt;br /&gt;&lt;span style="margin-right: 10px; font-family: courier;"&gt;&lt;br /&gt; SELECT * FROM XmlImport (NOLOCK) &lt;b&gt;CROSS APPLY ImportDocument.nodes('/Project/Project/Text') as tab(col)&lt;/b&gt; WHERE XmlImportId = 1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've bolded the applicable part of this query. You are applying the results of this query to your result set as column 'col' - fully delineated I believed its tab.col.&lt;br /&gt;&lt;br /&gt;The above SQL statement will not work, however. If you run it you will get an error 'The column 'col' that was returned from the nodes() method cannot be used directly. It can only be used with one of the four xml data type methods, exist(), nodes(), query(), and value(), or in IS NULL and IS NOT NULL checks.' This because SQL needs to know what you want it to return; it has no way of representing xml data in a tabular format otherwise. In order to do that, you need to include XQueries in your select statement to declare what you want to get back. To whit:&lt;br /&gt;&lt;br /&gt;&lt;span style="margin-right: 10px; font-family: courier;"&gt;&lt;br /&gt; SELECT col.value('en_us[1]') as 'Text' FROM XmlImport (NOLOCK) CROSS APPLY ImportDocument.nodes('/Project/Project/Text') as tab(col) WHERE XmlImportId = 1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This will return the following, based on our XML document from above:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Text&lt;/b&gt;&lt;br /&gt;Alpha&lt;br /&gt;Beta&lt;br /&gt;&lt;br /&gt;You can, of course, join that statement with other SQL statements to produce views, updates, or whatever.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-4817835663032394111?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/4817835663032394111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=4817835663032394111' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/4817835663032394111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/4817835663032394111'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2008/10/querying-xml-in-tabular-format.html' title='Querying XML in a Tabular Format'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-7050289660205715267</id><published>2008-08-12T07:22:00.000-07:00</published><updated>2008-10-03T07:23:22.597-07:00</updated><title type='text'>Development Environment</title><content type='html'>So tomorrow we're having a meeting to discuss the development environment that we're going to use for an upcoming project. This has kept me somewhat busy thinking about it, but I'm reasonably sure I know what we need.&lt;br /&gt;&lt;br /&gt;First, hardware. I'm going to be proposing that we buy a new server. A big, beefy server that can run up to three VM instances on it. Those three VM instances will be our development environment web server, our development environment database server, and a development server running a couple of other things. If we can't get one that will run three instances, than we'll get one that can run two instances and another, smaller one, for our development server&lt;br /&gt;&lt;br /&gt;The development environment web server and db server are boring. IIS and SQL Server 2005. Yawn.&lt;br /&gt;&lt;br /&gt;The development server is the really interesting thing - in one fell swoop I'm proposing updating a lot of our development practices:&lt;br /&gt;&lt;UL&gt;&lt;LI&gt;Install Subversion as our source control client. This is head and shoulders above Visual SourceSafe, and represents a new model of source control that makes multiple people editing a file easier and makes it a lot easier to branch off the main development trunk. This will involve installing TortoiseSVN and AnkhSVN on developer boxes.&lt;/LI&gt;&lt;LI&gt;Cruise Control.NET. This is iffiest - I'm not sure I can get support for true continuous integration.&lt;/LI&gt;&lt;LI&gt;nAnt. If I can't get support for continuous integration, I'll need this anyways. Minimally, we're going to do nightly builds. They're the best way to determine that progress is being made and that quality is being maintained during the code construction phase of a project.&lt;/LI&gt;&lt;LI&gt;fxCop. This allows us to do code construction checking based on a set of rules generated by Microsoft guidelines. We'll be taking a close look to turn off rules that are stupid.&lt;/LI&gt;&lt;/UL&gt;&lt;P&gt;In addition, we'll be upgrading to Visual Studio 2008 as soon as possible . I believe the plan is to get the MSDN SKU of it, which will be awesome. We'll also be creating a seperate area of FogBugz for the use of this project and discussion best practices for using that.&lt;br /&gt;&lt;br /&gt;Getting all this through will probably be a not easy task. But doing it will get us right on line for some world-class development environment characteristics. And it will make our projects more successful - which means it will be worth it.&lt;/P&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-7050289660205715267?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/7050289660205715267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=7050289660205715267' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7050289660205715267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7050289660205715267'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2008/08/development-environment.html' title='Development Environment'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-7965181569053877543</id><published>2007-12-20T18:42:00.001-08:00</published><updated>2007-12-20T18:58:30.633-08:00</updated><title type='text'>Consuming SAML Identity Authentication - Introduction</title><content type='html'>&lt;span xmlns=""&gt;&lt;p&gt;&lt;strong&gt;Introduction&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;One of the hot new topics in software development is the idea of a company buying a subscription to a piece of software. Instead of deploying that piece of software internally, with the host of IT needs and challenges that face any sort of deployment, they pay another company to allow them access to that software.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;This has many advantages – the client does not need to deal with rolling the application out to many users. This can be especially troublesome if the application is only used once or twice in a two year period – perhaps the application is used to review results of a survey that only occurs every so often or perhaps the application is used to manage the employee's pension plan.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;As with anything in software, though, there are disadvantages. The one that this entry is going to focus on is the problem of login propagation. Basically if each system that a client purchases uses a different login and password for the user, this can quickly lead to problems as more and more such systems are purchased. Think about all the online accounts that you have and how many passwords you've ended up with. This has security implications – the more usernames and passwords that a user has, the greater the possibility that they will be written down or made insecure. This is frankly unacceptable if, for instance,  the system holds valuable confidential data.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Companies, of course, have usernames and passwords – users use them every day to log into their corporate accounts and do their job. It would be a lot easier if they could share that information with third-parties and use those accounts used for logins. This is, of course, impossible – no company is going to want to share such sensitive information with a provider. Not to even mention the difficulties of keeping that credentials store up-to-date in the face of new users, removed users, and required password changes.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In past years vendors have tried to address this need with proprietary solutions. Netegrity (now owned by CA) released a product called Affiliate Agent, for instance.  Users on the way out of the corporate intranet were routed through a portal site. This redirected them to the service with credential information included in the HTTP request. An ISAPI filter runs on the provider's web site that intercepts the request, authenticates the user, and provides information about them in HTTP headers available to the provider's web application. This was a workable solution, though a proprietary one.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;With newer, open standards coming out around passing, encrypting and signing information, however, there is now a better solution. &lt;strong&gt;Security Assertion Markup Language &lt;/strong&gt;(SAML) is that solution.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;What is SAML?&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;SAML is a way of expressing information about a user in a secure fashion. This can include pretty much anything – user ids, email addresses, phone numbers – generally speaking whatever can be exposed by the systems linked up with a corporation's security gateway (think LDAP).&lt;br /&gt;&lt;/p&gt;&lt;p&gt;SAML itself is a specification defined by the &lt;a href="http://www.oasis-open.org/"&gt;OASIS&lt;/a&gt; (Organization for the Advancement of Structured Information Standards) group of several leading companies. The specification itself works with several other standards – &lt;a href="http://www.w3.org/XML/"&gt;XML&lt;/a&gt;, &lt;a href="http://www.w3.org/TR/xmldsig-core/"&gt;XML-Signature&lt;/a&gt;, &lt;a href="http://wp.netscape.com/eng/ssl3/"&gt;SSL&lt;/a&gt;, and (of course) &lt;a href="http://www.w3.org/Protocols/"&gt;HTTP&lt;/a&gt;. These combine to create a secure method for companies to pass credential information to their service providers.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;How Does a SAML Request &amp;amp; Response Work?&lt;/strong&gt;&lt;br /&gt;   &lt;/p&gt;&lt;p&gt;The lifecycle of a SAML Request &amp;amp; Response is as follows:&lt;br /&gt;&lt;/p&gt;&lt;ol style="margin-left: 37pt;"&gt;&lt;li&gt;The user clicks on the link to the provider's site (in this case we'll pretend the url is &lt;a href="https://www.provider.com/"&gt;https://www.provider.com/&lt;/a&gt;).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The web application running on the provider's site looks at the request and realizes that it has no idea who this user is. It redirects the user to a pre-arranged portal site that is hosted by the customer.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The portal site determines who the user is. This can be done through a username/password combo, the user's domain credentials, or any number of different ways.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The portal site creates a SAML response – a piece of XML indicating who the user is.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The portal site signs the SAML response with its private key, including the public key (or not! Some implementations do not include the public key. In this case the customer and the provider will need to exchange that public key. More on this later.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The SAML response is encoded in base64 and dropped into a HTTP POST request (within the SAMLResponse key) to the original provider's site.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The provider pulls out the SAMLResponse data, decodes it, verifies the signature, and extracts the user id. Frequently this user id is compared to the provider's list of allowed user ids.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If the user id validates, the user is allowed into the provider's site to do their work.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;SAML Responses&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Here's an example of a SAML response:&lt;br /&gt;&lt;/p&gt;&lt;div style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; font-family:Courier New; width: 100%;"&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%;margin-left: 36pt;"&gt;&amp;lt;samlp:Response xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" IssueInstant="2007-12-20T15:29:18.082Z" MajorVersion="1" MinorVersion="1" Recipient="" ResponseID="SM3b3c34b2352b7fedbaa30f1d9dc5a0c28e697fbe53"&amp;gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;ds:Signature xmlns="http://www.w3.org/2000/09/xmldsig#" xmlns:ds="http://www.w3.org/2000/09/xmldsig#"&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;ds:SignedInfo&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;ds:Reference URI="#SM3b3c34b2352b7fedbaa30f1d9dc5a0c28e697fbe53"&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;ds:Transforms&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                    &amp;lt;ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                    &amp;lt;ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;/ds:Transforms&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;ds:DigestValue&amp;gt;7wS/K/2tMeEWLrPE2hVAxJOoMFI=&amp;lt;/ds:DigestValue&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;/ds:Reference&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;/ds:SignedInfo&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;ds:SignatureValue&amp;gt;Base-64 signature goes here.&amp;lt;/ds:SignatureValue&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;ds:KeyInfo&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;ds:X509Data&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;ds:X509Certificate&amp;gt;Base-64 certificate goes here&amp;lt;/ds:X509Certificate&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;ds:X509IssuerSerial&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                    &amp;lt;ds:X509IssuerName&amp;gt;CN=Trusted Secure Certificate Authority,O=Trusted Secure Certificate Authority,C=US&amp;lt;/ds:X509IssuerName&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                    &amp;lt;ds:X509SerialNumber&amp;gt;&amp;lt;/ds:X509SerialNumber&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;/ds:X509IssuerSerial&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;ds:X509SubjectName&amp;gt;&amp;lt;/ds:X509SubjectName&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;ds:X509SKI&amp;gt;&amp;lt;/ds:X509SKI&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;/ds:X509Data&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;/ds:KeyInfo&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;/ds:Signature&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;samlp:Status xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol"&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;samlp:StatusCode Value="samlp:Success"/&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;/samlp:Status&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;saml:Assertion xmlns:SM="http://www.netegrity.com/SiteMinder" AssertionID="SMb65e33e44ef3db1774911aea9b268074bb5fdbe0" IssueInstant="2007-12-20T15:29:18.071Z" Issuer="http://www.netegrity.com/SiteMinder" MajorVersion="1" MinorVersion="1" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion"&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;saml:Conditions NotBefore="2007-12-20T15:28:48.062Z" NotOnOrAfter="2007-12-20T15:30:48.062Z"&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;saml:AudienceRestrictionCondition&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;saml:Audience&amp;gt;http://www.netegrity.com/SampleAudience&amp;lt;/saml:Audience&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;/saml:AudienceRestrictionCondition&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;/saml:Conditions&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;saml:AttributeStatement&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;saml:Subject&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="www.netegrity.com"&amp;gt;&amp;lt;/saml:NameIdentifier&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;saml:SubjectConfirmation&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                    &amp;lt;saml:ConfirmationMethod&amp;gt;urn:oasis:names:tc:SAML:1.0:cm:bearer&amp;lt;/saml:ConfirmationMethod&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;/saml:SubjectConfirmation&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;/saml:Subject&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;saml:Attribute AttributeName="SMContent" AttributeNamespace="http://www.netegrity.com/SiteMinder"&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;saml:AttributeValue&amp;gt;&amp;lt;/saml:AttributeValue&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;/saml:Attribute&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;/saml:AttributeStatement&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;saml:AuthenticationStatement AuthenticationInstant="2007-12-20T15:29:17.000Z" AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:unspecified"&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;saml:Subject&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.0:assertion" NameQualifier="www.netegrity.com"&amp;gt;&amp;lt;/saml:NameIdentifier&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;saml:SubjectConfirmation&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                    &amp;lt;saml:ConfirmationMethod&amp;gt;urn:oasis:names:tc:SAML:1.0:cm:bearer&amp;lt;/saml:ConfirmationMethod&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;                &amp;lt;/saml:SubjectConfirmation&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;            &amp;lt;/saml:Subject&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;        &amp;lt;/saml:AuthenticationStatement&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;    &amp;lt;/saml:Assertion&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p style="background: rgb(253, 233, 217) none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; margin-left: 36pt;"&gt;&lt;span style="font-family:Courier New;"&gt;&amp;lt;/samlp:Response&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p&gt;In the next post, I'll dissect the components of this request and explain what goes into a SAML response. After that I'll show how, in .NET, you can consume a SAML response, verify it, and pull out the user id.&lt;/p&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-7965181569053877543?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/7965181569053877543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=7965181569053877543' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7965181569053877543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/7965181569053877543'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2007/12/consuming-saml-identity-authentication.html' title='Consuming SAML Identity Authentication - Introduction'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-3090921878870244631</id><published>2007-11-13T17:43:00.000-08:00</published><updated>2007-12-12T17:44:33.697-08:00</updated><title type='text'>Breaking Assumptions</title><content type='html'>&lt;div class="ljcut" text="Geekier than you probably want to know..."&gt;Usually when you do a project you talk to the people who are going to use it. You discuss with them what the product is supposed to do, and what conditions will break the product. You come to some agreement and you make some plans and assumptions based on those agreements.&lt;/div&gt; &lt;div class="ljcut" text="Geekier than you probably want to know..."&gt; &lt;/div&gt; &lt;div class="ljcut" text="Geekier than you probably want to know..."&gt;Generally, the first of those assumptions will be broken in the first six months. That’s what happened to me today. And, as usual in these cases, rampant hacking was required.&lt;/div&gt; &lt;div class="ljcut" text="Geekier than you probably want to know..."&gt; &lt;/div&gt; &lt;div class="ljcut" text="Geekier than you probably want to know..."&gt;Anyways, some context. Our reporting system defines, on a per-report basis, a set of views that we can guide a user through to give them a high-level view of their reporting data. We offer a PDF download of this "Summary View". The PDF download is implemented in SQL Server Reporting Services 2005. Since it is dynamic, we do this by defining an rdl for each type of page (stacked graph, difference graph, table, etc). An ASP.NET application is responsible for looking up what types of views constitutes a user's Summary View and, using the reporting services control shipped with Visual Studio 2005, getting the pdf for each individual page. We then use a third party component to put it together and ship it to the user.&lt;br /&gt;&lt;br /&gt;Basically, charts in SQL Server Reporting Services 2005 don't span pages. So if you have a ton of rows in your chart, that chart will get scrunched up to the point of uselessness. This isn't such a good thing; it also isn't fixable with the component that ships with SSRS - this may not be true in a third-party component, but we really didn't have time to go price one out.&lt;br /&gt;&lt;br /&gt;There is a fix - but it is one with drawbacks. Basically, you can embed a chart in the row of a table in such a way that it mimics chart functionality. To do this, you need to drag a table onto the form and set the dataset name for that table to the dataset you were originally going to plug into the chart. (In our case, it was something like StackedGraphData).&lt;br /&gt;&lt;br /&gt;This is where you run into the first problem. If you simply drag a chart object onto the data area of the table you will get an error indicating that you can't do that: charts aren't supported in tables. This is mis-leading and entirely not true (mad props to my co-worker Greg for discovering this). What you need to do is get a property dialog for the table and switch to the Grouping tab. You're going to set up grouping for your table - just set it up to be some unique value in your data set (in our case, each item in the graph has a unique code that we could set it to. Your mileage may very, but there ought to be some sort of unique row identifier in your data). Hit OK.&lt;br /&gt;&lt;br /&gt;Your table will now have several new rows: a new header, footer, a separator row between two groups, and at least two different group "bands".  This is fine: delete what you don't need. You can now drag a chart onto the table area and set it up however you'd like. Remember that your chart is going to be repeated for each row of your table: you probably don't want a legend and may well not want axis labels.&lt;br /&gt;&lt;br /&gt;There are, of course, drawbacks to this approach:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You're embedding a new chart object in each row of your table. This is not the most performance-happy thing you could be doing. Don't do this unless you &lt;b&gt;really, really&lt;/b&gt; have to.&lt;/li&gt;&lt;li&gt;The charts are independent of each other, which means you'll have to do a lot more hacking than I was willing to put up with if you want to have an axis label that makes any sense.&lt;/li&gt;&lt;/ul&gt;Once this was accomplished, then came the next problem. Our chart is a stacked bar chart, with three values in blue, yellow and red. We wanted to have a legend attached to each page of the output that explained what was going on. This would normally be simple: just add a footer to the table and, in the properties of the footer, specify that it should be repeated on each page. Not for us, of course!&lt;br /&gt;&lt;br /&gt;Where we ran into problems was the fact that none of the text for a report page is specified in the rdl itself. Instead, we store all the text in the database: this allows us to do things like override text on a per-project basis and, more importantly, to support as many languages as our heart desires. So, in the rdl, we've defined a few data sets that contain individual pieces of text for the report.&lt;br /&gt;&lt;br /&gt;The problem here is that a textbox doesn't have a data set property. You need to specify it by creating an expression that specifically refers to the data set in question. Where this falls down is when you attempt to embed that textbox into a table: doing so will cause a run-time error as a textbox needs to refer to the dataset that's specified in the data region you're working in (for no readily apparent reason).&lt;br /&gt;&lt;br /&gt;It took me a while of hacking to figure out the way around this issue. Basically: you cheat. Create a corresponding textbox for each textbox you want to put into the table, outside of the table. Have it get the value from the dataset you want, and set its visibility to false. Be sure to give it a good name. Then, in the textboxes in your table you're going to set the value equal to an expression that grabs the value of the hidden textbox: ReportItem!textbox1.Value. This will allow you to get around the rediculous data set rule.&lt;br /&gt;&lt;br /&gt;Tomorrow I need to alter our ASP.NET application to, in only certain cases, substitute these new graphs for our old ones.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-3090921878870244631?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/3090921878870244631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=3090921878870244631' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/3090921878870244631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/3090921878870244631'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2007/11/breaking-assumptions.html' title='Breaking Assumptions'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-2483012830140147145</id><published>2007-09-11T17:43:00.000-07:00</published><updated>2007-12-12T17:43:53.361-08:00</updated><title type='text'>Rocovering from a Failed Process Crisis</title><content type='html'>&lt;p class="MsoNormal"&gt;&lt;b style=""&gt;Introduction&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If you are a member of an IT organization that supports a business process (as opposed to producing the product that the business sells, for instance), then there are some operational realities that you no doubt face. One of these is that there is probably at least one process that you work with that is failing.&lt;/p&gt;    &lt;p class="MsoNormal"&gt;Why do processes fail? There are several reasons, and very few of them are bad. No one, after all, sets out to create a failed process. No one sets out to create something that will lead to the cursing of their name. Nonetheless, processes fail for many reasons:&lt;br /&gt; &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt; &lt;!--[endif]--&gt;&lt;/p&gt;  &lt;ul style="margin-top: 0in;" type="disc"&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Business changes &lt;/b&gt;– I think this is      the most common of the reasons a process fails; the business assumptions      that process rested on change. This is sure to happen the longer a process      is in place. The very success of a process, in fact, will guarantee that      this will happen; as the business prospers either the load through the      process increases to dangerous levels or the type of load changes      fundamentally. This is equivalent to an earthquake cracking the foundation      of the house.&lt;br /&gt;      &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt;      &lt;!--[endif]--&gt;&lt;b style=""&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Technology changes &lt;/b&gt;– This is      another common failing. The base technology changes and things that were      impossible before become possible. What was possible with VB6 and MS      Access is not, after all, what is possible with C# and Microsoft.NET. If      this was the case, why would anyone move to .NET?&lt;br /&gt;      &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt;      &lt;!--[endif]--&gt;&lt;b style=""&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Personnel changes &lt;/b&gt;– This can      easily relate to the last two, but is important enough that it needs to be      brought up separately. As people leave your company through retirement or      simple job changes, the knowledge that they bring with them will leave      with them. Thus, you can easily find yourself with no one who can support      the current process.&lt;b style=""&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/li&gt;&lt;/ul&gt;    &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;&lt;o:p&gt; &lt;/o:p&gt;&lt;/b&gt;&lt;br /&gt;One thing to note about each of these reasons, by the way, is that none of them are really indicative of a defective process. They are simply indicative that the conditions that the process has operated under has changed in such a way that makes using that process non-economical.&lt;/p&gt;    &lt;p class="MsoNormal"&gt;This is also not to say that every company with a failed process will find itself in a crisis. Your company might live with a failing process for weeks and months, even years. Until the business decision makers realize that the failing process is interfering with work in a severe enough fashion, there won’t be a crisis. Generally, you’ll probably need at least two of the items in the above list to be true. Probably all three, in fact. If that happens, then you case a failed process crisis.&lt;/p&gt; &lt;br /&gt; &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;What does a failed process crisis look like?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;There are several defining characteristics of a failed process crisis that you need to be aware of.&lt;br /&gt; &lt;!--[endif]--&gt;&lt;/p&gt;  &lt;ol style="margin-top: 0in;" start="1" type="1"&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;The crisis is immediate.&lt;/b&gt; There are      things that need to happen immediately; whatever the process was, the      outputs of it still need to happen. Shutting down the business for a few      days is not an option.&lt;br /&gt;      &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt;      &lt;!--[endif]--&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;The crisis is long-term.&lt;/b&gt; All the      same, the fundamental problem is that your business process is failing.      You need to re-architect a process and that is not something that can be      done overnight; it requires careful thought and development.&lt;br /&gt;      &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt;      &lt;!--[endif]--&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Its your fault, even if it isn’t&lt;/b&gt;.      Sure you’ve been telling them for years that using an Access database as a      multi-user database store is a bad idea. Sure you’ve been wanting to      re-write the thing since you started. That doesn’t matter. What does      matter is that the business process has failed and IT wasn’t immediately      ready with a replacement. Yes, I know that you had no way of knowing when      the server would fail, or when that key person would quit. And yes, its      not fair. But that’s the way it is.&lt;/li&gt;&lt;/ol&gt;    &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;The Good News&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;      &lt;p class="MsoNormal"&gt;So from what you’ve read so far, you’re probably despairing. And you should; a failed business process is a hard thing to deal with. There is good news here, though, to go with the bad. And that is this: you have never been more visible to the company than you are right now. If you respond well to this crisis than you’ve proven your worth to the company, in spades.&lt;br /&gt;&lt;br /&gt;Of course, the bad news is that you have never been more visible to the company. If you fall down from this challenge, you’re probably going to need a resume. This is not a time for the faint at heart.&lt;/p&gt;    &lt;p class="MsoNormal"&gt;&lt;b style=""&gt;What do I do?&lt;o:p&gt;&lt;/o:p&gt;&lt;/b&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;If you’ve read this far, than hopefully you’re ready for what needs to be done.&lt;/p&gt;    &lt;ul style="margin-top: 0in;" type="disc"&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Get out of your office.&lt;/b&gt; Seriously.      It may seem like you need to be in your office crunching code twelve hours      a day, but you’re wrong. What you &lt;b style=""&gt;need&lt;/b&gt;      to be doing is talking to the people who aren’t in IT. You need to know      how things were done before; how can you improve anything if you don’t      know that?&lt;br /&gt;    &lt;br /&gt;     Arguable more important, though, is the political aspect. People need to      see you helping to deal with the crisis. People need to think that you      care about what they’re going through and that you are there to help them      fix the problem. The caveat to this? Make sure that you &lt;b style=""&gt;are&lt;/b&gt; helping to deal with the      crisis and that you really &lt;b style=""&gt;do &lt;/b&gt;care      about what people are going through? Nothing will sink you faster than      insincerity.&lt;/li&gt;&lt;/ul&gt;    &lt;ul style="margin-top: 0in;" type="disc"&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Think about the short term.&lt;/b&gt; Get      your developers in your office. Include a representative of the people who      have to go through the process. Ask yourselves this question: “What can we      do in two weeks that will have best impact on the process?”&lt;br /&gt;    &lt;br /&gt;     You’re looking for easy wins here; things that will make things easier      without betting the farm. Two weeks is baseline; its fine if it really      takes three weeks or a month. Generally speaking, though, your first few      easy wins should be very short. Your goal here is to both make things a      little better and make it clear that your group actually is making things      better.&lt;br /&gt;    &lt;br /&gt;     When considering these tasks, you’re judging them on two axis. First, what      is the risk of doing this? How much chance is it that this is going to      blow up in your face? How much chance is there that this is going to be an      enormous win? Secondly, how long will it take? You want to keep these in      opposition: if you’re going to try something that may blow up in your      face, you only want to spend a day trying it. If you’re going to try      something that’s probably going to save your rear, then spend two weeks      doing it.&lt;br /&gt;    &lt;br /&gt;     Just make sure that whatever you’re doing, you’re following the first      rule. People really do need to know that you’re trying to make a      difference.&lt;br /&gt;      &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt;      &lt;!--[endif]--&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Nothing is sacred&lt;/b&gt;. Seriously, the      process is broken? Why are you holding up sacred cows when you have no      food? &lt;i style=""&gt;Eat the damned cow.&lt;/i&gt; That      may mean personnel changes. That may mean hiring temporary workers to help      you. That may mean process changes. Leave nothing off the table.&lt;br /&gt;    &lt;br /&gt;     That said, if you’re going to try to eat a sacred cow you need to be sure      of a couple of things. First, you’re going to need buy-in. That’s the      point of the all-important first step; hopefully by now you’ve gotten the      buy-in and goodwill that you need. Second, it needs to work. Take into      account the risk that it won’t, and be honest about confronting those      risks. If your sacred cow gives you salmonella, you’re in deep shit.&lt;br /&gt;      &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt;      &lt;!--[endif]--&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Think about the long term.&lt;/b&gt; This      crisis won’t last forever. When it ends, the urgency will go out of the      situation. Don’t let that make you think that the fix is over. If you’ve      been following these instructions, you’ve made a series of short term      patches to the underlying problem. Essentially, you glued everything      together with duct tape and baling wire.&lt;br /&gt;    &lt;br /&gt;     Now its time to build something entirely new. This process is more akin to      a traditional software process, so I won’t go into the full details of how      to go about doing it. There are some things you need to consider.&lt;br /&gt;    &lt;br /&gt;     First, a lot of the urgency has gone out of the process now that the      immediate crisis is gone. You need to be the voice of reason here,      reminding people of how bad it got and what still needs to be done. You      need to keep building up good-will with everyone else in your company,      because you’re going to keep spending it. People need to believe that you      know what you’re talking about&lt;br /&gt;      &lt;!--[if !supportLineBreakNewLine]--&gt;&lt;br /&gt;      &lt;!--[endif]--&gt;&lt;/li&gt;&lt;li class="MsoNormal" style=""&gt;&lt;b style=""&gt;Act&lt;/b&gt;. This is the last point, but      probably one of the most important. You need to act. You can’t stand      still. If it looks like things are bogging down into discussions and      meeting after meeting, then do something. You need to drive everyone to      action.&lt;br /&gt;    &lt;br /&gt;     This does not mean you act without thinking. Hold meetings. Be sure,      though, that the right people are around the table. You need to be holding      meetings with the people who are going to be involved in this failed process.      And if a meeting looks like its driving towards no action, then push. Try      to get everyone to agree on an action, no matter how small. Then go do the      action and start again.&lt;br /&gt;    &lt;br /&gt;     This is going to be hard; probably the hardest part of this process.      There’s a lot of motivation towards inaction, towards getting group      consensus and not acting until everyone knows everything that needs to be      done. Letting these fears bog down this recovery process, though, will      kill you as sure as tying a plastic bag to your head.&lt;/li&gt;&lt;/ul&gt;            &lt;p class="MsoNormal"&gt;That’s it in a nut-shell. There are tons of more points that need to be made, and situations that are specific to your specific company will come up. Be flexible, be aware, and be damned good, and you’ll make it through this mostly un-singed.&lt;br /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;br /&gt;Good luck.&lt;br /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;br /&gt;&lt;st1:personname st="on"&gt;John Christensen&lt;/st1:personname&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-2483012830140147145?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/2483012830140147145/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=2483012830140147145' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/2483012830140147145'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/2483012830140147145'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2007/09/rocovering-from-failed-process-crisis.html' title='Rocovering from a Failed Process Crisis'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1561696658668544884.post-793804207314266886</id><published>2006-08-25T13:08:00.000-07:00</published><updated>2006-08-25T13:09:30.099-07:00</updated><title type='text'>First Post</title><content type='html'>This is my first post using this. I'm interesting in seeing if blogger has the tools needed for me to use javascript in there. I'd love to add in my starred items from Google Reader, or add in analysis from Google Analytics.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1561696658668544884-793804207314266886?l=netbard.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://netbard.blogspot.com/feeds/793804207314266886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1561696658668544884&amp;postID=793804207314266886' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/793804207314266886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1561696658668544884/posts/default/793804207314266886'/><link rel='alternate' type='text/html' href='http://netbard.blogspot.com/2006/08/first-post.html' title='First Post'/><author><name>netbard</name><uri>http://www.blogger.com/profile/01148354641369170774</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://4.bp.blogspot.com/-ZysaJJ6eDFc/TpyPujjbU-I/AAAAAAAAADs/Tft1gKxXp8k/s220/photo.jpg'/></author><thr:total>0</thr:total></entry></feed>
