<?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-7020748</id><updated>2011-04-21T19:37:01.769-07:00</updated><title type='text'>StaticGround</title><subtitle type='html'>Better Living Through Mobility</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>54</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7020748.post-2177612389448219139</id><published>2007-12-20T11:19:00.000-08:00</published><updated>2007-12-20T15:38:15.369-08:00</updated><title type='text'>Derived classes and events</title><content type='html'>Events are a useful feature of the C# language and allow for clients to be notified when the state of a server changes.  You create an event by declaring it in the class that will raise the event:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public event EventHandler&lt;eventargs&gt; NotifyClient;&lt;br /&gt;&lt;/eventargs&gt;&lt;/pre&gt;&lt;br /&gt;Here, I used the generic event template to eliminate the need to define a separate delegate.  To register a callback method with the event, we do the following in the class that will receive the event notification from the class that raised the event:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;message.NotifyClient += new EventHandler&lt;eventargs&gt;(message_NotifyClient);&lt;br /&gt;&lt;br /&gt;static void message_NotifyClient(object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;  throw new Exception("The method or operation is not implemented.");&lt;br /&gt;}&lt;br /&gt;&lt;/eventargs&gt;&lt;/pre&gt;&lt;br /&gt;When the event is raised the message_NotifyClient method will execute.  To raise the event we add the following to the class that raises the event:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;protected virtual void OnNotifyClient(EventArgs e)&lt;br /&gt;{&lt;br /&gt;  EventHandler&lt;eventargs&gt; handler = NotifyClient;&lt;br /&gt;&lt;br /&gt;  if (handler != null)&lt;br /&gt;      handler(this, e);&lt;br /&gt;}&lt;br /&gt;&lt;/eventargs&gt;&lt;/pre&gt;&lt;br /&gt;Here, we make a copy of the event since access to the event is not thread-safe (i.e. another thread could delete/modify the event before the if (handler != null) completes).  When the client wants to raise the event, it does so by executing the OnNotifyClient method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private void DoSomething()&lt;br /&gt;{&lt;br /&gt; // Do something...&lt;br /&gt; OnNotifyClient(new EventArgs());&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When OnNotifyClient is executed, the message_NotifyClient method is executed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Derived classes and events&lt;/span&gt;&lt;br /&gt;An event can only be raised from methods declare within the class that declared the event.  So events declared in class A can only be raised from methods within class A.  By default, events are not inherited by derived classes, so in the following base class definition:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Base&lt;br /&gt;{&lt;br /&gt; public event EventHander&lt;eventargs&gt; NotifyClient;&lt;br /&gt;}&lt;br /&gt;&lt;/eventargs&gt;&lt;/pre&gt;&lt;br /&gt;with the derived class definition&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Derived : Base&lt;br /&gt;{&lt;br /&gt; private void DoSomething()&lt;br /&gt; {&lt;br /&gt;   EventHandler&lt;eventargs&gt; handler = NotifyClient;&lt;br /&gt;&lt;br /&gt;   if (handler != null)&lt;br /&gt;       handler(this, new EventArgs());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/eventargs&gt;&lt;/pre&gt;&lt;br /&gt;The derived class will not have access to the NotifyClient event since the NotifyClient event was not declared in the Derived class.  There are two ways to workaround this requirement:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Define the OnNotifyClient method in the Base class as virtual and then override the OnNotifyClient method in the Derived class&lt;/li&gt;&lt;li&gt;Declare the event as virtual in the Base class, then override the event in the Derived class&lt;/li&gt;&lt;/ul&gt;You'll notice above that the OnNotifyClient method is declared with the virtual keyword.  This allows the Derived class to override the OnNotifyClient method and access the NotifyClient directly.  So, we could do this in the Derived class:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;protected override void OnNotifyClient(EventArgs e)&lt;br /&gt;{&lt;br /&gt; EventHandler&lt;eventargs&gt; handler = NotifyClient;&lt;br /&gt;&lt;br /&gt; if (handler != null)&lt;br /&gt;   handler(this, e);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;protected void DoSomething()&lt;br /&gt;{&lt;br /&gt; // Do something Derived-class specific, then call OnNotifyClient&lt;br /&gt; OnNotifyClient(new EventArgs());&lt;br /&gt;}&lt;br /&gt;&lt;/eventargs&gt;&lt;/pre&gt;&lt;br /&gt;The second approach is to declare the event virtual in the Base class, then override the event in the Derived class:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Base&lt;br /&gt;{&lt;br /&gt; public virtual event EventHandler&lt;eventargs&gt; NotifyClient;&lt;br /&gt; ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Derived : Base&lt;br /&gt;{&lt;br /&gt; public override event EventHandler&lt;eventargs&gt; NotifyClient;&lt;br /&gt;&lt;br /&gt; public void DoSomething()&lt;br /&gt; {&lt;br /&gt;   EventHandler&lt;eventargs&gt; handler = NotifyClient;&lt;br /&gt;&lt;br /&gt;   // Here, we can access the NotifyClient directly since we've overridden access&lt;br /&gt;   if (handler != null)&lt;br /&gt;       handler(this, new EventArgs());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/eventargs&gt;&lt;/eventargs&gt;&lt;/eventargs&gt;&lt;/pre&gt;&lt;br /&gt;Which approach you take is up to you.  Both approaches give the Derived class the flexibility to perform Derived-specific tasks around the decision to raise the event.  It really comes down to which approach is preferred.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-2177612389448219139?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/2177612389448219139/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=2177612389448219139' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/2177612389448219139'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/2177612389448219139'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2007/12/derived-classes-and-events.html' title='Derived classes and events'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-1119345787451950610</id><published>2007-11-28T11:44:00.000-08:00</published><updated>2007-11-28T11:45:16.374-08:00</updated><title type='text'></title><content type='html'>&lt;DIV class=ExternalClass946F06D3539449CB90BEB7FFEFC433A7&gt;&lt;br /&gt;&lt;DIV&gt;﻿ &lt;br /&gt;&lt;DIV id=edit-area&gt;﻿ &lt;br /&gt;&lt;DIV id=edit-area&gt;When the pros of using reflection outweigh the cons, you can take advantage of using it when iterating over properties of classes.&amp;nbsp; To help with debugging, you can override the ToString() of your classes to return a string that contains the name of any public properties along with their corresponding values:&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public override string ToString()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; StringBuilder sb = new StringBuilder();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Type t = this.GetType();&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; PropertyInfo[] pInfo = t.GetProperties();&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Append(t.ToString() + "\r\n");&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (PropertyInfo p in pInfo)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; string fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Append(fmt + "\r\n");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return sb.ToString();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;The function uses reflection to get the public properties of the class and it iterates over the collection of properties and builds a string that represents the state of the class.&amp;nbsp; The string returned from ToString() would look like this:&lt;BR&gt;&lt;BR&gt;Property1 = Value1&lt;BR&gt;Property2 = Value2&lt;BR&gt;.&lt;BR&gt;.&lt;BR&gt;.&lt;BR&gt;&lt;BR&gt;The PropertyInfo.GetValue() function takes two parameters; the first parameter is the reference to this, while the second parameter is an object array that is used when the PropertyInfo references an indexed property.&amp;nbsp; When using reflection to enumerate properties on a class that contains other classes, you must accomodate the case where a class might contain an indexed property:&lt;BR&gt;&lt;BR&gt;public class Details&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public EDIProcess.Model.EstimateDetailType this[int index]&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; get { return (EDIProcess.Model.EstimateDetailType) DetailCollection[index]; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;In this case, the Details class contains an indexer that is used to retrieve EstimateDetailType objects by index from the DetailCollection property.&amp;nbsp; You can use the GetValue() function and pass in an object array that contains a single entry that is the value of the offset into the collection, which will reference the indexed item at that position within the collection.&lt;BR&gt;&lt;BR&gt;public class Details&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; public override string ToString()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; StringBuilder sb = new StringBuilder();&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; try&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; Type t = this.GetType();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; string fmt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; PropertyInfo[] pInfo = t.GetProperties();&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Append(t.ToString() + "\r\n");&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; foreach (PropertyInfo p in pInfo)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if (p.Name == "Item")&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; for (int i = 0; i &amp;lt; Count; i++)&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, new object[] { i }));&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Append(fmt + "\r\n");&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&lt;SPAN style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/SPAN&gt;&lt;BR style="FONT-WEIGHT: bold"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; else&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; sb.Append(fmt + "\r\n");&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; catch (Exception ex)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; log.Error(ex.Message);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return sb.ToString();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;BR&gt;}&lt;BR&gt;&lt;BR&gt;The items in bold represent the changes to support the indexed properties.&amp;nbsp; The Details class contains a DetailCollection class (which derives from ArrayList), and the Details class contains an indexer to retrieve an item from the collection as well as a property that returns the number of items stored in the collection.&amp;nbsp; The modification looks for a property named Item in the Details class, and it then retrieves the count of objects in the collection and for each object in the collection it calls the GetValue(), passing in a reference to the Details class (this) and a new object[] array that contains a single member that stores the integer value of the item within the collection.&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;BR&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-1119345787451950610?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/1119345787451950610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=1119345787451950610' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/1119345787451950610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/1119345787451950610'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2007/11/when-pros-of-using-reflection-outweigh.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-2232217520821325826</id><published>2007-09-21T13:30:00.000-07:00</published><updated>2007-09-21T13:31:31.741-07:00</updated><title type='text'>Threading in C#</title><content type='html'>I found an interesting online resource on &lt;a href="http://www.albahari.com/threading/index.html"&gt;Threading in C#&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-2232217520821325826?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/2232217520821325826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=2232217520821325826' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/2232217520821325826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/2232217520821325826'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2007/09/threading-in-c.html' title='Threading in C#'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-116260747027792534</id><published>2006-11-03T17:46:00.000-08:00</published><updated>2006-11-03T18:31:10.686-08:00</updated><title type='text'></title><content type='html'>On the project that I am leading, I ran across an interesting issue using a combination of a stored procedure and the ISNULL SQL function.  If we have the following table definition:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CREATE TABLE [dbo].[TEST_TABLE] (&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;[Data] [varchar] (5) COLLATE Latin1_General_BIN NOT NULL&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;and this table contains a row that contains:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Data&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;=====&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;ABCDE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now, if we have a stored procedure that updates the row called UpdateData:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CREATE PROCEDURE UpdateData&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    @Data varchar(3) = null&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;AS&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;Begin Tran&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    update TEST_TABLE&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    set Data = ISNULL(@Data, Data)&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;IF @@ERROR &lt;&gt; 0&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    Rollback Tran&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;else&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;    Commit Tran&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The stored procedure sets the @Data variable to null by defualt, otherwise it will use the value passed to it via the @Data variable.  The update statement uses the ISNULL function to check if the @Data variable is the default value of null and if it is, then it should use the current value in the Data column on the table.  If we call this stored procedure, without passing in the @Data parameter, the stored procedure will set the value of the @Data parameter to null, and this is what we'll get:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Data&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;=====&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;&lt;br /&gt;ABC&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What happened, why did my data get truncated?  Think about how the ISNULL function works, it sets the variable specified in the first parameter to the value of the variable specified in the second parameter if the first parameter is null.  So, it should set the @Data variable to the value in the Data column.  Also note that the stored procedure is implicitly creating the @Data variable in the procedure declaration and also note that the @Data variable has a width of 3 varchars instead of the 5 varchars in the TEMP_TABLE Data column declaration.  Essentially what happens is that the ISNULL function sees that the @Data variable is null, reads the Data column from the table and then copies the value from the Data column into the @Data variable.  Since the @Data variable is only 3 varchars wide, only 3 varchars are copied to it.  The set clause then updates the Data column with these 3 varchars from the @Data variable.  That's why the data gets truncated.  So, the moral of the story is to make sure of the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Your table column widths and your stored procedure widths match&lt;/li&gt;&lt;li&gt;You pass the right amount of data from your code to your stored procedure&lt;br /&gt;&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/7020748-116260747027792534?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/116260747027792534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=116260747027792534' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/116260747027792534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/116260747027792534'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/11/on-project-that-i-am-leading-i-ran.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115998973153403777</id><published>2006-10-04T12:21:00.000-07:00</published><updated>2006-10-04T12:22:13.813-07:00</updated><title type='text'>SQL Server pseudo nested transactions</title><content type='html'>SQL Server 2000 does not support nested transactions.  So, if we have the following two stored procedures:&lt;br /&gt;&lt;br /&gt;SP1:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;create procedure sp1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;as&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;begin tran&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;exec sp2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;if (@@error &lt;&gt; 0) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  goto on_error&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;commit tran&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;on_error:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;rollback tran&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;SP1:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; create procedure sp2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; as&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt; begin tran&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;insert table values ('sp2')&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt; if (@@error &lt;&gt; 0) &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;   goto on_error&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt; commit tran&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt; on_error:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt; rollback tran&lt;br /&gt;&lt;span style="font-family: arial;"&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The rules for nested begin transactions is:&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;Any begin tran statements are ignored, but each begin tran statement does update the @@trancount variable.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Any commit statements executed after the first commit transaction statement are ignored.  The transaction is committed only when the outermost commit statement is executed.  The @@trancount variable is decremented by one for each commit statement executed.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Any rollback statements executed will rollback the entire transaction and set the @@trancount variable to 0.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Basically, I think of nested transactions as really just one main transaction that could contain multiple time points where the state of the transaction (committed, rollback) can be modified.&lt;br /&gt;&lt;br /&gt;When using the ADO.NET SqlTransaction object you need to be aware of how transactions are committed and rolled back.  When the SqlTransaction.BeginTransaction method is executed, it implicitly executes the BEGIN TRAN SQL statement.  Any SQL statements executed will then execute on this main transaction.  If the SQL statements that are executed perform a commit or rollback, the main transaction is affected based on the rules above.  There may be certain cases where a servere SQL error will cause the main transaction to rollback, and if the main transaction is created by the SqlTransaction.BeginTransaction method, when the exception is caught, you will need to check if the transacion was actually already rolled back before executing the SqlTransaction.Rollback method:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    try&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       SqlTransaction txn = new SqlTransaction();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       txn.BeginTransaction();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Data.CallSproc1();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       Data.CallSproc2();  // throws an exception and rolls back the transaction&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;       txn.CommitTransaction();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    catch(SqlException ex)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        txn.RollbackTransaction();  // If the transaction is already rolled back, this will throw an exception&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;catch(SqlException ex)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    // Transaction was already rolled back, do something&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;span style="font-family: arial;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt; &lt;/span&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115998973153403777?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115998973153403777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115998973153403777' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115998973153403777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115998973153403777'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/10/sql-server-pseudo-nested-transactions.html' title='SQL Server pseudo nested transactions'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115983697439239906</id><published>2006-10-02T17:55:00.000-07:00</published><updated>2006-10-02T17:56:15.440-07:00</updated><title type='text'>NTLM Explained</title><content type='html'>If you want a good description of NTLM Authentication (Windows authentication), you can find a good resource &lt;a href="http://davenport.sourceforge.net/ntlm.html"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115983697439239906?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115983697439239906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115983697439239906' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115983697439239906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115983697439239906'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/10/ntlm-explained.html' title='NTLM Explained'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115931077756261791</id><published>2006-09-26T15:46:00.000-07:00</published><updated>2006-09-26T15:46:18.016-07:00</updated><title type='text'></title><content type='html'>Dan Ciruli has a good post on software as a service (SAAS) in the trenches &lt;a href="http://westcoastgrid.blogspot.com/2006/09/wait-i-thought-s-a-s-spelled-panacea.html"&gt;here&lt;/a&gt;.  In it he talks about a number of concerns that CIO's raise.  One of the concerns revolves around data security.  Companies want to be able to own the only copy of their data (not in some vendor's database halfway across the country) and they want to have the ability to apply different levels of access to the data based on how the data is used.  Having been involved in more than one SaaS projects, the discussions I've heard the same things over and over from clients: Where will my data live, and how will you secure it?  In general, discussions usually go like this:&lt;br /&gt;&lt;br /&gt;Project Lead: Your users can login to your own custom-branded site and use the system.&lt;br /&gt;Customer: How do I limit access to the site?&lt;br /&gt;Project Lead:  We have an admin screen that you can use to setup users.&lt;br /&gt;&lt;br /&gt;Customer: What if I want this integrated with my ActiveDirectory security?  When a user quits, I want one way to turn off access to the application.  Can I do that?&lt;br /&gt;&lt;br /&gt;Project Lead: No, you'd have to use the admin tool to remove the user.  We're working on the ActiveDirctory integration for the next release&lt;br /&gt;&lt;br /&gt;Customer: Well, OK, so how do I prevent users &lt;span style="font-style: italic;"&gt;outside &lt;/span&gt;of the company from going to the site and hacking into it?&lt;br /&gt;&lt;br /&gt;Project Lead: We have a very secure data center.&lt;br /&gt;&lt;br /&gt;Customer: What about data, where will it live?&lt;br /&gt;&lt;br /&gt;Project Lead: At our data center.&lt;br /&gt;&lt;br /&gt;Customer: So, if something happens to the data center, I won't have access to the data?  What if your site is down, and what if this is our accounting system, then we can't use the system.&lt;br /&gt;&lt;br /&gt;Project Lead: Well, yes, but we do have a service level agreement that we'd have to adhere to or your subscription will get reduced.  Also, our data center also has a service level agreement.&lt;br /&gt;&lt;br /&gt;Customer: I honestly don't really care about the reduced subscription rate, but at your prices this application needs to be bulletproof.  I need access to this data 24-7.  So, do you have a backup plan for my data?&lt;br /&gt;&lt;br /&gt;Project Lead: of course.&lt;br /&gt;&lt;br /&gt;Customer: OK, let me think about it.  I'll get back to you.&lt;br /&gt;&lt;br /&gt;The project lead goes back to the team and tells them to firgure out a way to integrate their application with ActiveDirectory.  The project lead also has some conversations with their hosting site.  The customer discusses purchasing the service with the executive management team.  The customer calls the project lead up:&lt;br /&gt;&lt;br /&gt;Customer: Well, I talked with the management here, and they had some concerns over data access.&lt;br /&gt;&lt;br /&gt;Project Lead: Our security policies are very comprehensive, your data will be secure.&lt;br /&gt;&lt;br /&gt;Customer: I can't guarantee that my data will be secure, unless I own the data, behind my firewall.&lt;br /&gt;&lt;br /&gt;Project Lead: Well I see your point, but you won't be able to get the advantages of automatic feature upgrades and centralized administration if we are unable to access the application behind your firewall.&lt;br /&gt;&lt;br /&gt;Customer: Access and control of our data is our biggest concern, the other 'features' are not essential.  Also, how do we get the data &lt;span style="font-style: italic;"&gt;out&lt;/span&gt; of your system?  Can we export the data into Excel?&lt;br /&gt;&lt;br /&gt;Project Lead: Well, we don't have an easy way of doing this, I suppose you could export most of the data to Excel, but some of the data will take a little more work to get to it.&lt;br /&gt;&lt;br /&gt;Project Lead: What databases do you have available for use?&lt;br /&gt;&lt;br /&gt;Customer: Oracle.  Some MySQL.&lt;br /&gt;&lt;br /&gt;Project Lead: Well, currently our application only works with SQL Server, and we'd need to make some modifications to give you the ability to host the application behind your firewall.&lt;br /&gt;&lt;br /&gt;Customer: We like the features of the application, but having a system that we can host ourselves is a requirement.  Let me know when you have an application that will integrate with our security model and our network architecture.&lt;br /&gt;&lt;br /&gt;Project Lead: OK, I'll see what I can do...&lt;br /&gt;&lt;br /&gt;I've seen most conversations with customers turn out like this, especially when you are trying to sell to the first handful of customers.  As the number of customers increases, there's usually trust in numbers, so it becomes less of a concern if a potential client can see that other clients trust you with their data.  I'm sure the first few customers that SalesForce tried to get had issues around data access and security.  If you are unable to convince them to trust you with their data, you have two choices:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Convert your application into a hosted solution that the customer can install on their own servers and manage.  Don't forget to think about how they will install and upgrade the application.  And security.  And data migration from legacy systems.  And browser support.  And rollback strategies.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Try and convince some other large enterprise customer that trusting you with their data is the only way to go.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115931077756261791?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115931077756261791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115931077756261791' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115931077756261791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115931077756261791'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/09/dan-ciruli-has-good-post-on-software.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115868989789185047</id><published>2006-09-19T11:17:00.000-07:00</published><updated>2006-09-19T11:18:18.830-07:00</updated><title type='text'></title><content type='html'>I was unable to find the documentation or a code sample that described how to configure the connectionString node in the dataConfiguration.config for the Data Access Application Block 2.0 (DAAB).  I searched the web and Google groups and each example shown used Integrated Security.  So, I had to take a look at the DAAB source code to figure out which parameters I needed to configure.&lt;br /&gt;&lt;br /&gt;In Data Access Application Block 2.0 To specify the connection strings for both integrated security and SQL security, you configure the dataConfiguration.config file:&lt;br /&gt;&lt;br /&gt;This will configure the DAAB to use SQL Security:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;     &amp;lt;connectionStrings&amp;gt;&lt;br /&gt;        &amp;lt;connectionString name="SQLSecConnStr"&amp;gt;&lt;br /&gt;          &amp;lt;parameters&amp;gt;&lt;br /&gt;            &amp;lt;parameter name="database" value="Database" isSensitive="false" /&amp;gt;&lt;br /&gt;            &amp;lt;parameter name="uid" value="Test" isSensitive="true" /&amp;gt;&lt;br /&gt;            &amp;lt;parameter name="pwd" value="Test" isSensitive="true" /&amp;gt;&lt;br /&gt;            &amp;lt;parameter name="server" value="WWW.XX.YY.ZZ\SQLInstance" isSensitive="false" /&amp;gt;&lt;br /&gt;          &amp;lt;/parameters&amp;gt;&lt;br /&gt;        &amp;lt;/connectionString&amp;gt;&lt;br /&gt;      &amp;lt;/connectionStrings&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This will configure the DAAB to use Integrated Security:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;     &amp;lt;connectionStrings&amp;gt;&lt;br /&gt;        &amp;lt;connectionString name="IntSecConnStr"&amp;gt;&lt;br /&gt;          &amp;lt;parameters&amp;gt;&lt;br /&gt;            &amp;lt;parameter name="database" value="Database" isSensitive="false" /&amp;gt;&lt;br /&gt;            &amp;lt;parameter name="Integrated Security" value="true" /&amp;gt;&lt;br /&gt;            &amp;lt;parameter name="server" value="WWW.XX.YY.ZZ\SQLInstance" isSensitive="false" /&amp;gt;&lt;br /&gt;          &amp;lt;/parameters&amp;gt;&lt;br /&gt;        &amp;lt;/connectionString&amp;gt;&lt;br /&gt;     &amp;lt;/connectionStrings&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115868989789185047?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115868989789185047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115868989789185047' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115868989789185047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115868989789185047'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/09/i-was-unable-to-find-documentation-or.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115697540843684399</id><published>2006-08-30T15:03:00.000-07:00</published><updated>2006-08-30T15:03:28.536-07:00</updated><title type='text'>Exceptions</title><content type='html'>Exceptions&lt;br /&gt;&lt;br /&gt;When throwing/handling exceptions you should be aware of a few things:&lt;br /&gt;&lt;br /&gt;Take a look at the following code:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;          try&lt;br /&gt;&lt;br /&gt;          {&lt;br /&gt;&lt;br /&gt;              db.ExecuteNonQuery(dbCommandWrapper);&lt;br /&gt;&lt;br /&gt;              log.Debug("Executed: " + sqlCommand);&lt;br /&gt;&lt;br /&gt;          }&lt;br /&gt;&lt;br /&gt;          catch (SqlException ex)&lt;br /&gt;&lt;br /&gt;          {&lt;br /&gt;&lt;br /&gt;              throw new ApplicationException("Exception encountered while inserting data", ex);&lt;br /&gt;&lt;br /&gt;          }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Notice a few things:&lt;br /&gt;&lt;br /&gt;  * I am catching a specific exception instead of catching the generic Exception.  So instead of catching all exceptions, just catch the exceptions that you intend to handle.&lt;br /&gt;  * I am throwing a new exception of type ApplicationException, and I am wrapping the original exception into the InnerException property.  This accomplishes two things: It gives the caller the ability to handle exceptions of type ApplicationException instead of handling Exception or SqlException typed exceptions.  The case for this is that if the business tier calls the data tier and the data tier encounters a SqlException, then either the data tier should handle the SqlException and don't throw it, or create a new exception and wrap the SqlException and throw this new exception to the business tier.  This eliminates the need for the business tier to try to handle SqlException exceptions when the Data tier should handle the SqlException.  Another point to note is that you should probably stay away from using the following throw commands: throw; throw ex; and throw new ApplicationException("some message"); as all three will overwrite any stack trace for the exception up to the point when the throw was executed, so all past stack traces before the throw was executed will be lost.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115697540843684399?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115697540843684399/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115697540843684399' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115697540843684399'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115697540843684399'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/exceptions_30.html' title='Exceptions'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115647628733212072</id><published>2006-08-24T20:23:00.000-07:00</published><updated>2006-08-24T20:24:47.523-07:00</updated><title type='text'>Interesting discussions around Google's open API's</title><content type='html'>Discussions about who really owns your data on the web and how you can access your data &lt;a href="http://scobleizer.wordpress.com/2006/08/24/wheres-google-in-the-conversation/"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115647628733212072?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115647628733212072/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115647628733212072' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115647628733212072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115647628733212072'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/interesting-discussions-around-googles.html' title='Interesting discussions around Google&apos;s open API&apos;s'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115647323508340265</id><published>2006-08-24T19:20:00.000-07:00</published><updated>2006-08-24T20:06:46.820-07:00</updated><title type='text'>Concurrency on the web</title><content type='html'>Lately, I've been noticing that more and more people are beginning to discuss concurrency and how it relates to the new multi core CPU's that are being released.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://krgreenlee.blogspot.com/"&gt;Kim Greenlee's blog post&lt;/a&gt;&lt;br /&gt;&lt;a href="http://acmqueue.com/modules.php?name=Content&amp;pa=showpage&amp;amp;pid=332"&gt;Herb Sutter's article on concurrency&lt;/a&gt;&lt;br /&gt;&lt;a href="http://software.ericsink.com/entries/LarryO.html"&gt;Musings about concurrency and manycore CPUs&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.devx.com/amd/Article/32246"&gt;Larry O'Brien&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Most of the discussions center on how to design software to take advantage of multiple cores, and how to come up with an easy way to get developers interested in concurrency.  Designing software to take advantage of multiple CPUs is familiar to most systems software engineers (operating systems, web servers, database servers, search engines), but most business applications are still designed to take advantage of a single CPU.  Most business application developers are not familiar with concepts such as threading, synchronization, shared memory/data, deadlocks, etc. because the software that they build usually has the requirment that it perform one task at a time, in serial because there was never a requirement to run tasks in parallel.  Even if there was a  requirement to run tasks in parallel, it would probably be easier to install the system on a new machine and load balance both systems, since the cost of a new machine is less than the time/effort cost for the developer to redesign the system as a concurrent system.&lt;br /&gt;&lt;br /&gt;From the business application developer standpoint there are two questions they will ask about concurrency: How can I split my application into different business processes that can run independently of one another?  what's a thread? why would I use it?  what's a lock? what's deadlock?  All of these questions will need to get answered if the developer wants to take advantage of all of the computing power available to them.  The questions around threads, locks, synchronization, etc. are easy to find answers to, there are lots of books/websites on the topic.  The more difficult questions to answer are about how to divide applications into business processes that can run in parallel.  Since every business application is different, there probably is no one right answer to this question, but I do feel that it is useful for developers to become familiar with how system engineers solve problems by programming for concurrency.  Basically, I believe that we will start to see more and more design patterns that are used to solve concurrency problems.  Martin Fowler's book: Patterns of Enterprise Application Architecture has a section on concurrency, and the book Data Access Patterns also has a section on concurrency, so these are two good places to start.  For learning about multithreading, the book &lt;a href="http://manning.com/dennis/"&gt;.NET Multithreading&lt;/a&gt; is a good one.  There are a few frameworks that may make developing concurrent applications easier on the .NET platform:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.alchemi.net/about.html"&gt;Alchemi&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.digipede.com"&gt;Digipede&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Although not .NET-only, the framework &lt;a href="http://www.openmp.org/drupal/"&gt;OpenMP&lt;/a&gt; is another choice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115647323508340265?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115647323508340265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115647323508340265' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115647323508340265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115647323508340265'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/concurrency-on-web.html' title='Concurrency on the web'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115626811712086171</id><published>2006-08-22T10:32:00.000-07:00</published><updated>2006-08-22T10:36:53.656-07:00</updated><title type='text'></title><content type='html'>When the pros of using reflection outweigh the cons, you can take advantage of using it when iterating over properties of classes.  To help with debugging, you can override the ToString() of your classes to return a string that contains the name of any public properties along with their corresponding values:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;        public override string ToString()&lt;br /&gt;        {&lt;br /&gt;            StringBuilder sb = new StringBuilder();&lt;br /&gt;            Type t = this.GetType();&lt;br /&gt;&lt;br /&gt;            PropertyInfo[] pInfo = t.GetProperties();&lt;br /&gt;&lt;br /&gt;            sb.Append(t.ToString() + "\r\n");&lt;br /&gt;&lt;br /&gt;            foreach (PropertyInfo p in pInfo)&lt;br /&gt;            {&lt;br /&gt;                string fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));&lt;br /&gt;&lt;br /&gt;                sb.Append(fmt + "\r\n");&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return sb.ToString();&lt;br /&gt;        }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The function uses reflection to get the public properties of the class and it iterates over the collection of properties and builds a string that represents the state of the class.  The string returned from ToString() would look like this:&lt;br /&gt;&lt;br /&gt;Property1 = Value1&lt;br /&gt;Property2 = Value2&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;.&lt;br /&gt;&lt;br /&gt;The PropertyInfo.GetValue() function takes two parameters; the first parameter is the reference to this, while the second parameter is an object array that is used when the PropertyInfo references an indexed property.  When using reflection to enumerate properties on a class that contains other classes, you must accomodate the case where a class might contain an indexed property:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Details&lt;br /&gt;{&lt;br /&gt;        public Main.Model.DetailType this[int index]&lt;br /&gt;        {&lt;br /&gt;            get { return (Main.Model.DetailType) DetailCollection[index]; }&lt;br /&gt;        }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In this case, the Details class contains an indexer that is used to retrieve DetailType objects by index from the DetailCollection property.  You can use the GetValue() function and pass in an object array that contains a single entry that is the value of the offset into the collection, which will reference the indexed item at that position within the collection.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;public class Details&lt;br /&gt;{&lt;br /&gt;        public override string ToString()&lt;br /&gt;        {&lt;br /&gt;            StringBuilder sb = new StringBuilder();&lt;br /&gt;&lt;br /&gt;            try&lt;br /&gt;            {&lt;br /&gt;                Type t = this.GetType();&lt;br /&gt;                string fmt;&lt;br /&gt;&lt;br /&gt;                PropertyInfo[] pInfo = t.GetProperties();&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;                sb.Append(t.ToString() + "\r\n");&lt;br /&gt;&lt;br /&gt;                foreach (PropertyInfo p in pInfo)&lt;br /&gt;                {&lt;br /&gt;                    if (p.Name == "Item")&lt;br /&gt;                    {&lt;br /&gt;                        for (int i = 0; i &lt; Count; i++)&lt;br /&gt;                        {&lt;br /&gt;                            fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, new object[] { i }));&lt;br /&gt;                            sb.Append(fmt + "\r\n");&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                    else&lt;br /&gt;                    {&lt;br /&gt;                        fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));&lt;br /&gt;                        sb.Append(fmt + "\r\n");&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            catch (Exception ex)&lt;br /&gt;            {&lt;br /&gt;                log.Error(ex.Message);&lt;br /&gt;            }&lt;br /&gt;&lt;br /&gt;            return sb.ToString();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The items in bold represent the changes to support the indexed properties.  The Details class contains a DetailCollection class (which derives from ArrayList), and the Details class contains an indexer to retrieve an item from the collection as well as a property that returns the number of items stored in the collection.  The modification looks for a property named Item in the Details class, and it then retrieves the count of objects in the collection and for each object in the collection it calls the GetValue(), passing in a reference to the Details class (this) and a new object[] array that contains a single member that stores the integer value of the item within the collection.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115626811712086171?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115626811712086171/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115626811712086171' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115626811712086171'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115626811712086171'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/when-pros-of-using-reflection-outweigh.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115569593734672375</id><published>2006-08-15T19:29:00.000-07:00</published><updated>2006-08-15T19:38:58.560-07:00</updated><title type='text'>Retrieving class property values via reflection</title><content type='html'>Recently I was implementing some logging code for some legacy C# classes that contained many public properties.  Instead of implementing each property in the overriden ToString() of the class, I decided to use reflection to get the list of properties and print out their values:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;  public override string ToString()&lt;br /&gt;  {&lt;br /&gt;   StringBuilder sb = new StringBuilder();&lt;br /&gt;   Type t = this.GetType();&lt;br /&gt;&lt;br /&gt;   PropertyInfo[] pInfo = t.GetProperties();&lt;br /&gt;&lt;br /&gt;   sb.Append(t.ToString() + "\r\n");&lt;br /&gt;&lt;br /&gt;   foreach (PropertyInfo p in pInfo)&lt;br /&gt;   {&lt;br /&gt;    string fmt = string.Format("{0} = {1}", p.Name, p.GetValue(this, null));&lt;br /&gt;&lt;br /&gt;    sb.Append(fmt + "\r\n");&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   return sb.ToString();&lt;br /&gt;  }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The code first gets the Type of the class that contains the properties.  Then it retrieves an array of PropertyInfo objects that contains each property name and type.    The GetValue method of the PropertyInfo class is used to retrieve the value of the property.  It takes two arguments; the first argument is the pointer to the class that contains the property, and the second value is an object array in the case that the property is an indexed property (stores an indexed array).  if the class does not contain any indexed properties, you can pass in null for the second parameter.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115569593734672375?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115569593734672375/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115569593734672375' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115569593734672375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115569593734672375'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/retrieving-class-property-values-via.html' title='Retrieving class property values via reflection'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115568504467876411</id><published>2006-08-15T16:37:00.000-07:00</published><updated>2006-08-15T17:19:25.100-07:00</updated><title type='text'>log4net setup for .NET 2.0</title><content type='html'>For some reason, even though setting up log4net is relatively simple, I always spend too much time trying to configure it for various types of applications (Web, Console, Web Service, Windows Service, Windows App), and after I figure it out, I forget to document what I did to get it working.  Here's an attempt to do this.&lt;br /&gt;&lt;br /&gt;Console Apps:&lt;br /&gt;First, you need to download log4net.  You can get it from the &lt;a href="http://logging.apache.org/log4net/downloads.html"&gt;log4net Downloads&lt;/a&gt; page.&lt;br /&gt;&lt;br /&gt;Once you've installed it, add a reference to it from your project that will perform the logging.  The location of the log4net.dll for 2.0 on my machine is at C:\log4net\log4net-1.2.10\bin\net\2.0\release&lt;br /&gt;&lt;br /&gt;Add a section in the configSections area of the hosting applications' app.config or web.config file:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net"/&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Add the log4net configuration settings to the app.config:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;log4net&amp;gt;&lt;br /&gt;  &amp;lt;!-- RollingFileAppender looks after rolling over files by size or date --&amp;gt;&lt;br /&gt;  &amp;lt;appender name="RollingFileAppender" type="log4net.Appender.RollingFileAppender"&amp;gt;&lt;br /&gt;    &amp;lt;param name="File" value="c:\\Logs\\RollingLogHelloWorld.log"&amp;gt;&lt;br /&gt;    &amp;lt;param name="AppendToFile" value="true"&amp;gt;&lt;br /&gt;    &amp;lt;param name="MaxSizeRollBackups" value="10"&amp;gt;&lt;br /&gt;    &amp;lt;param name="MaximumFileSize" value="1000"&amp;gt;&lt;br /&gt;    &amp;lt;param name="RollingStyle" value="Size"&amp;gt;&lt;br /&gt;    &amp;lt;param name="StaticLogFileName" value="true"&amp;gt;&lt;br /&gt;    &amp;lt;layout type="log4net.Layout.PatternLayout"&amp;gt;&lt;br /&gt;      &amp;lt;param name="ConversionPattern" value="%d [%t] %-5p %-45c [%x] - %m%n"&amp;gt;&lt;br /&gt;    &amp;lt;/layout&amp;gt;&lt;br /&gt;  &amp;lt;/appender&amp;gt;&lt;br /&gt;  &amp;lt;!-- FileAppender appends to a log and it is manually managed or size --&amp;gt;&lt;br /&gt;  &amp;lt;appender name="FileAppender" type="log4net.Appender.FileAppender"&amp;gt;&lt;br /&gt;    &amp;lt;param name="File" value="c:\\Logs\\LogHelloWorld.log"&amp;gt;&lt;br /&gt;    &amp;lt;!-- Example using environment variables in params --&amp;gt;&lt;br /&gt;    &amp;lt;!-- &amp;lt;param name="File" value="${TMP}\\ApplicationKit.log"&amp;gt; --&amp;gt;&lt;br /&gt;    &amp;lt;param name="AppendToFile" value="true"&amp;gt;&lt;br /&gt;    &amp;lt;layout type="log4net.Layout.PatternLayout"&amp;gt;&lt;br /&gt;      &amp;lt;param name="ConversionPattern" value="%d [%t] %-5p %c [%x] - %m%n"&amp;gt;&lt;br /&gt;    &amp;lt;/layout&amp;gt;&lt;br /&gt;  &amp;lt;/appender&amp;gt;&lt;br /&gt;  &amp;lt;!-- Setup the root category, add the appenders and set the default level --&amp;gt;&lt;br /&gt;  &amp;lt;root&amp;gt;&lt;br /&gt;    &amp;lt;level value="INFO"&amp;gt;&lt;br /&gt;    &amp;lt;appender-ref ref="FileAppender"&amp;gt;&amp;lt;/appender-ref&amp;gt;&lt;br /&gt; &amp;lt;/level&amp;gt;&lt;br /&gt;&amp;lt;/root&amp;gt;&lt;br /&gt;&amp;lt;/log4net&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This configures log4net to use one or more appenders, either a RollingFileAppender or a FileAppender.  The &amp;lt;root&amp;gt; element defines which file appender it will use.&lt;br /&gt;&lt;br /&gt;The log files are created in the c:\Logs directory.  Make sure that the process that hosts the classes that perform the logging (classes contained either within the exe or within a class library dll) has write access to the directory where files are created.  For windows and console applications the user identity is the current logged in user that executes the console application.  For windows services, the user identity is the user that the service is configured to run as.  For ASP.NET applications, give the ASPNET user access Full control rights to the webroot folder (the physical folder location for the virtual directory of the app) for the application. This will allow the aspnet_wp.exe process to create/write/update the log file&lt;br /&gt;&lt;br /&gt;You can also add a switch that will output log4net's debug information to the Visual Studio output debug window as an appSetting:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&amp;lt;appsettings&amp;gt;&lt;br /&gt;  &amp;lt;add key="log4net.Internal.Debug" value="true"&amp;gt;&lt;br /&gt;&amp;lt;/add&amp;gt;&lt;br /&gt;&amp;lt;/appsettings&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you have an AssemblyInfo.cs file in your project, you should add an entry to it which will configure the logging framework:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;[assembly: log4net.Config.DOMConfigurator()]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Alternatively, you can put the initialization function into your code, you should execute the following line when the application first starts:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;log4net.Config.XmlConfigurator.Configure();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;In each class that will perform logging, add the following using statements:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;using log4net;&lt;br /&gt;using log4net.Config;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Add the following static member variable to each class, replacing &amp;lt;class name=""&amp;gt; with the name of the class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;private static readonly ILog log = LogManager.GetLogger(typeof (&amp;lt;class name=""&amp;gt;));&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;when you want to log something, you can try this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;log.Info("Hello World.");&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115568504467876411?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115568504467876411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115568504467876411' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115568504467876411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115568504467876411'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/log4net-setup-for-net-20.html' title='log4net setup for .NET 2.0'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115535251900262499</id><published>2006-08-11T20:14:00.000-07:00</published><updated>2006-08-11T20:15:19.183-07:00</updated><title type='text'>Good Read on writing maintainable code</title><content type='html'>&lt;a href="http://advogato.org/article/258.html"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115535251900262499?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115535251900262499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115535251900262499' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115535251900262499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115535251900262499'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/good-read-on-writing-maintainable-code.html' title='Good Read on writing maintainable code'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115534962963953938</id><published>2006-08-11T19:25:00.000-07:00</published><updated>2006-08-11T19:27:10.216-07:00</updated><title type='text'>Network Sequence Diagrams</title><content type='html'>I stumbled upon some HTTP and TCP sequence diagrams at the EventHelix site.  They also have some interesting articles related to real time and embedded system design.  You can find them &lt;a href="http://www.eventhelix.com/RealtimeMantra/"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115534962963953938?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115534962963953938/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115534962963953938' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115534962963953938'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115534962963953938'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/network-sequence-diagrams.html' title='Network Sequence Diagrams'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115446891030360477</id><published>2006-08-01T14:48:00.000-07:00</published><updated>2006-08-01T14:50:38.736-07:00</updated><title type='text'>Problems undeploying an assembly in BizTalk 2004</title><content type='html'>﻿If you ever get this error when undeploying a pipeline or schema assembly in BizTalk 2004:&lt;br /&gt;&lt;br /&gt;Some items in the removed assembly are still being used by items not&lt;br /&gt;defined in the same assembly, thus removal of the assembly failed.&lt;br /&gt;Make sure that items in the assembly you are trying to remove fulfill the&lt;br /&gt;following conditions:&lt;br /&gt;&lt;br /&gt;1. Pipelines, maps, and schemas are not being used by Send Ports or Receive&lt;br /&gt;Locations&lt;br /&gt;2. Roles have no enlisted parties.&lt;br /&gt;&lt;br /&gt;Try the following:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Don't forget to write down what the current settings are, once you've undeployed and redeployed the assemblies, you'll need to update the settings that you changed to their original values. &lt;/span&gt; &lt;br /&gt;&lt;br /&gt;    * Change the send ports send pipeline in the Visual Studio BizTalk Explorer (Edit | Configuration | Send | General) to reference the default Microsoft.BizTalk.DefaultPipelines.PassThru&lt;br /&gt;    * Remove all outbound maps that are associated with the send port in the Visual Studio BizTalk Explorer (Edit | Configuration | Filters &amp; Maps | Outbound Maps)&lt;br /&gt;    * Check that your roles do not have enlisted parties.&lt;br /&gt;&lt;br /&gt;doing these steps should allow you to undeploy the assemblies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115446891030360477?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115446891030360477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115446891030360477' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115446891030360477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115446891030360477'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/08/problems-undeploying-assembly-in.html' title='Problems undeploying an assembly in BizTalk 2004'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115413108961879257</id><published>2006-07-28T16:49:00.000-07:00</published><updated>2006-07-28T16:59:21.286-07:00</updated><title type='text'>Visual Studio 2005 and ExpansionsXML.xml</title><content type='html'>In Visual Studio 2005, I started to notice excessive disk activity when I saved one or more files.  So, I installed File Monitor from &lt;a href="http://www.sysinternals.com"&gt;Sysinternals&lt;/a&gt; and I noticed that when I saved my files, that the monitor reported that a lot of operations were performed on a file called ExpansionsXML.xml in the C:\Documents and Settings\&lt;User&gt;\Local Settings\Application Data\Microsoft\VisualStudio\8.0\1033 directory.  This file is used to store code snippets, and I wasn't able to find a way to turn off the code snippets, so I I googled around for a bit, and I found a news posting that addressed the problem.  So the temporary fix is to make the ExpansionsXML.xml file read-only.  I did that and no more disk thrashing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115413108961879257?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115413108961879257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115413108961879257' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115413108961879257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115413108961879257'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/07/visual-studio-2005-and.html' title='Visual Studio 2005 and ExpansionsXML.xml'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-115178781569003030</id><published>2006-07-01T14:01:00.000-07:00</published><updated>2006-07-28T17:04:16.053-07:00</updated><title type='text'>CopySourceAsHtml</title><content type='html'>There's a cool tool for Visual Studio 2005 that allows you to copy ans paste code as&lt;br /&gt;HTML.  Very usefull when copying/pasting from Visual Studio into a blog entry.  &lt;br /&gt;&lt;br /&gt;You can get it &lt;a href="http://www.jtleigh.com/CopySourceAsHtml"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;{\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Courier New;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs20    \cf2 public\cf0  \cf2 interface\cf0  \cf10 ISpecification\par ??\cf0     \{\par ??       \cf2 bool\cf0  isSatisfiedBy(\cf2 object\cf0  candidate);\par ??    \}\par ??\par ??    \cf2 public\cf0  \cf2 class\cf0  \cf10 LogicalAnd\cf0  : \cf10 ISpecification\par ??\cf0     \{\par ??        \cf2 public\cf0  \cf2 bool\cf0  isSatisfiedBy(\cf2 object\cf0  candidate)\par ??        \{\par ??            \cf2 throw\cf0  \cf2 new\cf0  \cf10 Exception\cf0 (\cf13 "The method or operation is not implemented."\cf0 );\par ??        \}\par ??    \}}&lt;br /&gt;--&gt;&lt;br /&gt;&lt;div style="font-family: Courier New; font-size: 10pt; color: black; background: white;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;7&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;interface&lt;/span&gt; &lt;span style="color: teal;"&gt;ISpecification&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;8&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;9&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; isSatisfiedBy(&lt;span style="color: blue;"&gt;object&lt;/span&gt; candidate);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;10&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;11&lt;/span&gt;&amp;nbsp;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;12&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; &lt;span style="color: teal;"&gt;LogicalAnd&lt;/span&gt; : &lt;span style="color: teal;"&gt;ISpecification&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;13&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;14&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;public&lt;/span&gt; &lt;span style="color: blue;"&gt;bool&lt;/span&gt; isSatisfiedBy(&lt;span style="color: blue;"&gt;object&lt;/span&gt; candidate)&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;15&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;16&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue;"&gt;throw&lt;/span&gt; &lt;span style="color: blue;"&gt;new&lt;/span&gt; &lt;span style="color: teal;"&gt;Exception&lt;/span&gt;(&lt;span style="color: maroon;"&gt;"The method or operation is not implemented."&lt;/span&gt;);&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;17&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: #2b91af;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;18&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-115178781569003030?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/115178781569003030/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=115178781569003030' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115178781569003030'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/115178781569003030'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2006/07/copysourceashtml.html' title='CopySourceAsHtml'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-112802125142281687</id><published>2005-09-29T12:06:00.000-07:00</published><updated>2005-09-29T12:14:35.666-07:00</updated><title type='text'>How to become a hacker</title><content type='html'>Nat Friedman has a great post on what it takes to become a decent programmer:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://nat.org/2005/september/#How%20to%20become%20a%20hacker"&gt;How to become a hacker&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I agree with all of his points, especially the paragraph where he mentions that experienced programmers write easy to read code.  I can agree with him since, I remember when I was first starting my career that I would try to come up with "elegant" solutions which in hindsight they were not elegant but they were more complex than what was needed to solve the problem.  As I my skillset matured, I always tried to come up with a solution that is simple enough to solve the problem.  I don't always succeed, but it is worth the effort, especially when you have to revisit your code months later and attempt to fix a bug, and you find a fairly simple to read codebase instead of a over designed mess of curly braces.  Make the solution as simple as it needs to be but not more simple than that (or whatever Einstein said).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-112802125142281687?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/112802125142281687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=112802125142281687' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112802125142281687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112802125142281687'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/09/how-to-become-hacker.html' title='How to become a hacker'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-112535449208560602</id><published>2005-08-29T15:26:00.000-07:00</published><updated>2005-08-29T15:28:12.090-07:00</updated><title type='text'>Dynamic Code Execution</title><content type='html'>Both Eric Gunnerson and Joel Pobar have written about executing code dynamically:&lt;br /&gt;&lt;br /&gt;http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp02172004.asp&lt;br /&gt;&lt;br /&gt;http://msdn.microsoft.com/msdnmag/issues/05/07/Reflection/default.aspx&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-112535449208560602?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/112535449208560602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=112535449208560602' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112535449208560602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112535449208560602'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/08/dynamic-code-execution.html' title='Dynamic Code Execution'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-112492611621910791</id><published>2005-08-24T16:24:00.000-07:00</published><updated>2005-08-24T16:28:36.226-07:00</updated><title type='text'>Investment Books</title><content type='html'>Over at &lt;a href="http://www.deadprogrammer.com"&gt;Deadprogrammer's Cafe&lt;/a&gt; he mentions a few books about the stock market/wall street that are good reads:&lt;br /&gt;&lt;br /&gt;"A Random Walk Down Wall Street"&lt;br /&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0393325350/ref%3Dnosim/organfocuscom/103-0852232-6188660"&gt;&lt;img src="http://images.amazon.com/images/P/0393325350.01._BO2,204,203,200_PIsitb-dp-500-arrow,TopRight,45,-64_AA240_SH20_SCLZZZZZZZ_.jpg"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"Liar's Poker"&lt;br /&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/0140143459/ref%3Dnosim/organfocuscom/103-0852232-6188660"&gt;&lt;img src="http://images.amazon.com/images/P/0140143459.01._BO2,204,203,200_PIsitb-dp-500-arrow,TopRight,45,-64_AA240_SH20_SCLZZZZZZZ_.jpg"&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"Ugly Americans"&lt;br /&gt;&lt;a href="http://www.amazon.com/exec/obidos/ASIN/006057500X/ref%3Dnosim/organfocuscom/103-0852232-6188660"&gt;&lt;img src="http://images.amazon.com/images/P/006057500X.01._BO2,204,203,200_PIsitb-dp-500-arrow,TopRight,45,-64_AA240_SH20_SCLZZZZZZZ_.jpg"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-112492611621910791?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/112492611621910791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=112492611621910791' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112492611621910791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112492611621910791'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/08/investment-books.html' title='Investment Books'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-112431176880628945</id><published>2005-08-17T13:49:00.000-07:00</published><updated>2005-08-17T13:49:28.813-07:00</updated><title type='text'>Testing a post from Word</title><content type='html'>Testing a post from Word to Blogger:&lt;br/&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;abstract class&amp;nbsp;&amp;nbsp;ProcessorWorker&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected string _url;&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;protected static string _results;&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public ProcessorWorker()&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;public virtual void Run()&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine(string.Format("Results: {0}", _results));&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.ReadLine();&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/span&gt;&lt;br/&gt;&lt;span style="font-family:Verdana;font-size:85%;"&gt;&lt;/span&gt;&lt;br/&gt;Just a Test.&lt;br/&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-112431176880628945?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/112431176880628945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=112431176880628945' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112431176880628945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112431176880628945'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/08/testing-post-from-word.html' title='Testing a post from Word'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-112370879706999193</id><published>2005-08-10T14:19:00.000-07:00</published><updated>2005-08-10T14:19:57.073-07:00</updated><title type='text'>.NET XML Performance Tips</title><content type='html'>A link that offers some tips on using XML in .NET&lt;br /&gt;&lt;br /&gt;http://msdn.microsoft.com/library/en-us/dnpag/html/scalenetchapt09.asp&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-112370879706999193?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112370879706999193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112370879706999193'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/08/net-xml-performance-tips.html' title='.NET XML Performance Tips'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-112370736191385578</id><published>2005-08-10T13:55:00.000-07:00</published><updated>2005-08-10T13:56:01.916-07:00</updated><title type='text'>Interview with Erich Gamma</title><content type='html'>Here he discusses design patterns and tips on becoming a better designer.&lt;br /&gt;&lt;br /&gt;http://www.artima.com/lejava/articles/patterns_practice.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-112370736191385578?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/112370736191385578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=112370736191385578' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112370736191385578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112370736191385578'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/08/interview-with-erich-gamma.html' title='Interview with Erich Gamma'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-112173000056754881</id><published>2005-07-18T16:29:00.000-07:00</published><updated>2005-07-18T16:41:59.180-07:00</updated><title type='text'>Math.Round in .NET</title><content type='html'>The .NET 1.1 Framework Math.Round function uses an interesting rounding algorithm called "Bankers Rounding".  Basically, this means that the numbers are rounded to the nearest &lt;span style="font-style:italic;"&gt;even&lt;/span&gt; number.  So both 5.3 and 5.6 are rounded to the nearest even number, 6.  This is different from the rounding algorithm that we applied in elementary school, which is to round up any number that has a fractional element greater than or equal to .50.  I'm not sure why they did the rounding this way, but we have to live with it.  I did a sample run of some numbers and saw the following when I used Math.Round():&lt;br /&gt;&lt;br /&gt;using Math.Round(numbers[i])&lt;br /&gt;====================&lt;br /&gt;774.10 rounded : 774&lt;br /&gt;774.50 rounded : 774&lt;br /&gt;774.99 rounded : 775&lt;br /&gt;775.10 rounded : 775&lt;br /&gt;775.50 rounded : 776&lt;br /&gt;775.99 rounded : 776&lt;br /&gt;775.15 rounded : 775&lt;br /&gt;775.55 rounded : 776&lt;br /&gt;&lt;br /&gt;As you can see, 774.50 was rounded to 774 (the nearest whole even number to 774.50).&lt;br /&gt;&lt;br /&gt;Apparently, the string.Format() method actually rounds numbers the normal way, as you can tell from this run:&lt;br /&gt;&lt;br /&gt;using string.Format("{0:n0}", numbers[i])&lt;br /&gt;=========================================&lt;br /&gt;774.10 rounded : 774&lt;br /&gt;774.50 rounded : 775&lt;br /&gt;774.99 rounded : 775&lt;br /&gt;775.10 rounded : 775&lt;br /&gt;775.50 rounded : 776&lt;br /&gt;775.99 rounded : 776&lt;br /&gt;775.15 rounded : 775&lt;br /&gt;775.55 rounded : 776&lt;br /&gt;&lt;br /&gt;Here, all of the numbers with fractional values less than .50 are rounded down to the nearest whole number, while numbers with fractional values greater than .50 are rounded up to the nearest whole number.  &lt;br /&gt;&lt;br /&gt;Version 2.0 of the framework will provide the ability to specify the type of rounding algorithm to use with the Math.Round() method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-112173000056754881?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/112173000056754881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=112173000056754881' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112173000056754881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/112173000056754881'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/07/mathround-in-net.html' title='Math.Round in .NET'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-111531428508147406</id><published>2005-05-05T10:29:00.000-07:00</published><updated>2005-05-05T10:31:25.110-07:00</updated><title type='text'>Microsoft Connected Systems Kit</title><content type='html'>I was a member of the team that helped write Microsoft's Connected Systems Kit.  I focused on the BizTalk components.  Check it out here &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=F8DCF367-0624-4BA2-80FE-6CB05D3C1DC7&amp;displaylang=en"&gt;Connected Systems Kit&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-111531428508147406?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/111531428508147406/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=111531428508147406' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111531428508147406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111531428508147406'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/05/microsoft-connected-systems-kit.html' title='Microsoft Connected Systems Kit'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-111111084902399997</id><published>2005-03-17T17:41:00.000-08:00</published><updated>2005-03-17T17:54:09.026-08:00</updated><title type='text'>URL Rewriting</title><content type='html'>You can redirect users to a URL by using URL Rewriting in ASP.NET.  To accomplish this, you can use a HttpModule that Scott Mitchell wrote to perform the redirects based on mapping rules configured in web.config for the web application.  His article on this is here: &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/urlrewriting.asp"&gt;URL Rewriting with ASP.NET&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;One thing that you might want to do is to allow users to navigate your site by using directory-only URL's like this: http://localhost/Products, which should redirect them to the http://localhost/Products/inventory.aspx page.  IIS processes requests for directory-only URLs by first determining if the directory exists, and if it does, it then checks to see if the directory contains a default document.  By default, the following files are default documents for directories: default.htm, default.asp, index.htm and iisstart.asp.  If the directory does not contain one of the default files, IIS will issue a 403 Forbidden error.  To require IIS to process the directory request for a directory that only contains the default.aspx file, you will need to add the default.aspx document to the default documents property via the property page for the virtual directory.  Once this is done, you can add a rule to redirect /Products/default.aspx to /Products/inventory.aspx as described in Scott's article.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-111111084902399997?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/111111084902399997/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=111111084902399997' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111111084902399997'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111111084902399997'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/03/url-rewriting.html' title='URL Rewriting'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-111110992834124777</id><published>2005-03-17T17:01:00.000-08:00</published><updated>2005-03-17T17:38:48.343-08:00</updated><title type='text'>Variable scope and Debug vs. Release builds</title><content type='html'>Lately, I was debugging some code when I came across this little gem in global.asax.cs:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;protected void Application_Start(Object sender, EventArgs e)&lt;br /&gt;{&lt;br /&gt;  StartTimer();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public void StartTimer()&lt;br /&gt;{&lt;br /&gt;  string METHODNAME = "StartTimer";&lt;br /&gt;  &lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    TimerCallback tcallback = new TimerCallback(TimerMethod);&lt;br /&gt;   &lt;br /&gt;    Timer timer = new Timer(tcallback, null, new TimeSpan(0, 0, 1), new TimeSpan(0, 0, 10));&lt;br /&gt;  }&lt;br /&gt;  catch (Exception ex)&lt;br /&gt;  {&lt;br /&gt;    System.Diagnostics.Debug(ex.Message);   &lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The code basically starts a timer when the web application starts (when the first web page request is issued by a client).  The timer fired fine during debugging, but when I ran the web app without debugging, the timer didn't fire.  I did fix the issue by scoping the timer object at the Global class level, rather than as a local variable within the StartTimer() mehtod (the timer object was only visible in StartTimer), but I wanted to find out why the debug build exhibited different behavior from the Release build.  I stumbled across Mike Tautly's weblog &lt;a href="http://mtaulty.com/blog/archive/2005/02/17/1496.aspx"&gt;On Garbage Collection, Scope and Object Lifetimes &lt;/a&gt; and he describes one reason for the issue: The JIT optimization will determine how long local variables are kept around before being garbage collected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-111110992834124777?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/111110992834124777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=111110992834124777' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111110992834124777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111110992834124777'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/03/variable-scope-and-debug-vs-release.html' title='Variable scope and Debug vs. Release builds'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-111084327372670408</id><published>2005-03-14T15:33:00.000-08:00</published><updated>2005-03-14T15:34:33.726-08:00</updated><title type='text'>This page provides a good introduction to Page-User Control communication</title><content type='html'>http://www.openmymind.net/communication/index.html&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-111084327372670408?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/111084327372670408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=111084327372670408' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111084327372670408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111084327372670408'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/03/this-page-provides-good-introduction.html' title='This page provides a good introduction to Page-User Control communication'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-111057311640587245</id><published>2005-03-11T11:38:00.000-08:00</published><updated>2005-03-11T12:31:56.406-08:00</updated><title type='text'>Differences between Type.GetType() and typeof</title><content type='html'>Suzanne Cook has a good explanation for why GetType() only searches the current assembly in addition to mscorlib.dll when it tries to find a type.&lt;br /&gt;&lt;br /&gt;http://blogs.msdn.com/suzcook/archive/2003/05/30/57158.aspx&lt;br /&gt;&lt;br /&gt;You can use typeof() which will search all loaded assemblies within the current app domain.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-111057311640587245?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/111057311640587245/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=111057311640587245' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111057311640587245'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/111057311640587245'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/03/differences-between-typegettype-and.html' title='Differences between Type.GetType() and typeof'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-110996476792428244</id><published>2005-03-04T11:25:00.000-08:00</published><updated>2005-03-04T11:32:47.926-08:00</updated><title type='text'>"The dependency whatever.dll cannot be copied to the run directory because it would conflict with the dependancy..."</title><content type='html'>If you ever get a message along the lines of:&lt;br /&gt;&lt;br /&gt;Warning: The dependency 'Foo, Version=1.0.1661.21305, Culture=neutral' in project 'Bar' cannot be copied to the run directory because it would overwrite the reference 'Foo, Version=1.0.1661.20048, Culture=neutral'&lt;br /&gt;&lt;br /&gt;You can check out Scott Hanselman's site here for some tips:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.hanselman.com/blog/TheDependencyWhateverdllCannotBeCopiedToTheRunDirectoryBecauseItWouldConflictWithTheDependancy.aspx"&gt;Dependency Conflicts&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In addition, you can also check the dependency list using ILDASM.  If you open each dependent DLL in ILDASM and inspect the manifest, looking for references to 'Foo', you should be able to track down the assembly that is referencing the old assembly (in this case the 1.0.1661.20048 version of Foo).  Usually the assembly is referencing a different version of the conflicting DLL (or the assembly is referencing multiple versions of the same DLL).  Once you find the assembly, you can rebuild it or delete it from the bin directory and re-reference it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-110996476792428244?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/110996476792428244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=110996476792428244' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110996476792428244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110996476792428244'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/03/dependency-whateverdll-cannot-be.html' title='&quot;The dependency whatever.dll cannot be copied to the run directory because it would conflict with the dependancy...&quot;'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-110980513460237618</id><published>2005-03-02T14:48:00.000-08:00</published><updated>2005-03-02T16:07:07.300-08:00</updated><title type='text'>Programatically POST xml to a page</title><content type='html'>In .NET you can use the HttpWebRequest class to make page requests.  The HttpWebRequest class supports the GET and POST verbs.  Suppose that you wanted to retrieve xml from a page by issuing a GET request for the page http://localhost/Test/Default.aspx?Name=Test&amp;Email=Test.  You could do this with the following code:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;string uriString = "http://localhost/Test/Default.aspx?Name=Test&amp;Email=Test";&lt;br /&gt;HttpWebRequest httpRequest = null;&lt;br /&gt;HttpWebResponse response = null;&lt;br /&gt;&lt;br /&gt;string xml = "";&lt;br /&gt;Uri uri = new Uri(uriString);&lt;br /&gt;httpRequest = (HttpWebRequest)WebRequest.Create(uri);&lt;br /&gt;response = (HttpWebResponse)request.GetResponse( );&lt;br /&gt;&lt;br /&gt;if (response != null)&lt;br /&gt;{&lt;br /&gt;  Stream responseStream = response.GetResponseStream( );&lt;br /&gt;  StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);&lt;br /&gt;&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    xml = reader.ReadToEnd( );&lt;br /&gt;  }&lt;br /&gt;  finally&lt;br /&gt;  {&lt;br /&gt;    reader.Close( );&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will return the xml string into the xml variable.&lt;br /&gt;&lt;br /&gt;Now suppose that you wanted to POST xml to the same web page.  You can either post the xml directly to the page, or you could put the xml into a form variable and post it to the page.  To post the xml as part of the form (in the 'BodyText' variable), you could do this:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;XmlDocument xmlDoc = new XmlDocument();&lt;br /&gt;xmlDoc.Load("test.xml");&lt;br /&gt;body = xmlDoc.OuterXml;&lt;br /&gt;&lt;br /&gt;string uriString = "http://localhost/Test/Default.aspx?Name=Test&amp;Email=Test";&lt;br /&gt;HttpWebRequest httpRequest = null;&lt;br /&gt;HttpWebResponse response = null;&lt;br /&gt;&lt;br /&gt;string xml = "";&lt;br /&gt;Uri uri = new Uri(uriString);&lt;br /&gt;httpRequest = (HttpWebRequest)WebRequest.Create(uri);&lt;br /&gt;&lt;br /&gt;httpRequest.Method = "POST";&lt;br /&gt;postData = HttpUtility.HtmlEncode(postData);&lt;br /&gt;postData = HttpUtility.UrlEncode(postData);&lt;br /&gt;postData = "BodyText=" + postData;&lt;br /&gt;ASCIIEncoding encoding = new ASCIIEncoding();&lt;br /&gt;byte[] bytes = encoding.GetBytes(postData); &lt;br /&gt;httpRequest.ContentLength = postData.Length;&lt;br /&gt;httpRequest.KeepAlive = false;&lt;br /&gt;httpRequest.ContentType = "application/x-www-form-urlencoded";&lt;br /&gt;Stream requestStream = httpRequest.GetRequestStream( );&lt;br /&gt;requestStream.Write(bytes,0,bytes.Length);&lt;br /&gt;requestStream.Close( );&lt;br /&gt;response = (HttpWebResponse)request.GetResponse( );&lt;br /&gt;&lt;br /&gt;if (response != null)&lt;br /&gt;{&lt;br /&gt;  Stream responseStream = response.GetResponseStream( );&lt;br /&gt;  StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);&lt;br /&gt;&lt;br /&gt;  try&lt;br /&gt;  {&lt;br /&gt;    xml = reader.ReadToEnd( );&lt;br /&gt;  }&lt;br /&gt;  finally&lt;br /&gt;  {&lt;br /&gt;    reader.Close( );&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Be careful to not confuse HtmlEncode and UrlEncode.  It seems that even though the content type is set to "application/x-www-form-urlencoded" that you should NOT JUST URL encode the xml string.  The HttpWebRequest object will appear to process the message for &lt;span style="font-style:italic;"&gt;some&lt;/span&gt; characters if the string is UrlEncoded, but for other characters, you will receive a '(500) Internal Server' error (this case is especially for xml strings that contain the &amp;lt; character).  You should first HtmlEncode, then UrlEncode the string, then prefix the form variable.  On the server side, you only have to HtmlDecode the string since the UrlDecoding is automatically done for you.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-110980513460237618?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/110980513460237618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=110980513460237618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110980513460237618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110980513460237618'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/03/programatically-post-xml-to-page.html' title='Programatically POST xml to a page'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-110963466207638093</id><published>2005-02-28T15:28:00.000-08:00</published><updated>2005-02-28T17:27:21.336-08:00</updated><title type='text'></title><content type='html'>If you have an object that you would like to serialize into xml as a string, you can do the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// returns a utf-16 string&lt;br /&gt;XmlSerializer ser = new XmlSerializer(test.GetType());&lt;br /&gt;StringWriter sw = new StringWriter();&lt;br /&gt;ser.Serialize(sw, test);&lt;br /&gt;ret = sw.ToString();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you want to use the above code to return a utf-8 encoded string, you cannot because the StringWriter class does not allow you to set the encoding, the Encoding property is read-only. You might be able to use the XmlTextWriter to serialize the object in utf-8 encoding. One of the overloaded constructors takes a TextWriter as an argument, so I thought that I could create the XmlTextWriter, pass in the StringWriter (which derives from TextWriter), and then set the Encoding property on the constructed XmlTextWriter object. Unfortunately, an Encoding property does not exist on the XmlTextWriter object. The XmlTextWriter has two other constructors, one that takes a Stream and one that takes a filename. Both of the constructors also take an Encoding object as a parameter. Since I do not want to write to a file (I want to write to a string), I will use the constructor that takes a Stream, and pass in a MemoryStream object:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// returns a utf-8 string with a prepended character&lt;br /&gt;MemoryStream memStrmWrite = new MemoryStream();&lt;br /&gt;XmlSerializer ser = new XmlSerializer(test.GetType());&lt;br /&gt;XmlTextWriter xtw = new XmlTextWriter(memStrmWrite, Encoding.UTF8);&lt;br /&gt;ser.Serialize(xtw, test);&lt;br /&gt;memStrmWrite = (MemoryStream)xtw.BaseStream;&lt;br /&gt;UTF8Encoding enc = new UTF8Encoding();&lt;br /&gt;ret = enc.GetString(memStrmWrite.ToArray());&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This does return the xml in the correct encoding, but it also prepends the xml with an byte order mark character (which most XML 1.0+ processors should handle):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;?&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;....&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To get the proper encoded string without the leading extra character, read from the MemoryStream into a StreamReader, and call the StreamReader.ReadToEnd() method, remembering to reset the position of the MemoryStream to zero after the Serialize() method is executed:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;MemoryStream memStrmWrite = new MemoryStream();&lt;br /&gt;XmlSerializer ser = new XmlSerializer(test.GetType());&lt;br /&gt;XmlTextWriter xtw = new XmlTextWriter(memStrmWrite, Encoding.UTF8);&lt;br /&gt;ser.Serialize(xtw, test);&lt;br /&gt;memStrmWrite = (MemoryStream)xtw.BaseStream;&lt;br /&gt;&lt;br /&gt;// Keeps the byte order mark intact&lt;br /&gt;if (_bKeepByteOrderMark == true)&lt;br /&gt;{&lt;br /&gt;   UTF8Encoding enc = new UTF8Encoding();&lt;br /&gt;   ret = enc.GetString(memStrmWrite.ToArray());&lt;br /&gt;}&lt;br /&gt;else&lt;br /&gt;{&lt;br /&gt;   memStrmWrite.Position = 0;  // reset the position to 0&lt;br /&gt;   StreamReader sr = new StreamReader(memStrmWrite, Encoding.UTF8);&lt;br /&gt;   ret = sr.ReadToEnd();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This will remove the byte order mark at the beginning of the xml:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;?xml version="1.0" encoding="utf-8"?&amp;gt;....&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Here are a few links on this:&lt;br /&gt;&lt;br /&gt;http://www.eggheadcafe.com/articles/system.xml.xmlserialization.asp&lt;br /&gt;&lt;br /&gt;http://weblogs.asp.net/rmclaws/archive/2003/07/31/22080.aspx&lt;br /&gt;&lt;br /&gt;http://msdn.microsoft.com/msdnmag/issues/01/05/xml/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-110963466207638093?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/110963466207638093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=110963466207638093' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110963466207638093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110963466207638093'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/02/if-you-have-object-that-you-would-like.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-110505946385898596</id><published>2005-01-06T16:40:00.000-08:00</published><updated>2005-01-06T16:59:50.250-08:00</updated><title type='text'>ASP.NET, IIS6 and SQL Server 2000</title><content type='html'>If you are trying to connect to SQL server using a SQL login/password in the connection string, and you receive the following error:&lt;br /&gt;&lt;br /&gt;Login failed for user '&lt;sql&gt;'. Reason: Not associated with a trusted SQL Server connection.&lt;br /&gt;&lt;br /&gt;Do the following:&lt;br /&gt;&lt;/sql&gt;&lt;ul&gt;   &lt;li&gt;Check the security settings on the SQL Server registration. Right click the server (local), choose the security tab and make sure that the 'SQL Server and Windows' radio button is selected. If it is not, select it, then restart SQL Server.&lt;br /&gt; &lt;/li&gt;   &lt;li&gt;If that doesn't work, check if ASP.NET is doing any kind of impersonation by looking for an impersonation tag in web.config. If the &lt;authentication&gt;authentication tag is set to "Windows" and the &lt;impersonation&gt; impersonation tag is set to "true", then ASP.NET will impersonate the logged in user, which is the user that IIS authenticated (If IIS is set to use Windows authentication). So If my user is DOMAIN\USER, IIS would first perform authentication and then forward the request as well as my security token to the ASP.NET process. If the &lt;authentication&gt; authentication tag is "Windows" and the &lt;impersonation&gt; impersonation tag is "true", the ASP.NET process will impersonate the logged in user (DOMAIN\USER). Any requests (file, network, database) from the ASP.NET process will operate under the identity of this logged in user. If impersonation is not set to true, and IIS authntication is set to anonymous, the ASP.NET process will run as ASPNET for IIS5 or the application pool identity, NT Authority\NetworkService for IIS6.&lt;/impersonation&gt;&lt;/authentication&gt;&lt;/impersonation&gt;&lt;/authentication&gt;&lt;/li&gt; &lt;/ul&gt; More information can be found &lt;a href="http://www.dotnet247.com/247reference/a.aspx?u=http://blogs.bartdesmet.net/bart/archive/2004/07/31.aspx"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-110505946385898596?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/110505946385898596/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=110505946385898596' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110505946385898596'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/110505946385898596'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2005/01/aspnet-iis6-and-sql-server-2000.html' title='ASP.NET, IIS6 and SQL Server 2000'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-109727741941840609</id><published>2004-10-08T16:15:00.000-07:00</published><updated>2004-10-08T16:16:59.420-07:00</updated><title type='text'>Scolbe's nice summary of using the web as a tool</title><content type='html'>awesome summary by Scoble about how people will use the web:&lt;br /&gt;&lt;a href="http://radio.weblogs.com/0001011/2004/10/07.html#a8370"&gt;http://radio.weblogs.com/0001011/2004/10/07.html#a8370&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-109727741941840609?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/109727741941840609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=109727741941840609' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109727741941840609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109727741941840609'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/10/scolbes-nice-summary-of-using-web-as.html' title='Scolbe&apos;s nice summary of using the web as a tool'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-109536897084428342</id><published>2004-09-16T14:07:00.000-07:00</published><updated>2004-09-16T14:09:30.843-07:00</updated><title type='text'>BizTalk 2004 Contest Winners</title><content type='html'>Scott Woodgate has the list of the BizTalk 2004 developers content winners here:&lt;br /&gt;&lt;a href="http://blogs.msdn.com/scottwoo/archive/2004/09/14/229601.aspx"&gt;&lt;br /&gt;http://blogs.msdn.com/scottwoo/archive/2004/09/14/229601.aspx&lt;/a&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-109536897084428342?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/109536897084428342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=109536897084428342' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109536897084428342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109536897084428342'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/09/biztalk-2004-contest-winners.html' title='BizTalk 2004 Contest Winners'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-109519583040021705</id><published>2004-09-14T14:03:00.000-07:00</published><updated>2005-01-20T12:49:15.370-08:00</updated><title type='text'></title><content type='html'>&lt;table cellpadding="1" width="100%"&gt;  &lt;tbody&gt;&lt;tr&gt;&lt;br /&gt;   &lt;td valign="top"&gt;&lt;br /&gt;&lt;h1&gt;Control Events&lt;br /&gt;&lt;/h1&gt;&lt;br /&gt;Controls can have events that are associated with them. Suppose that we had a server control that contained a single button. The button click event could perform some processing directly, or the event could call a function in another client via an exposed public event. If we have a number of different pages that contain the server control on them, each page could hook a function to the event defined in the button. When the button click event is fired, the hook function on the page is called. The page can now determine what happens in response to a click event that occurred on the button within an embedded server control. It is the page's responsibility to wire the button click event to the hook function. Note that the server control (or the button within the control) has no knowledge of what client is consuming it. Each page within the application can determine the behavior of the control event via the exposed hook function on the page. Suppose we had the following in the ascx file for the control:&lt;br /&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;br /&gt;  &amp;lt;table width="100%"&amp;gt;&lt;br /&gt;   &amp;lt;TR&amp;gt;&lt;br /&gt;    &amp;lt;td align="right"&amp;gt;&lt;br /&gt;     &amp;lt;asp:Button id="btnProceed" runat="server" Text="Proceed"&amp;gt;&amp;lt;/asp:Button&amp;gt;&lt;br /&gt;    &amp;lt;/td&amp;gt;&lt;br /&gt;    &amp;lt;td align="left"&amp;gt;&lt;br /&gt;     &amp;lt;asp:Button id="btnCancel" runat="server" Text="Cancel"&amp;gt;&amp;lt;/asp:Button&amp;gt;&lt;br /&gt;    &amp;lt;/td&amp;gt;&lt;br /&gt;   &amp;lt;/TR&amp;gt;&lt;br /&gt;  &amp;lt;/table&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;In the code behind for the control we would define two EventHandlers, one for each button:&lt;br /&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;br /&gt;  public event EventHandler Proceed;&lt;br /&gt;  public event EventHandler Cancel;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;The button events would then forward to the hook method associated with the Proceed, or Cancel event objects.&lt;br /&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;br /&gt;  private void btnProceed_Click(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   Proceed(this, e);&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  private void btnCancel_Click(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   Cancel(this, e);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;The page that contains the control, sets the OnProceed and OnCancel events on the control to the hook functions in the code-behind of the page:&lt;br /&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;br /&gt;  &amp;lt;%@ Register TagPrefix="ctrl" TagName="Buttons" Src="Buttons.ascx" %&amp;gt;&lt;br /&gt; &lt;br /&gt;  ...&lt;br /&gt; &lt;br /&gt;  &amp;lt;ctrl:buttons id="NavigateButtons" runat="server" OnProceed="Page_Proceed" OnCancel="Page_Cancel"&amp;gt;&amp;lt;/ctrl:buttons&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;The code behind of the page contains the hook functions Page_Proceed and Page_Cancel. Note that the hook functions are protected. The generated class that derives from the code behind will need to access the two hook functions, so they are declared with protected visibility.&lt;br /&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;br /&gt;  protected void Page_Proceed(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   &lt;a href="http:///"&gt;//&lt;/a&gt; do something for proceed&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  protected void Page_Cancel(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   &lt;a href="http:///"&gt;//&lt;/a&gt; do something for cancel&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;When the aspx page is parsed and the dynamic class is generated, the control properties OnProceed and OnCancel are translated into the following code (in the generated page class):&lt;br /&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;br /&gt;  NavigateButtons.Proceed += new EventHandler(this.Page_Proceed);&lt;br /&gt;  NavigateButtons.Cancel += new EventHandler(this.Page_Cancel);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;When the Button1_Click event in the control fires, the Page_Proceed method is called in the page. Each page can now define hook methods that should be called when the button click events on the contained control are fired. Each page defines the hook functions, and the control tag in the .aspx page is modified to associate the hook methods with events in the control:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Add the EventHandler declarations in the control&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add the hook functions in the parent page that should be called when the event in the control is triggered&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add the server control tag to the .aspx file associated with the page&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add the On... attributes to the server control tag and set the attributes to the appropriate hook function in the page. Make sure that the attribute is named the same as the declared event in the control, prefixed by On. So if the event field in the control is Proceed, the attribute on the control in the .aspx page should be in the format OnProceed="hook function name in page"&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Now each page can define their own hook functions for the Proceed and Cancel events exposed by the control:&lt;br /&gt;&lt;span style="font-family: 'Courier New';"&gt;&lt;br /&gt;  &lt;a href="http:///"&gt;//&lt;/a&gt; page A&lt;br /&gt;  &amp;lt;ctrl:buttons id="NavigateButtons" runat="server" OnProceed="PageA_Proceed" OnCancel="PageA_Cancel"&amp;gt;&amp;lt;/ctrl:buttons&amp;gt;&lt;br /&gt; &lt;br /&gt;  &lt;a href="http:///"&gt;//&lt;/a&gt; page B&lt;br /&gt;  &amp;lt;ctrl:buttons id="NavigateButtons" runat="server" OnProceed="PageB_Proceed" OnCancel="PageB_Cancel"&amp;gt;&amp;lt;/ctrl:buttons&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;The functions within each page (PageA_Proceed, PageB_Proceed) do not have to be named uniquely. Both pages could contain a Page_Proceed and Page_Cancel hook functions, the only difference being that the Page_Proceed and Page_Cancel in each page would perform different operations.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;     &lt;/td&gt;&lt;br /&gt;   &lt;td align="right" nowrap="nowrap" valign="top"&gt;&lt;br /&gt;    &lt;br /&gt;     &lt;/td&gt;&lt;br /&gt;&lt;br /&gt;   &lt;/tr&gt;&lt;br /&gt; &lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-109519583040021705?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/109519583040021705/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=109519583040021705' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109519583040021705'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109519583040021705'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/09/control-events-controls-can-have.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-109519559089008464</id><published>2004-09-14T13:59:00.000-07:00</published><updated>2004-09-14T13:59:50.890-07:00</updated><title type='text'></title><content type='html'>&lt;table width="100%" cellpadding="1"&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td valign="top"&gt;&lt;br /&gt;      &lt;br&gt;&lt;H2&gt;Creating an XML driven web site&lt;BR&gt;&lt;/H2&gt;&lt;BR&gt;An XML driven website is a website that stores the content as XML, either in a file or in a database. When a user requests a page, the XML content is retrieved from the data store and rendered as HTML in the browser. The HTML is usually created by a transformation, such as XSLT, or the HTML can be created programmatically. In either case, the XML data is merged with the markup to create the returned HTML page. &lt;BR&gt;&lt;FONT style="FONT-FAMILY: 'Courier New'"&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public void GetContent(string loc)&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;XmlTextReader reader = null;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;try&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;reader = new XmlTextReader(Server.MapPath(loc));&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (reader != null)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;RenderContent(reader);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;catch(Exception e)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string err = e.ToString();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&lt;/FONT&gt;&lt;BR&gt;&lt;BR&gt;The nodes in an XML stream can be accessed by an XMLDocument, an XMLTextReader/XMLTextWriter and an XPathNavigator. Each method has its advantages and drawbacks: &lt;BR&gt;&lt;br /&gt;&lt;br /&gt;&lt;UL&gt;&lt;br /&gt;&lt;LI&gt;XmlDocument: Provides direct memory access to the entire xml document. Nodes can be selected from the XmlDocument by XPath expressions. Can use a large amount of memory resources. &lt;BR&gt;&lt;br /&gt;&lt;LI&gt;XMLTextReader: Provide forward-only access to an xml stream. The entire xml dataset is not loaded into memory all at once, the XmlTextReader reads in nodes on an as-needed basis. The XMLTextWriter writes xml data to a file in a forward-only manner.&lt;BR&gt;&lt;br /&gt;&lt;LI&gt;XPathNavigator: Provides bi-directional access to nodes in a XmlDocument or XPathDocument. The XPathDocument provides a fast read-only cache for an xml document. If you are using an XmlTextReader to access the xml, an XPathDocument can be created by passing in a XmlTextReader object into the XPathDocument constructor. This object is not created directly, it is returned from a call to the CreateNavigator() method on the XmlDocument/XPathDocument class.&lt;BR&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;BR&gt;&lt;BR&gt;When inserting text into an XML file, beware of the special characters &amp;lt;, &amp;gt;, ', ", &amp;amp;. They should be escaped by using the special notation. &lt;BR&gt;&lt;BR&gt;&lt;BR&gt;When passing XML data in memory you can use the following object types: &lt;BR&gt;&lt;br /&gt;&lt;UL&gt;&lt;br /&gt;&lt;LI&gt;XmlNode. Provides an interface to an in-memory tree representation of an XML document. Gives a R/W interface to the XML data structure in addition to XPath expression selections. The XmlDocument inherits the XmlNode abstract class.&lt;BR&gt;&lt;br /&gt;&lt;LI&gt;XmlReader. Streaming forward only object. Provides an xml facade over an existing object graph/text/binary data object. Difficult to use.&lt;BR&gt;&lt;br /&gt;&lt;br /&gt;&lt;LI&gt;XPathNavigator. Traverses xml in a bi-directional manner. Able to navigate an xml document via XPath expressions. This is the preferred way to pass xml around in the CLR.&lt;BR&gt;&lt;/LI&gt;&lt;/UL&gt;&lt;br&gt;&lt;br /&gt;      &lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;    &lt;td valign="top" align="right" nowrap&gt;&lt;br /&gt;&lt;br /&gt;      &lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;  &lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-109519559089008464?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/109519559089008464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=109519559089008464' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109519559089008464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109519559089008464'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/09/creating-xml-driven-web-sitean-xml.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-109519547112815914</id><published>2004-09-14T13:47:00.000-07:00</published><updated>2004-09-14T13:57:51.130-07:00</updated><title type='text'></title><content type='html'>&lt;table width="100%" cellpadding="1"&gt;&lt;br /&gt;  &lt;tr&gt;&lt;br /&gt;    &lt;td valign="top"&gt;&lt;br /&gt;      &lt;br&gt;&lt;H2&gt;Delegates&lt;BR&gt;&lt;/H2&gt;&lt;BR&gt;Delegates are data types in the .NET framework that reference a method with a specific signature. Delegates are used to execute a method on a class via the created type. The ThreadStart type is an example of a delegate, in this case the ThreadStart delegate references a method that has an empty parameter list. You can create a ThreadStart delegate as follows: &lt;BR&gt;&lt;FONT style="FONT-FAMILY: 'Courier New'"&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;ThreadStart ts = new ThreadStart(DelegateFunction);&lt;BR&gt;&amp;nbsp;&amp;nbsp;Thread t = new Thread(ts);&lt;BR&gt;&amp;nbsp;&amp;nbsp;t.Start();&amp;nbsp;&lt;A href="http://start/"&gt;&lt;a href="//start"&gt;//start&lt;/a&gt;&lt;/A&gt; the thread&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; 1000; i++)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;t.Sleep(5);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;/FONT&gt;&lt;BR&gt;&lt;BR&gt;The ThreadStart class takes a reference to a method that cannot have any input parameters. The DelegateFunction is defined as: &lt;BR&gt;&lt;FONT style="FONT-FAMILY: 'Courier New'"&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public void DelegateFunction()&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http:///"&gt;&lt;a href="//"&gt;//&lt;/a&gt;&lt;/A&gt; Do something...&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;&lt;BR&gt;&lt;/FONT&gt;&lt;BR&gt;&lt;BR&gt;The DelegateFunction is executed when the Thread.Start function is run. In this case, the ThreadStart delegate wraps the method call, so that the method can be called via a type instance. Delegates are used for callback functions, events and as an implicit interface contract. A delegate can reference a function that takes parameters: &lt;BR&gt;&lt;FONT style="FONT-FAMILY: 'Courier New'"&gt;&lt;BR&gt;&amp;nbsp;public delegate string FunctionPointer(int foo, string bar);&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;public FunctionPointer fpi;&amp;nbsp;&lt;BR&gt;&amp;nbsp;fpi = new FunctionPointer(Function);&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&lt;/FONT&gt;&lt;BR&gt;&lt;BR&gt;The Function declaration loooks like this: &lt;BR&gt;&lt;FONT style="FONT-FAMILY: 'Courier New'"&gt;&lt;BR&gt;&amp;nbsp;string Function(int foo, string bar)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;string temp = "";&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; foo; i++)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp += bar;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;return temp;&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&lt;/FONT&gt; The same delegate can point to another function with the same signature &lt;BR&gt;&lt;FONT style="FONT-FAMILY: 'Courier New'"&gt;&lt;BR&gt;&amp;nbsp;string AnotherFunction(int foo, string bar)&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;string temp = "AnotherFunction";&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;for (int i = 0; i &amp;lt; foo; i++)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;temp += bar;&lt;BR&gt;&lt;BR&gt;&amp;nbsp;&amp;nbsp;return temp;&lt;BR&gt;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&lt;/FONT&gt;&lt;BR&gt;&lt;BR&gt;The following is a sample console application that demonstrates delegates. In Main(), the source class and each sink class is created. The source class is the class that will call the function in the sink class via the delegate reference. Each sink class contains a method called Callback that will be called by the source class. To hook up the Callback method in the sink class to the delegate in the source class, a reference to the delegate is created and the name of the callback function in the sink class is passed as a parameter to the delegate reference constructor: &lt;BR&gt;&lt;FONT style="FONT-FAMILY: 'Courier New'"&gt;&lt;BR&gt;&amp;nbsp;using System;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;namespace Delegate&lt;BR&gt;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;class Class1&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;[STAThread]&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;static void Main(string[] args)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SourceClass sc = new SourceClass();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SinkAClass sac = new SinkAClass();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;SinkBClass sbc = new SinkBClass();&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http:///"&gt;&lt;a href="//"&gt;//&lt;/a&gt;&lt;/A&gt; Hook up the function and execute&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sc.fp = new SourceClass.FunctionPointer(sac.Callback);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sc.DoSomething();&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http:///"&gt;&lt;a href="//"&gt;//&lt;/a&gt;&lt;/A&gt; Hook up a new sink&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sc.fp = new SourceClass.FunctionPointer(sbc.Callback);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sc.DoSomething();&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public class SourceClass&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public delegate void FunctionPointer(int arg1, string arg2);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public FunctionPointer fp;&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void DoSomething()&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;A href="http:///"&gt;&lt;a href="//"&gt;//&lt;/a&gt;&lt;/A&gt; call the function pointed to by fp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fp(3, this.ToString());&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public class SinkAClass&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void Callback(int arg1, string arg2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine("{0} Callback method was called with arguments: {1}, {2}", this.ToString(), arg1.ToString(), arg2);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&lt;BR&gt;&amp;nbsp;&amp;nbsp;public class SinkBClass&lt;BR&gt;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public void Callback(int arg1, string arg2)&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console.WriteLine("{0} Callback method was called with arguments: {1}, {2}", this.ToString(), arg1.ToString(), arg2);&lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;&amp;nbsp;}&lt;BR&gt;&amp;nbsp;}&lt;/FONT&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;      &lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;    &lt;td valign="top" align="right" nowrap&gt;&lt;br /&gt;      &lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;  &lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-109519547112815914?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/109519547112815914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=109519547112815914' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109519547112815914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109519547112815914'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/09/delegatesdelegates-are-data-types-in.html' title=''/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-109112232472667074</id><published>2004-07-29T10:30:00.000-07:00</published><updated>2004-07-29T10:32:04.726-07:00</updated><title type='text'>In new york</title><content type='html'>In new York&lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;br /&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-109112232472667074?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/109112232472667074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=109112232472667074' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109112232472667074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109112232472667074'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/07/in-new-york.html' title='In new york'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-109067994704150780</id><published>2004-07-24T07:39:00.000-07:00</published><updated>2004-07-24T07:50:07.423-07:00</updated><title type='text'>Trying to get to London...</title><content type='html'>So my JetBlue flight from Oakland to NY was cancelled due to weather. &lt;br /&gt;So, day one of my vacation will be spent haggling with&amp;nbsp;agents at &lt;br /&gt;airport ticket counters. I was also planning to visit Paris, but I have no time &lt;br /&gt;for that now.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;I was in total shock when I&amp;nbsp;arrived at the airport and found out that my flight was cancelled.&amp;nbsp;&amp;nbsp;There were&amp;nbsp;two later JetBlue flights to NY, but they were delayed.&amp;nbsp; The JetBlue&amp;nbsp;person was nice enough to&amp;nbsp;try to find me a JetBlue flight that would get&amp;nbsp;me to NY in time for my flight to London, but every flight was sold out.&amp;nbsp; So I sat and waited&amp;nbsp;for the JetBlue agent to find me another flight for 3 hours while people around me checked in their bags going to NY.&amp;nbsp; He called my other&amp;nbsp;airline and tried to see if they would change my reservation, but they said that I would either have to&amp;nbsp;fly standby,&amp;nbsp;or pay $1500 for a ticket.&amp;nbsp; So I agreed to go standby to London,&amp;nbsp;and the JetBlue agent refunded my ticket, and&amp;nbsp;purchased another ticket for me on&amp;nbsp;another airline.&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-109067994704150780?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/109067994704150780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=109067994704150780' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109067994704150780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/109067994704150780'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/07/trying-to-get-to-london.html' title='Trying to get to London...'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108948151678461370</id><published>2004-07-10T10:41:00.000-07:00</published><updated>2004-07-10T10:45:16.783-07:00</updated><title type='text'>Summary of WS-* Specifications</title><content type='html'>From the BEA site: &lt;a href="http://dev2dev.bea.com/technologies/soa/xmlmessaging/articles/WS-Security.jsp"&gt;WS Security&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;"&lt;h3&gt;Web Services Security Specifications &lt;/h3&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;WS-Security describes how to attach signature and encryption headers to SOAP messages. In addition, it describes how to attach security tokens, including binary security tokens such as X.509 certificates and Kerberos tickets, to messages. &lt;br /&gt;&lt;li&gt;WS-Policy represents a set of specifications that describe the capabilities and constraints of the security (and other business) policies on intermediaries and endpoints (e.g. required security tokens, supported encryption algorithms, privacy rules) and how to associate policies with services and endpoints. &lt;br /&gt;&lt;li&gt;WS-Trust describes a framework for trust models that enables Web services to securely interoperate by requesting, issuing, and exchanging security tokens. &lt;br /&gt;&lt;li&gt;WS-Privacy will describe a model for how Web services and requestors state privacy preferences and organizational privacy practice statements. &lt;br /&gt;&lt;li&gt;WS-SecureConversation describes how to manage and authenticate message exchanges between parties, including security context exchanges and establishing and deriving session keys. &lt;br /&gt;&lt;li&gt;WS-Federation describes how to manage and broker the trust relationships in a heterogeneous federated environment, including support for federated identities, sharing of attributes, and management of pseudonyms. &lt;br /&gt;&lt;li&gt;WS-Authorization will describe how to manage authorization data and authorization policies. &lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;Additionally, several other key Web services specifications complete the foundation layer of specifications: &lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;WS-Addressing describes how to specify identification and addressing information for messages. &lt;br /&gt;&lt;li&gt;WS-MetadataExchange describes how to exchange metadata such as WS-Policy information and WSDL between services and endpoints. &lt;br /&gt;&lt;li&gt;WS-ReliableMessaging describes how to ensure reliable delivery of messages in the presence of unreliable networks. &lt;br /&gt;&lt;li&gt;WS-Transactions and WS-Coordination describe how to enable transacted operations as part of Web service message exchanges. &lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;The combination of the specifications above and interoperability profiles will enable customers to easily build interoperable secure reliable transacted Web services that integrate within and across federations by composing federation and security specifications with other Web services specifications. "&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108948151678461370?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108948151678461370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108948151678461370' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108948151678461370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108948151678461370'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/07/summary-of-ws-specifications.html' title='Summary of WS-* Specifications'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108923814713640297</id><published>2004-07-07T15:06:00.000-07:00</published><updated>2004-07-07T15:09:07.136-07:00</updated><title type='text'>Retrieving the identity associated with the current Thread</title><content type='html'>Using the System.Threading and System.Security.Principal namespaces, you can obtain the identity of the user associated with the current thread:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);&lt;br /&gt;&lt;br /&gt;IPrincipal wp = Thread.CurrentPrincipal;&lt;br /&gt;IIdentity id = wp.Identity;&lt;br /&gt;&lt;br /&gt;string authType = id.AuthenticationType;&lt;br /&gt;string isAuth = id.IsAuthenticated.ToString();&lt;br /&gt;string name = id.Name;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108923814713640297?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108923814713640297/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108923814713640297' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108923814713640297'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108923814713640297'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/07/retrieving-identity-associated-with_07.html' title='Retrieving the identity associated with the current Thread'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108863786557102538</id><published>2004-06-30T15:54:00.000-07:00</published><updated>2005-03-04T11:36:34.356-08:00</updated><title type='text'>Web Service Security</title><content type='html'>Using the WS-Security you can make your web service communications more secure by using encryption, signing in addition to authentication and authorization.  SOAP Header items can be encrypted using Username (user, passoword), Keberos or X.509 certificates.  Electronic signatures are created using X.509 or Username tokens.&lt;br /&gt;&lt;br /&gt;First, a few definitions:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Use encryption to encode messages sent between the web service client and the web service server.  In the case of a SOAP message, the SOAP body is usually encrypted using a public key (a subset of the private key located on the server) that is located on the client computer.  The message body is encrypted using this key, and it is sent to the server.  The server uses a private key to decode the message.  Messages can use Username tokens or X.509 certificates for encryption.  In the case of the Username token encryption, the Username token is used to encrypt the Soap body of the message on the client, and the Username token is also sent to the server in the Soap header.  Once the server receives the message, the server uses the Username token sent in the header to decrypt the body of the message.  With X.509 certificates, the server uses a private key assigned to it to extract a corresponding public key.  The public key is then used by clients of the web service to encrypt messages sent to the server.  Once the server receives the message, it uses the private key to decrypt the Soap body of the message.  Since X.509 certficiates are used for encryption and not authorization, a Username token (Kerberos token) are still required for authentication and authorization.  In addition to encrypting the body of the message, the Soap header can be encrypted as well.  The entire header can be encrypted (including the username token) using an X.509 certificate.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Use digital signing to mark the message with a unique identifier.  The identifier is usually generated using an X.509 certificate, but a simple Username token can be used to generate a signature.  The signature can be used by the web service to determine the identity of the message sender.  Sending a signature instead of a username &amp; password combination is preferred since no passwords are sent between the client and the web service.  The authentication is based solely on the signature, since the signature was generated using partial information from a certificate on the web service server.  The public key that a client uses to generate the signature is a portion of the private key present on the web server.  If a message is received by a web service that requires signed messages, the web service might decide that the message has been tampered with and will not process the message.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Username, and Keberos tokens can be used for authentication.  The credentials are set by the client and read by the web service.  When using Username tokens, passwords can be sent in either plain text or as hashes (digest).  It is up to the web service to determine what type of tokens it will use, and the client must send compatible tokens to the server.  The server can create policies which dictate what type of tokens are valid for authentication.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Username tokens can also be used for authorization.  If a client sends a username token to a web service, the web service will unencrypt the token and pass the token to the OS for authentication.  If the authentication fails, an error is returned to the client.  If the authentication succeeds, the WSE framework will check to see if the authenticated username token is authorized to access the requested resource (the web method the client is attempting to execute).  If the token is not authorized access, an error is returned to the client.  If the token is authorized access to the resource, the requested web method is executed and the results are returned to the client.&lt;br /&gt;&lt;br /&gt;Authorization can be implemented in two ways:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Use WS-Policy to setup policies that are required by the web service.  Each web service (.asmx) can be associated with one or more policies.  A policy can be setup to allow only users in the Domain\Group access to the web methods exposed by the web service.  To authorize access to the web methods in the web service, the WSE framework will first try to authenticate via the username token, and then it will determine if the role defined in the policy (in policyConfig.Cache) is in the list of roles associated with the username token.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Programmatically send Username tokens to the web service.  The client would create a UsernameToken object from the user credentials and add the token to the RequestSoapContext.Security.Tokens collection.  The web server would then read the UsernameToken and authenticate the token.  Once the token was authenticated, the web service could determine if the roles in the token include the required role defined in the web service and if so, authorize access to the requested resource.  You could also intercept the authentication process by deriving a class from UsernameTokenManager and overriding the AuthenticateToken() method to look up the roles (in a DB) associated with the user in the token and add those roles to the principal associated with the token.  The web service would then retrieve the token from the SoapContext.Security.Tokens collection and compare the required role to execute the web service with the role list from the token.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;table&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Usage&lt;/td&gt;&lt;td&gt;Username&lt;/td&gt;&lt;td&gt;X.509&lt;/td&gt;&lt;td&gt;Kerberos&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Signing&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;N&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Encryption&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;N&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Authentication&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;N&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;br /&gt;&lt;td&gt;Authorization&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;td&gt;N&lt;/td&gt;&lt;td&gt;Y&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108863786557102538?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108863786557102538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108863786557102538' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108863786557102538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108863786557102538'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/06/web-service-security.html' title='Web Service Security'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108810616122933785</id><published>2004-06-24T12:40:00.000-07:00</published><updated>2004-06-24T12:42:41.230-07:00</updated><title type='text'>Control Events</title><content type='html'>Controls can have events that are associated with them. Suppose that we had a server control that contained a single button. The button click event could perform some processing directly, or the event could call a function in another client via an exposed public event. If we have a number of different pages that contain the server control on them, each page could hook a function to the event defined in the button. When the button click event is fired, the hook function on the page is called. The page can now determine what happens in response to a click event that occurred on the button within an embedded server control. It is the page's responsibility to wire the button click event to the hook function. Note that the server control (or the button within the control) has no knowledge of what client is consuming it. Each page within the application can determine the behavior of the control event via the exposed hook function on the page. Suppose we had the following in the ascx file for the control:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &lt;table width="100%"&gt;&lt;br /&gt;   &lt;TR&gt;&lt;br /&gt;    &lt;td align="right"&gt;&lt;br /&gt;     &lt;asp:Button id="btnProceed" runat="server" Text="Proceed"&gt;&lt;/asp:Button&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;    &lt;td align="left"&gt;&lt;br /&gt;     &lt;asp:Button id="btnCancel" runat="server" Text="Cancel"&gt;&lt;/asp:Button&gt;&lt;br /&gt;    &lt;/td&gt;&lt;br /&gt;   &lt;/TR&gt;&lt;br /&gt;  &lt;/table&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the code behind for the control we would define two EventHandlers, one for each button:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public event EventHandler Proceed;&lt;br /&gt;  public event EventHandler Cancel;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The button events would then forward to the hook method associated with the Proceed, or Cancel event objects.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  private void btnProceed_Click(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   Proceed(this, e);&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  private void btnCancel_Click(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   Cancel(this, e);&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The page that contains the control, sets the OnProceed and OnCancel events on the control to the hook functions in the code-behind of the page:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &lt;%@ Register TagPrefix="ctrl" TagName="Buttons" Src="Buttons.ascx" %&gt;&lt;br /&gt;  &lt;br /&gt;  ...&lt;br /&gt;  &lt;br /&gt;  &lt;ctrl:buttons id="NavigateButtons" runat="server" OnProceed="Page_Proceed" OnCancel="Page_Cancel"&gt;&lt;/ctrl:buttons&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The code behind of the page contains the hook functions Page_Proceed and Page_Cancel. Note that the hook functions are protected. The generated class that derives from the code behind will need to access the two hook functions, so they are declared with protected visibility.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  protected void Page_Proceed(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   // do something for proceed&lt;br /&gt;  }&lt;br /&gt;  &lt;br /&gt;  protected void Page_Cancel(object sender, System.EventArgs e)&lt;br /&gt;  {&lt;br /&gt;   // do something for cancel&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When the aspx page is parsed and the dynamic class is generated, the control properties OnProceed and OnCancel are translated into the following code (in the generated page class):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  NavigateButtons.Proceed += new EventHandler(this.Page_Proceed);&lt;br /&gt;  NavigateButtons.Cancel += new EventHandler(this.Page_Cancel);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;When the Button1_Click event in the control fires, the Page_Proceed method is called in the page. Each page can now define hook methods that should be called when the button click events on the contained control are fired. Each page defines the hook functions, and the control tag in the .aspx page is modified to associate the hook methods with events in the control:&lt;br /&gt;&lt;br /&gt;    * Add the EventHandler declarations in the control&lt;br /&gt;    * Add the hook functions in the parent page that should be called when the event in the control is triggered&lt;br /&gt;    * Add the server control tag to the .aspx file associated with the page&lt;br /&gt;    * Add the On... attributes to the server control tag and set the attributes to the appropriate hook function in the page. Make sure that the attribute is named the same as the declared event in the control, prefixed by On. So if the event field in the control is Proceed, the attribute on the control in the .aspx page should be in the format OnProceed="hook function name in page"&lt;br /&gt;&lt;br /&gt;Now each page can define their own hook functions for the Proceed and Cancel events exposed by the control:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  // page A&lt;br /&gt;  &lt;ctrl:buttons id="NavigateButtons" runat="server" OnProceed="PageA_Proceed" OnCancel="PageA_Cancel"&gt;&lt;/ctrl:buttons&gt;&lt;br /&gt;  &lt;br /&gt;  // page B&lt;br /&gt;  &lt;ctrl:buttons id="NavigateButtons" runat="server" OnProceed="PageB_Proceed" OnCancel="PageB_Cancel"&gt;&lt;/ctrl:buttons&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The functions within each page (PageA_Proceed, PageB_Proceed) do not have to be named uniquely. Both pages could contain a Page_Proceed and Page_Cancel hook functions, the only difference being that the Page_Proceed and Page_Cancel in each page would perform different operations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108810616122933785?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108810616122933785/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108810616122933785' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810616122933785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810616122933785'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/06/control-events.html' title='Control Events'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108810598219304421</id><published>2004-06-24T12:38:00.000-07:00</published><updated>2004-06-24T12:39:42.193-07:00</updated><title type='text'>Control Validation (brief)</title><content type='html'>Let's say that we have the following simple page with one embedded server control (button) on the aspx page the following is the order of events that happen when the page is initially displayed:&lt;br /&gt;&lt;br /&gt;   1. The child controls' OnInit event is fired&lt;br /&gt;   2. The page OnInit event is fired&lt;br /&gt;   3. The Page's TrackViewState() is executed&lt;br /&gt;   4. The Page's OnLoad (Page_Load) event is fired&lt;br /&gt;   5. The child controls' OnLoad (Page_Load) event is fired&lt;br /&gt;   6. The Page's OnPreRender event is fired&lt;br /&gt;   7. The Page's SaveViewState() is run&lt;br /&gt;   8. The Page's SaveViewState() is run&lt;br /&gt;&lt;br /&gt;If we have a click event defined for the button, called btn1_click, and inside this click event it executes a callback function called Page_Proceed on the page via postback, the order is:&lt;br /&gt;&lt;br /&gt;   1. The child controls' OnInit event is fired&lt;br /&gt;   2. The page OnInit event is fired&lt;br /&gt;   3. The Page's TrackViewState() is executed&lt;br /&gt;   4. The Page's OnLoad (Page_Load) event is fired&lt;br /&gt;   5. The child controls' OnLoad (Page_Load) event is fired&lt;br /&gt;   6. The Page's RaisePostBackEvent is fired&lt;br /&gt;   7. The child controls' btn1_Click event is fired&lt;br /&gt;   8. The Page's Page_Proceed() method is executed&lt;br /&gt;   9. The Page's OnPreRender event is fired&lt;br /&gt;  10. The Page's SaveViewState() is run&lt;br /&gt;  11. The Page's SaveViewState() is run&lt;br /&gt;&lt;br /&gt;A few new events are added to the sequence: RaisePostBackEvent, btn1_Click, and the Page_Proceed event. The RaisePostBackEvent is used to trigger a server side event. The RaisePostBackEvent is defined as:&lt;br /&gt;&lt;br /&gt;  protected override void RaisePostBackEvent(IPostBackEventHandler sourceControl, string eventArgument)&lt;br /&gt;&lt;br /&gt;RaisePostBackEvent takes two arguments: the IPostBackEventHandler derived control that is raising the event and a string argument. The RaisePostBackEvent will determine which function in the codebehind of the control to execute. If a textbox and a RangeValidator control are placed on the page, the following order is observerd (if the validation was successful):&lt;br /&gt;&lt;br /&gt;   1. The child controls' OnInit event is fired&lt;br /&gt;   2. The page OnInit event is fired&lt;br /&gt;   3. The Page's TrackViewState() is executed&lt;br /&gt;   4. The Page's OnLoad (Page_Load) event is fired&lt;br /&gt;   5. The child controls' OnLoad (Page_Load) event is fired&lt;br /&gt;   6. The Page's RaisePostBackEvent is fired&lt;br /&gt;   7. The Page's Validate() is fired&lt;br /&gt;   8. The child controls' btn1_Click event is fired&lt;br /&gt;   9. The Page's Page_Proceed() method is executed&lt;br /&gt;  10. The Page's RaisePostBackEvent finishes&lt;br /&gt;  11. The Page's OnPreRender event is fired&lt;br /&gt;  12. The Page's SaveViewState() is run&lt;br /&gt;  13. The Page's SaveViewState() is run&lt;br /&gt;&lt;br /&gt;If the validation was not successful, no postback is processed, as all of the validation occurs on the client. One thing to note is that the fired event plus the Validate() methods are executed within the context of the RaisePostBackEvent. Usually a page processes only one event, so the RaisePostBackEvent waits until the fired event and its Validate() function to run before exiting. If the Validate() method of the Page fails, the fired event does not run. If we take a view of the source for the page in the browser, we see:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   &lt;input type="submit" name="NavigateButtons:Button1" value="Proceed" onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="NavigateButtons_Button1" /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This basically calls the javascript function Page_ClientValidate(), which is located in /aspnet_client/system_web/1_1_4322/WebUIValidation.js:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  function Page_ClientValidate()&lt;br /&gt;  {&lt;br /&gt;   var i;&lt;br /&gt;   for (i = 0; i &lt; Page_Validators.length; i++) {&lt;br /&gt;   ValidatorValidate(Page_Validators[i]);&lt;br /&gt;   }&lt;br /&gt;   ValidatorUpdateIsValid();&lt;br /&gt;   ValidationSummaryOnSubmit();&lt;br /&gt;   Page_BlockSubmit = !Page_IsValid;&lt;br /&gt;   return Page_IsValid;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This function iterates over each validator and calls the ValidatorValidate() function for each validator. Depending on the type of validator (RequiredField, RequiredRange, RegularExpression, etc.) a corresponding function exists in WebUIValidation.js:&lt;br /&gt;&lt;br /&gt;    * CompareValidatorEvaluateIsValid&lt;br /&gt;    * CustomValidatorEvaluateIsValid&lt;br /&gt;    * RegularExpressionValidatorEvaluateIsValid&lt;br /&gt;    * RequiredFieldValidatorEvaluateIsValid&lt;br /&gt;    * RangeValidatorEvaluateIsValid&lt;br /&gt;&lt;br /&gt;The ValidatorValidate() uses the evaluationfunction property of each validator to execute one of the functions above:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; function ValidatorValidate(val)&lt;br /&gt; {&lt;br /&gt;  val.isvalid = true;&lt;br /&gt;  if (val.enabled != false) {&lt;br /&gt;  if (typeof(val.evaluationfunction) == "function") {&lt;br /&gt;  val.isvalid = val.evaluationfunction(val);&lt;br /&gt;  }&lt;br /&gt;  }&lt;br /&gt;  ValidatorUpdateDisplay(val);&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Once evaluationfunction has run the isvalid field on each validator has been set. The ValidatorUpdateDisplay() function then runs. This function will then display the item within the span tag that is associated with the validator:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  &lt;span style="font-size:18px"&gt;!&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The ValidatorUpdateDisplay() will toggle whether the item within the 'span' tag is set to the 'hidden' or 'visible' state.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; function ValidatorUpdateDisplay(val)&lt;br /&gt; {&lt;br /&gt;  if (typeof(val.display) == "string") {&lt;br /&gt;  if (val.display == "None") {&lt;br /&gt;  return;&lt;br /&gt;  }&lt;br /&gt;  if (val.display == "Dynamic") {&lt;br /&gt;  val.style.display = val.isvalid ? "none" : "inline";&lt;br /&gt;  return;&lt;br /&gt;  }&lt;br /&gt;  }&lt;br /&gt;  val.style.visibility = val.isvalid ? "hidden" : "visible";&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If the validation succeeds, the item within the span tag remains hidden, otherwise it is visible.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108810598219304421?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108810598219304421/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108810598219304421' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810598219304421'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810598219304421'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/06/control-validation-brief.html' title='Control Validation (brief)'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108810585826163170</id><published>2004-06-24T12:35:00.000-07:00</published><updated>2004-06-24T12:37:38.260-07:00</updated><title type='text'>Creating an XML driven web site</title><content type='html'>An XML driven website is a website that stores the content as XML, either in a file or in a database. When a user requests a page, the XML content is retrieved from the data store and rendered as HTML in the browser. The HTML is usually created by a transformation, such as XSLT, or the HTML can be created programmatically. In either case, the XML data is merged with the markup to create the returned HTML page.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public void GetContent(string loc)&lt;br /&gt;  {&lt;br /&gt;   XmlTextReader reader = null;&lt;br /&gt;   &lt;br /&gt;   try&lt;br /&gt;   {&lt;br /&gt;    reader = new XmlTextReader(Server.MapPath(loc));&lt;br /&gt;    &lt;br /&gt;    if (reader != null)&lt;br /&gt;     RenderContent(reader);&lt;br /&gt;   }&lt;br /&gt;   catch(Exception e)&lt;br /&gt;   {&lt;br /&gt;    string err = e.ToString();&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The nodes in an XML stream can be accessed by an XMLDocument, an XMLTextReader/XMLTextWriter and an XPathNavigator. Each method has its advantages and drawbacks:&lt;br /&gt;&lt;br /&gt;    * XmlDocument: Provides direct memory access to the entire xml document. Nodes can be selected from the XmlDocument by XPath expressions. Can use a large amount of memory resources.&lt;br /&gt;    * XMLTextReader: Provide forward-only access to an xml stream. The entire xml dataset is not loaded into memory all at once, the XmlTextReader reads in nodes on an as-needed basis. The XMLTextWriter writes xml data to a file in a forward-only manner.&lt;br /&gt;    * XPathNavigator: Provides bi-directional access to nodes in a XmlDocument or XPathDocument. The XPathDocument provides a fast read-only cache for an xml document. If you are using an XmlTextReader to access the xml, an XPathDocument can be created by passing in a XmlTextReader object into the XPathDocument constructor. This object is not created directly, it is returned from a call to the CreateNavigator() method on the XmlDocument/XPathDocument class.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When inserting text into an XML file, beware of the special characters &lt;, &gt;, ', ", &amp;. They should be escaped by using the special notation.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;When passing XML data in memory you can use the following object types:&lt;br /&gt;&lt;br /&gt;    * XmlNode. Provides an interface to an in-memory tree representation of an XML document. Gives a R/W interface to the XML data structure in addition to XPath expression selections. The XmlDocument inherits the XmlNode abstract class.&lt;br /&gt;    * XmlReader. Streaming forward only object. Provides an xml facade over an existing object graph/text/binary data object. Difficult to use.&lt;br /&gt;    * XPathNavigator. Traverses xml in a bi-directional manner. Able to navigate an xml document via XPath expressions. This is the preferred way to pass xml around in the CLR.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108810585826163170?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108810585826163170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108810585826163170' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810585826163170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810585826163170'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/06/creating-xml-driven-web-site.html' title='Creating an XML driven web site'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108810551521661509</id><published>2004-06-24T12:23:00.000-07:00</published><updated>2004-06-24T12:31:55.216-07:00</updated><title type='text'>Building Web Services Today (like, right now!)</title><content type='html'>Rich Turner from the Indigo team has a post about creating web services using existing technologies:&lt;br /&gt;&lt;a href="http://blogs.msdn.com/richturner666/archive/2004/06/23/164201.aspx"&gt;Building Service Today&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In general, he has a few points:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;“avoid the network wherever possible“. &lt;/li&gt;&lt;br /&gt;&lt;li&gt;you have choices: asmx, remoting, queuing, Enterprise Services&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Use the facade pattern to abstract the service layer from the underlying business layer.  Also use the facade pattern to abstract the Enterprise Services classes (if any) from the Business layer.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Think about transactions, either at the web service level or at the Enterprise Services level (if the transaction spans several business components)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108810551521661509?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108810551521661509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108810551521661509' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810551521661509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108810551521661509'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/06/building-web-services-today-like-right.html' title='Building Web Services Today (like, right now!)'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108794094010657610</id><published>2004-06-22T14:26:00.000-07:00</published><updated>2004-06-24T15:31:27.126-07:00</updated><title type='text'>Web Services exposing internal object types</title><content type='html'>Lately I have been looking at creating some WSDL for a few web services for the product that I am working on.&lt;br /&gt;One of the issues that I am having is how to maximize the flexibility of the system by making sure that each layer within the web service hierarchy (web service stub/business/data layer) is independent of one another.  One of the decisions that I have to make is whether or not to return a domain model object type via a web service method.  For instance, suppose that I have the following domain model object:&lt;br /&gt;&lt;br /&gt;Case A:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class Product&lt;br /&gt;{&lt;br /&gt; public string name;&lt;br /&gt; public string sku;&lt;br /&gt; public double price;&lt;br /&gt;&lt;br /&gt; public Product() {}&lt;br /&gt;&lt;br /&gt; public Product(string name, string sku, double price)&lt;br /&gt; {&lt;br /&gt;  this.name = name;&lt;br /&gt;  this.sku = sku;&lt;br /&gt;  this.price = price;&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;My business layer has a method that retrieves an object of type Product:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class ProductBusiness&lt;br /&gt;{&lt;br /&gt; public Product retrieveProduct()&lt;br /&gt; {&lt;br /&gt;  return new Product("JellyBelly (8 oz.)", "PK09834", 2.50);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;My web service calls the retrieveProduct method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[WebMethod]&lt;br /&gt;public Product getProduct()&lt;br /&gt;{&lt;br /&gt; ProductBusiness bus = new ProductBusiness();&lt;br /&gt; Product prod = bus.retrieveProduct();&lt;br /&gt; return prod;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In this example, the WSDL is driven by the domain model (what I call schema last).  There&lt;br /&gt;are a few drawbacks to this approach:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;The Product data type in the domain model is tightly coupled to the datatype in the public web service interface.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If a public field is added to the Product domain model object, this public field will&lt;br /&gt;be exposed via the WSDL.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;If another class in the business model would like to access a public field on the Product&lt;br /&gt;domain class, but we do not want to expose this public field via the web service, we would have to declare the field as non-public and expose the field to the client class via a helper class (or a helper method on the domain model class).&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;One solution would be to add a mapper class that would translate between the classes exposed via the public web service (WSDL) and the classes used internally by the business layer.  One way to do this is to define the WSDL independently of any application domain model classes.&lt;br /&gt;&lt;br /&gt;Case B:&lt;br /&gt;Suppose that I defined the WSDL for a product called WSProduct:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public class WSProduct&lt;br /&gt;{&lt;br /&gt;  public string name;&lt;br /&gt;  public string sku;&lt;br /&gt;  public double price;&lt;br /&gt;  public DateTime dateRetrieved;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And change the web method to use this class:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;[WebMethod]&lt;br /&gt;public WSProduct getWSProduct()&lt;br /&gt;{&lt;br /&gt; ProductBusiness bus = new ProductBusiness();&lt;br /&gt; WSProduct prod = bus.retrieveWSProduct();&lt;br /&gt; return prod;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now the web service method returns a class of type WSProduct, and it obtains&lt;br /&gt;the object from the ProductBusiness class via the retrieveWSProduct() method.&lt;br /&gt;The retrieveWSProduct method on the ProductBusiness class looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;public WSProduct retrieveWSProduct()&lt;br /&gt;{&lt;br /&gt; Product prod = new Product("JellyBelly (8 oz.)", "PK09834", 2.50);&lt;br /&gt; WSProduct wsProd = new WSProduct();&lt;br /&gt; wsProd.name = prod.name;&lt;br /&gt; wsProd.sku = prod.sku;&lt;br /&gt; wsProd.price = prod.price;&lt;br /&gt; wsProd.dateRetrieved = DateTime.Now;&lt;br /&gt; return wsProd;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The method creates a Product and a WSProduct class, and then it translates(copies)&lt;br /&gt;the values from the Product class to the WSProduct class.  It also sets the dateRetrieved field on the WSProduct class.  &lt;br /&gt;&lt;br /&gt;In this case, any changes to the Product domain model class will not affect the contract&lt;br /&gt;exposed by the web service, since this contract is represented by the WSProduct definition&lt;br /&gt;in the WSDL.  Any changes to the WSProduct in the WSDL will only affect the ProductBusiness&lt;br /&gt;object (retrieveProduct will need modification).  The Product object will remain unchanged since it is only used internally and it is not exposed by the web service.&lt;br /&gt;&lt;br /&gt;Now for the question:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Which method is preferred?  I would think that the case B is preferred over case A since there is less coupling&lt;br /&gt;between the web service interface and the underlying implementation.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108794094010657610?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108794094010657610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108794094010657610' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108794094010657610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108794094010657610'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/06/web-services-exposing-internal-object.html' title='Web Services exposing internal object types'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108492274927068365</id><published>2004-05-18T16:25:00.000-07:00</published><updated>2004-05-18T16:25:49.270-07:00</updated><title type='text'>Microsoft Architecture Patterns</title><content type='html'>A link to some architectural patterns can be found &lt;a href="http://msdn.microsoft.com/architecture/patterns/"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108492274927068365?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108492274927068365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108492274927068365' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108492274927068365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108492274927068365'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/05/microsoft-architecture-patterns.html' title='Microsoft Architecture Patterns'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108490645524424342</id><published>2004-05-18T11:52:00.000-07:00</published><updated>2004-05-18T11:54:15.243-07:00</updated><title type='text'>Data Compatibility in WebServices</title><content type='html'>Simon Guest has a blog post about data type compatibility between WebServices in different execution environments (Java and .NET) &lt;a href="http://blogs.msdn.com/smguest/archive/2004/05/18/134139.aspx"&gt;here&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108490645524424342?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108490645524424342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108490645524424342' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108490645524424342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108490645524424342'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/05/data-compatibility-in-webservices.html' title='Data Compatibility in WebServices'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108483183757330649</id><published>2004-05-17T15:10:00.000-07:00</published><updated>2004-07-10T10:47:46.406-07:00</updated><title type='text'>Delegates</title><content type='html'>Delegates are data types in the .NET framework that reference a method with a specific signature. Delegates are used to execute a method on a class via the created type. The ThreadStart type is an example of a delegate, in this case the ThreadStart delegate references a method that has an empty parameter list. You can create a ThreadStart delegate as follows: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  ThreadStart ts = new ThreadStart(DelegateFunction);&lt;br /&gt;  Thread t = new Thread(ts);&lt;br /&gt;  t.Start(); //start the thread&lt;br /&gt;  &lt;br /&gt;  for (int i = 0; i &lt; 1000; i++)&lt;br /&gt;   t.Sleep(5);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;The ThreadStart class takes a reference to a method that cannot have any input parameters. The DelegateFunction is defined as: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  public void DelegateFunction()&lt;br /&gt;  {&lt;br /&gt;   // Do something...&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;  &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The DelegateFunction is executed when the Thread.Start function is run. In this case, the ThreadStart delegate wraps the method call, so that the method can be called via a type instance. Delegates are used for callback functions, events and as an implicit interface contract. A delegate can reference a function that takes parameters: &lt;br /&gt;&lt;pre&gt;&lt;br /&gt; public delegate string FunctionPointer(int foo, string bar);&lt;br /&gt; &lt;br /&gt; public FunctionPointer fpi; &lt;br /&gt; fpi = new FunctionPointer(Function);&lt;br /&gt;&lt;/pre&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The Function declaration loooks like this: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; string Function(int foo, string bar)&lt;br /&gt; {&lt;br /&gt;  string temp = "";&lt;br /&gt;&lt;br /&gt;  for (int i = 0; i &lt; foo; i++)&lt;br /&gt;   temp += bar;&lt;br /&gt; &lt;br /&gt;  return temp;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;  The same delegate can point to another function with the same signature &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; string AnotherFunction(int foo, string bar)&lt;br /&gt; {&lt;br /&gt;  string temp = "AnotherFunction";&lt;br /&gt;&lt;br /&gt;  for (int i = 0; i &lt; foo; i++)&lt;br /&gt;   temp += bar;&lt;br /&gt;&lt;br /&gt;  return temp;&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The following is a sample console application that demonstrates delegates. In Main(), the source class and each sink class is created. The source class is the class that will call the function in the sink class via the delegate reference. Each sink class contains a method called Callback that will be called by the source class. To hook up the Callback method in the sink class to the delegate in the source class, a reference to the delegate is created and the name of the callback function in the sink class is passed as a parameter to the delegate reference constructor: &lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt; using System;&lt;br /&gt; &lt;br /&gt; namespace Delegate&lt;br /&gt; {&lt;br /&gt;  class Class1&lt;br /&gt;  {&lt;br /&gt;   [STAThread]&lt;br /&gt;   static void Main(string[] args)&lt;br /&gt;   {&lt;br /&gt;    SourceClass sc = new SourceClass();&lt;br /&gt;    SinkAClass sac = new SinkAClass();&lt;br /&gt;    SinkBClass sbc = new SinkBClass();&lt;br /&gt; &lt;br /&gt;    // Hook up the function and execute&lt;br /&gt;    sc.fp = new SourceClass.FunctionPointer(sac.Callback);&lt;br /&gt;    sc.DoSomething();&lt;br /&gt; &lt;br /&gt;    // Hook up a new sink&lt;br /&gt;    sc.fp = new SourceClass.FunctionPointer(sbc.Callback);&lt;br /&gt;    sc.DoSomething();&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  public class SourceClass&lt;br /&gt;  {&lt;br /&gt;   public delegate void FunctionPointer(int arg1, string arg2);&lt;br /&gt;   public FunctionPointer fp;&lt;br /&gt; &lt;br /&gt;   public void DoSomething()&lt;br /&gt;   {&lt;br /&gt;    // call the function pointed to by fp;&lt;br /&gt;    fp(3, this.ToString());&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  public class SinkAClass&lt;br /&gt;  {&lt;br /&gt;   public void Callback(int arg1, string arg2)&lt;br /&gt;   {&lt;br /&gt;    Console.WriteLine(&lt;br /&gt;"{0} Callback method was called with arguments: {1}, {2}", &lt;br /&gt;this.ToString(), &lt;br /&gt;arg1.ToString(), &lt;br /&gt;arg2);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  public class SinkBClass&lt;br /&gt;  {&lt;br /&gt;   public void Callback(int arg1, string arg2)&lt;br /&gt;   {&lt;br /&gt;    Console.WriteLine(&lt;br /&gt;"{0} Callback method was called with arguments: {1}, {2}", &lt;br /&gt;this.ToString(), &lt;br /&gt;arg1.ToString(), &lt;br /&gt;arg2);&lt;br /&gt;   }&lt;br /&gt;  }&lt;br /&gt; }&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108483183757330649?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108483183757330649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108483183757330649' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108483183757330649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108483183757330649'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/05/delegates.html' title='Delegates'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7020748.post-108483140746337147</id><published>2004-05-17T14:52:00.000-07:00</published><updated>2004-05-17T15:03:27.463-07:00</updated><title type='text'>TypePad vs Blogger</title><content type='html'>So I used to use UserLand Radio &lt;a href="http://radio.weblogs.com/0124037"&gt;My Blog&lt;/a&gt;, but I wanted to switch to a different blog host, so I tried out TypePad from SixApart.  So I signed up for the 30 day trial, and once registered, I had pretty high hopes for sticking with TypePad.  That is until I started to actually use their online tool for managing your blog.  First I created a weblog, then I added 3 posts to my weblog.  Once the posts were added, I cliked the View Weblog button to view my public blog.  Unfortunately my posts were not updated.  So I went back and added another post, and tried to view my blog again, but no luck, the post was not added.  So then I went and took a look at the help pages, thinking that maybe I was doing something wrong, but I couldn't find anything.  So guess what company is NOT getting my money every month?  Contrast my experience with Blogger, which has a much simpler registration/weblog creation system.  And the good thing about Blogger is that it did what I told it to do: create a post and update my weblog to display that post.  It really doesn't take that much to make a customer choose a competitors product over your product, if your product does not perform the way the customer expects it to, based on the published features of your product...&lt;br /&gt;&lt;br /&gt;Update:  It must just take a while for the new entries to post to the TypePad blog, I can see them now. &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7020748-108483140746337147?l=staticground.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://staticground.blogspot.com/feeds/108483140746337147/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7020748&amp;postID=108483140746337147' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108483140746337147'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7020748/posts/default/108483140746337147'/><link rel='alternate' type='text/html' href='http://staticground.blogspot.com/2004/05/typepad-vs-blogger.html' title='TypePad vs Blogger'/><author><name>Phil</name><uri>http://www.blogger.com/profile/04253680812859669469</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
