<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Jesse Johnston</title>
    <link>http://www.teamjohnston.net/cs/blogs/jesse/</link>
    <description>.NET Dev</description>
    <language>en-us</language>
    <copyright>Jesse Johnston</copyright>
    <lastBuildDate>Sat, 02 Aug 2008 06:05:26 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.1.8102.813</generator>
    <managingEditor>jesse@teamjohnston.net</managingEditor>
    <webMaster>jesse@teamjohnston.net</webMaster>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=53746DF1-441D-4EDA-B1DC-43A3132A1A30</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,53746DF1-441D-4EDA-B1DC-43A3132A1A30.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,53746DF1-441D-4EDA-B1DC-43A3132A1A30.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=53746DF1-441D-4EDA-B1DC-43A3132A1A30</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">I've changed hosters and blog engines.
I'll be posting in the future at <a href="http://www.teamjohnston.net/blogs/jesse">http://www.teamjohnston.net/blogs/jesse</a>.<br /><br /><img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=53746DF1-441D-4EDA-B1DC-43A3132A1A30" /></body>
      <title>Moving My Blog</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,53746DF1-441D-4EDA-B1DC-43A3132A1A30.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,53746DF1-441D-4EDA-B1DC-43A3132A1A30.aspx</link>
      <pubDate>Sat, 02 Aug 2008 06:05:26 GMT</pubDate>
      <description>I've changed hosters and blog engines. I'll be posting in the future at &lt;a href="http://www.teamjohnston.net/blogs/jesse"&gt;http://www.teamjohnston.net/blogs/jesse&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=53746DF1-441D-4EDA-B1DC-43A3132A1A30" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,53746DF1-441D-4EDA-B1DC-43A3132A1A30.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
If you're using LINQ to SQL with SQLCE and use the DataContext.CreateDatabase() method,
you may encounter this error.  If you used the LINQ to SQL class designer to
generate the classes from a different database provider (such as SQL Server 2005 or
SQL Server Express), the table source names may be prefixed with "dbo."
</p>
        <p>
Just remove the prefix, and CreateDatabase() will succeed.
</p>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac" />
      </body>
      <title>SQLCE Error 26100: The table name is not valid</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac.aspx</link>
      <pubDate>Wed, 16 Apr 2008 06:05:26 GMT</pubDate>
      <description>&lt;p&gt;
If you're using LINQ to SQL with SQLCE and use the DataContext.CreateDatabase() method,
you may encounter this error.&amp;#160; If you used the LINQ to SQL class designer to
generate the classes from a different database provider (such as SQL Server 2005 or
SQL Server Express), the table source names may be prefixed with &amp;quot;dbo.&amp;quot;
&lt;/p&gt;
&lt;p&gt;
Just remove the prefix, and CreateDatabase() will succeed.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,bc91e2ad-fdd3-4dc1-9eb3-cb80505264ac.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=c2e50a60-100c-40b3-b31f-f3cd860d9818</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,c2e50a60-100c-40b3-b31f-f3cd860d9818.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,c2e50a60-100c-40b3-b31f-f3cd860d9818.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=c2e50a60-100c-40b3-b31f-f3cd860d9818</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I'm posting this for future reference.  If you invoke a PageFunction and add
an event handler to the PageFunction's Return event, the event handler must be an <em>instance
method of the calling page</em>.  No other method will do.  If the event
handler doesn't meet this criteria, you'll see the FatalExecutionEngineError thrown
when you return from the PageFunction.  Sorry, no separation of concerns allowed.
</p>
        <p>
More details in this forum thread: <a title="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1975763&amp;SiteID=1" href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1975763&amp;SiteID=1">http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1975763&amp;SiteID=1</a>.
</p>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=c2e50a60-100c-40b3-b31f-f3cd860d9818" />
      </body>
      <title>FatalExecutionEngineError returning from WPF PageFunction</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,c2e50a60-100c-40b3-b31f-f3cd860d9818.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,c2e50a60-100c-40b3-b31f-f3cd860d9818.aspx</link>
      <pubDate>Fri, 30 Nov 2007 07:17:30 GMT</pubDate>
      <description>&lt;p&gt;
I'm posting this for future reference.&amp;#160; If you invoke a PageFunction and add
an event handler to the PageFunction's Return event, the event handler must be an &lt;em&gt;instance
method of the calling page&lt;/em&gt;.&amp;#160; No other method will do.&amp;#160; If the event
handler doesn't meet this criteria, you'll see the FatalExecutionEngineError thrown
when you return from the PageFunction.&amp;#160; Sorry, no separation of concerns allowed.
&lt;/p&gt;
&lt;p&gt;
More details in this forum thread: &lt;a title="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1975763&amp;amp;SiteID=1" href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1975763&amp;amp;SiteID=1"&gt;http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1975763&amp;amp;SiteID=1&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=c2e50a60-100c-40b3-b31f-f3cd860d9818" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,c2e50a60-100c-40b3-b31f-f3cd860d9818.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=1eb76cae-1dc2-4108-bcd0-ffe55f44ed36</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,1eb76cae-1dc2-4108-bcd0-ffe55f44ed36.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,1eb76cae-1dc2-4108-bcd0-ffe55f44ed36.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=1eb76cae-1dc2-4108-bcd0-ffe55f44ed36</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
We recently upgraded to VS 2008 RTM at work, and shortly after discovered that a new
build of our ClickOnce-deployed WinForms application failed to install correctly! 
During the download process, a message box would display, and the log details revealed
an InvalidDeploymentException (RefDefValidation) in System.Deployment.Application.DownloadManager.ProcessDownloadedFile().
</p>
        <p>
Let me just say that <em>days</em> of fruitless investigation followed.
</p>
        <p>
I'm happy to report that I finally did find the solution (completely by accident). 
A new option has been added to Visual Studio, allowing you to automatically create
and embed a manifest in your application.  This manifest allows you to provide
proper application behavior when running under UAC in Vista.  Here's the option,
on the Application property page of the Visual Studio project:<a href="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/ClickOnceErrorafterupgradingtoVS2008_10B3F/Manifest%20Options_2.png"><img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 10px 5px 5px 25px; border-right-width: 0px" height="282" alt="Manifest Options" src="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/ClickOnceErrorafterupgradingtoVS2008_10B3F/Manifest%20Options_thumb.png" width="377" border="0" /></a></p>
        <p>
When you upgrade a WinForms project from VS2005 to VS2008, this option is automatically
set for you.  If you had identified the application as a ClickOnce application
in VS 2005, the resulting deployment from a VS2008 build works correctly.
</p>
        <h3>Real-world ClickOnce
</h3>
        <p>
If you're like me, you're developing in a professional environment where you can't
just click the <strong>Publish Now</strong> button and send an app from your development
box into production.  Is it just me, or does everyone think that's insane? 
Do you think we might want to QA those phasers first, Captain?
</p>
        <p>
We have a relatively complex build that builds our ClickOnce manifests based on the
target environment (Dev, QA, or Production) so that we can test ClickOnce updates
from previous versions before going to production.  Also, since we've had our
ClickOnce app deployed for more than one year, we had to overcome the certificate
renewal problem, which requires a special signing process using both the expired and
the current signing certificate.  Needless to say, neither of these can be set
up in Visual Studio.  What we ended up with is a build where the ClickOnce options
are <em>not</em> set in the Visual Studio project, but externally in an MSBuild project
file, using many of the built-in targets that VS uses.
</p>
        <h3>Migrating from VS2005
</h3>
        <p>
When the project was converted to VS2008, it was upgraded by the wizard as if it wasn't
a ClickOnce project.  This means that the manifest setting was set incorrectly.
</p>
        <p>
Here's what the Visual Studio documentation has to say about the manifest setting:
</p>
        <p>
        </p>
        <dt>
          <em>
            <font size="2">Manifest</font>
          </em>
        </dt>
        <dt>
          <em>
            <font size="2">
            </font>
          </em>
        </dt>
        <dt>
          <em>
            <font size="2">Selects
a manifest generation option when the application runs on Windows Vista under User
Account Control (UAC). This option can have the following values:</font>
          </em>
          <ul>
            <li>
              <em>
                <font size="2">Embed manifest with default settings. Supports the typical manner
in which Visual Studio operates on Windows Vista, which is to embed security information
in the application's executable file, specifying that requestedExecutionLevel be AsInvoker.
This is the default option.</font>
              </em>
            </li>
            <li>
              <em>
                <font size="2">Create application without a manifest. This method is known as
virtualization. Use this option for compatibility with earlier applications.</font>
              </em>
            </li>
            <li>
              <em>
                <font size="2">Properties\app.manifest. This option is required for applications
deployed by ClickOnce or Registration-Free COM. If you publish an application by using
ClickOnce deployment, Manifest is automatically set to this option.</font>
              </em>
            </li>
          </ul>
          <p>
The only options I see in the combo box are the first and second.  In our application,
"Embed manifest with default settings" was selected by the conversion. 
As soon as I chose "Create application without a manifest", I was able to
build, deploy, and download with no trouble at all.
</p>
          <p>
I still need to investigate the manifest issue further.  I want my users to have
a great UAC experience with our app, and that means getting the manifest right. 
For now though, "create without a manifest" is your quick fix.
</p>
          <p>
Click On!
</p>
        </dt>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=1eb76cae-1dc2-4108-bcd0-ffe55f44ed36" />
      </body>
      <title>ClickOnce Error after upgrading to VS 2008</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,1eb76cae-1dc2-4108-bcd0-ffe55f44ed36.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,1eb76cae-1dc2-4108-bcd0-ffe55f44ed36.aspx</link>
      <pubDate>Fri, 30 Nov 2007 04:04:16 GMT</pubDate>
      <description>&lt;p&gt;
We recently upgraded to VS 2008 RTM at work, and shortly after discovered that a new
build of our ClickOnce-deployed WinForms application failed to install correctly!&amp;#160;
During the download process, a message box would display, and the log details revealed
an InvalidDeploymentException (RefDefValidation) in System.Deployment.Application.DownloadManager.ProcessDownloadedFile().
&lt;/p&gt;
&lt;p&gt;
Let me just say that &lt;em&gt;days&lt;/em&gt; of fruitless investigation followed.
&lt;/p&gt;
&lt;p&gt;
I'm happy to report that I finally did find the solution (completely by accident).&amp;#160;
A new option has been added to Visual Studio, allowing you to automatically create
and embed a manifest in your application.&amp;#160; This manifest allows you to provide
proper application behavior when running under UAC in Vista.&amp;#160; Here's the option,
on the Application property page of the Visual Studio project:&lt;a href="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/ClickOnceErrorafterupgradingtoVS2008_10B3F/Manifest%20Options_2.png"&gt;&lt;img style="border-top-width: 0px; border-left-width: 0px; border-bottom-width: 0px; margin: 10px 5px 5px 25px; border-right-width: 0px" height="282" alt="Manifest Options" src="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/ClickOnceErrorafterupgradingtoVS2008_10B3F/Manifest%20Options_thumb.png" width="377" border="0" /&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
When you upgrade a WinForms project from VS2005 to VS2008, this option is automatically
set for you.&amp;#160; If you had identified the application as a ClickOnce application
in VS 2005, the resulting deployment from a VS2008 build works correctly.
&lt;/p&gt;
&lt;h3&gt;Real-world ClickOnce
&lt;/h3&gt;
&lt;p&gt;
If you're like me, you're developing in a professional environment where you can't
just click the &lt;strong&gt;Publish Now&lt;/strong&gt; button and send an app from your development
box into production.&amp;#160; Is it just me, or does everyone think that's insane?&amp;#160;
Do you think we might want to QA those phasers first, Captain?
&lt;/p&gt;
&lt;p&gt;
We have a relatively complex build that builds our ClickOnce manifests based on the
target environment (Dev, QA, or Production) so that we can test ClickOnce updates
from previous versions before going to production.&amp;#160; Also, since we've had our
ClickOnce app deployed for more than one year, we had to overcome the certificate
renewal problem, which requires a special signing process using both the expired and
the current signing certificate.&amp;#160; Needless to say, neither of these can be set
up in Visual Studio.&amp;#160; What we ended up with is a build where the ClickOnce options
are &lt;em&gt;not&lt;/em&gt; set in the Visual Studio project, but externally in an MSBuild project
file, using many of the built-in targets that VS uses.
&lt;/p&gt;
&lt;h3&gt;Migrating from VS2005
&lt;/h3&gt;
&lt;p&gt;
When the project was converted to VS2008, it was upgraded by the wizard as if it wasn't
a ClickOnce project.&amp;#160; This means that the manifest setting was set incorrectly.
&lt;/p&gt;
&lt;p&gt;
Here's what the Visual Studio documentation has to say about the manifest setting:
&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;dt&gt;&lt;em&gt;&lt;font size="2"&gt;Manifest&lt;/font&gt;&lt;/em&gt;&lt;/dt&gt;&lt;dt&gt;&lt;em&gt;&lt;font size="2"&gt;&lt;/font&gt;&lt;/em&gt;&lt;/dt&gt;&lt;dt&gt;&lt;em&gt;&lt;font size="2"&gt;Selects
a manifest generation option when the application runs on Windows Vista under User
Account Control (UAC). This option can have the following values:&lt;/font&gt;&lt;/em&gt; 
&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;&lt;font size="2"&gt;Embed manifest with default settings. Supports the typical manner
in which Visual Studio operates on Windows Vista, which is to embed security information
in the application's executable file, specifying that requestedExecutionLevel be AsInvoker.
This is the default option.&lt;/font&gt;&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;&lt;font size="2"&gt;Create application without a manifest. This method is known as
virtualization. Use this option for compatibility with earlier applications.&lt;/font&gt;&lt;/em&gt; 
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;&lt;font size="2"&gt;Properties\app.manifest. This option is required for applications
deployed by ClickOnce or Registration-Free COM. If you publish an application by using
ClickOnce deployment, Manifest is automatically set to this option.&lt;/font&gt;&lt;/em&gt; 
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
The only options I see in the combo box are the first and second.&amp;#160; In our application,
&amp;quot;Embed manifest with default settings&amp;quot; was selected by the conversion.&amp;#160;
As soon as I chose &amp;quot;Create application without a manifest&amp;quot;, I was able to
build, deploy, and download with no trouble at all.
&lt;/p&gt;
&lt;p&gt;
I still need to investigate the manifest issue further.&amp;#160; I want my users to have
a great UAC experience with our app, and that means getting the manifest right.&amp;#160;
For now though, &amp;quot;create without a manifest&amp;quot; is your quick fix.
&lt;/p&gt;
&lt;p&gt;
Click On!
&lt;/p&gt;
&lt;/dt&gt;&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=1eb76cae-1dc2-4108-bcd0-ffe55f44ed36" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,1eb76cae-1dc2-4108-bcd0-ffe55f44ed36.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=95a12ae3-4be8-4521-bf2b-7e7a0c3ae253</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,95a12ae3-4be8-4521-bf2b-7e7a0c3ae253.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,95a12ae3-4be8-4521-bf2b-7e7a0c3ae253.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=95a12ae3-4be8-4521-bf2b-7e7a0c3ae253</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Phil Haack posed a <a href="http://haacked.com/archive/2007/11/27/question-for-you-dependency-injection-buffs.aspx">question</a> today
about dependency injection frameworks:
</p>
        <blockquote>
          <p>
Normally, I would just specify a type to instantiate as another <code>PluginFamily</code> entry.
But what I really want to happen in this case is for StructureMap to call a method
or delegate and use the value returned as the constructor argument. 
</p>
          <p>
...
</p>
          <p>
            <strong>Does anyone know if something like this is possible with any of the Dependency
Injection frameworks out there? </strong>Whether via code or configuration?
</p>
        </blockquote>
        <p>
I don't have much experience with the big three DI frameworks <a href="http://www.castleproject.org/container/index.html">Castle
Windsor</a>, <a href="http://www.springframework.net/">Spring.NET</a> and <a href="http://structuremap.sourceforge.net/Default.htm">StructureMap</a>,
but what I've seen suggests that these are strongly configuration based.
</p>
        <p>
That means that I can specify a concrete type name in a configuration file that the
framework will use to instantiate a particular interface type.  For example,
in Spring.NET, you might specify the concrete type like this:
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">
            <span>&lt;objects xmlns="http://www.springframework.net"&gt;</span>
          </pre>
          <pre style="margin: 0px">
            <span>    &lt;object</span>
          </pre>
          <pre style="margin: 0px">
            <span>        name="TheClassIWant"</span>
          </pre>
          <pre style="margin: 0px">
            <span>        type="MyNamespace.MyConcreteClass,
MyAssembly"</span>
          </pre>
          <pre style="margin: 0px">
            <span>    &lt;/object&gt;</span>
          </pre>
          <pre style="margin: 0px">
            <span>&lt;/objects&gt;</span>
          </pre>
        </div>
        <p>
Then in your code, you can ask Spring to create an instance of MyConcreteClass like
so:
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">IApplicationContext ctx = ContextRegistry.GetContext();</pre>
          <pre style="margin: 0px">MyConcreteClass instance = (MyConcreteClass)ctx.GetObject(<span style="color: #a31515">"TheClassIWant"</span>);</pre>
        </div>
        <p>
That's all well and good.  In Phil's case, though, he wants to specify a way
to create an instance of MyConcreteClass <em>in code</em> rather than configuration. 
Let's take that requirement more generally and assert that we know what concrete classes
we want to instantiate in our application, but just don't want the whole application
to know.  Maybe I need an instance of ISomeInterface in some part of my code,
but that code doesn't know how to get an ISomeInterface.  What I want is some
global mechanism to define how to get an instance of some type, and then a way to
get the type.  Now, how do we do that in code?
</p>
        <h3>Simple Service Locator
</h3>
        <p>
I had some spare time while at DevConnections, and decided to create just that - a
code-based service locator.  The basic idea is that we'll have a ServiceLocator
class that maps interface types to concrete types.
</p>
        <p>
At some point in your code, you register a concrete type for an interface:
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">
            <span style="color: #2b91af">ServiceLocator</span> locator
= <span style="color: blue">new</span><span style="color: #2b91af">ServiceLocator</span>();</pre>
          <pre style="margin: 0px">locator.Register&lt;<span style="color: #2b91af">ITest</span>&gt;(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Test</span>));</pre>
        </div>
        <p>
This means that when we ask for instance of the interface ITest, ServiceLocator will
create and return an instance of Test (the implication of course is that Test implements
ITest).  Here's how we ask for an ITest:
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">
            <span style="color: #2b91af">ITest</span> instance = locator.Get&lt;<span style="color: #2b91af">ITest</span>&gt;();</pre>
        </div>
        <p>
If you expose a singleton instance of ServiceLocator in your application, you can
register your types at startup, and then use the locator to instantiate the concrete
types from anywhere in the code.
</p>
        <h3>What about parameterized constructors?
</h3>
        <p>
Default constructors are the trivial case.  How do we handle creation of concrete
types that require constructor parameters?  We have two cases:
</p>
        <ol>
          <li>
The parameter is an interface that we want ServiceLocator to instantiate 
</li>
          <li>
The parameter is a value that we want to provide explicitly. 
</li>
        </ol>
        <p>
Here's how we handle the first case:
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">locator.Register&lt;<span style="color: #2b91af">ICat</span>&gt;(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Cat</span>), <span style="color: blue">typeof</span>(<span style="color: #2b91af">IOwner</span>));</pre>
          <pre style="margin: 0px">locator.Register&lt;<span style="color: #2b91af">IOwner</span>&gt;(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Owner</span>));</pre>
          <pre style="margin: 0px"> </pre>
          <pre style="margin: 0px">
            <span style="color: #2b91af">ICat</span> instance = locator.Get&lt;<span style="color: #2b91af">ICat</span>&gt;();</pre>
        </div>
        <p>
Here we're saying that if we want an ICat, we need to create a Cat with the constructor
Cat(IOwner).  By registering IOwner to create an Owner, ServiceLocator is able
to create a Cat by first instantiating an Owner and passing that value to the Cat
constructor.
</p>
        <p>
In the second case, we have some value that ServiceLocator doesn't know how to create. 
Let's suppose the Cat constructor takes an IOwner and a string:
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">locator.Register&lt;<span style="color: #2b91af">IOwner</span>&gt;(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Owner</span>));</pre>
          <pre style="margin: 0px">locator.Register&lt;<span style="color: #2b91af">ICat</span>&gt;(<span style="color: blue">typeof</span>(<span style="color: #2b91af">Cat</span>), <span style="color: blue">new</span><span style="color: #2b91af">TypeParameter</span>(<span style="color: blue">typeof</span>(<span style="color: #2b91af">IOwner</span>)), <span style="color: blue">new</span><span style="color: #2b91af">TypeParameter</span>(<span style="color: blue">typeof</span>(<span style="color: blue">string</span>), <span style="color: #a31515">"Kitty"</span>));</pre>
          <pre style="margin: 0px">
            <span style="color: #2b91af">ICat</span> cat = locator.Get&lt;<span style="color: #2b91af">ICat</span>&gt;();</pre>
        </div>
        <p>
In this case, ServiceLocator will call the constructor Cat(IOwner, string) with an
IOwner it creates, and the string "Kitty".
</p>
        <h3>And Singletons?
</h3>
        <p>
Sometimes we always want the same instance of an object:
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">
            <span style="color: #2b91af">Cat</span> kitty = <span style="color: blue">new</span><span style="color: #2b91af">Cat</span>();</pre>
          <pre style="margin: 0px">locator.Register&lt;<span style="color: #2b91af">ICat</span>&gt;(kitty);</pre>
          <pre style="margin: 0px">
            <span style="color: #2b91af">ICat</span> cat = locator.Get&lt;<span style="color: #2b91af">ICat</span>&gt;();</pre>
        </div>
        <p>
Here we always return the instance kitty when an ICat is requested.  We all know
how hard it is to work with a large number of cats.
</p>
        <h3>Le Delegate
</h3>
        <p>
Yes, there is a Santa Claus.  I might have some code that is responsible for
creating an object.  Perhaps it's responsible for managing a pool of objects,
or just has some complexity that would be difficult to express in configuration. 
I want to register a delegate that will provide the instance.
</p>
        <div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new">
          <pre style="margin: 0px">locator.Register&lt;<span style="color: #2b91af">ICat</span>&gt;(<span style="color: blue">delegate</span>()
{ <span style="color: blue">return</span> kitty.IsSleeping ? buffy : kitty; });</pre>
          <pre style="margin: 0px">
            <span style="color: #2b91af">ICat</span> cat = locator.Get&lt;<span style="color: #2b91af">ICat</span>&gt;();</pre>
        </div>
        <p>
Here I provided an anonymous method in the Register() call, but I could just as easily
register some other class method.
</p>
        <p>
So there you have it - a configuration-free service locator with quite a bit of flexibility
in object creation.
</p>
        <p>
You can download the source for my ServiceLocator <a href="http://www.teamjohnston.net/files/ServiceLocator.zip">here</a>. 
The project was built in Visual Studio 2008.
</p>
        <h3>Should I Use it?
</h3>
        <p>
If it works for you!  It's free of course.  However, I conjured this up
in an hour or two, so it's not likely that ServiceLocator offers anywhere near the
capabilities of a full-fledged dependency injection framework.  I'd encourage
you to look closely at <a href="http://www.castleproject.org/container/index.html">Castle
Windsor</a>, <a href="http://www.springframework.net/">Spring.NET</a> and <a href="http://structuremap.sourceforge.net/Default.htm">StructureMap</a>. 
I'm sure that there are other great frameworks too.
</p>
        <p>
I'd be grateful for any feedback as always.
</p>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=95a12ae3-4be8-4521-bf2b-7e7a0c3ae253" />
      </body>
      <title>Service Locator in Code?</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,95a12ae3-4be8-4521-bf2b-7e7a0c3ae253.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,95a12ae3-4be8-4521-bf2b-7e7a0c3ae253.aspx</link>
      <pubDate>Wed, 28 Nov 2007 09:04:57 GMT</pubDate>
      <description>&lt;p&gt;
Phil Haack posed a &lt;a href="http://haacked.com/archive/2007/11/27/question-for-you-dependency-injection-buffs.aspx"&gt;question&lt;/a&gt; today
about dependency injection frameworks:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
Normally, I would just specify a type to instantiate as another &lt;code&gt;PluginFamily&lt;/code&gt; entry.
But what I really want to happen in this case is for StructureMap to call a method
or delegate and use the value returned as the constructor argument. 
&lt;/p&gt;
&lt;p&gt;
...
&lt;/p&gt;
&lt;p&gt;
&lt;strong&gt;Does anyone know if something like this is possible with any of the Dependency
Injection frameworks out there? &lt;/strong&gt;Whether via code or configuration?
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
I don't have much experience with the big three DI frameworks &lt;a href="http://www.castleproject.org/container/index.html"&gt;Castle
Windsor&lt;/a&gt;, &lt;a href="http://www.springframework.net/"&gt;Spring.NET&lt;/a&gt; and &lt;a href="http://structuremap.sourceforge.net/Default.htm"&gt;StructureMap&lt;/a&gt;,
but what I've seen suggests that these are strongly configuration based.
&lt;/p&gt;
&lt;p&gt;
That means that I can specify a concrete type name in a configuration file that the
framework will use to instantiate a particular interface type.&amp;#160; For example,
in Spring.NET, you might specify the concrete type like this:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;&lt;span&gt;&amp;lt;objects xmlns=&amp;quot;http://www.springframework.net&amp;quot;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;object&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; name=&amp;quot;TheClassIWant&amp;quot;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; type=&amp;quot;MyNamespace.MyConcreteClass,
MyAssembly&amp;quot;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span&gt;&amp;#160;&amp;#160;&amp;#160; &amp;lt;/object&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span&gt;&amp;lt;/objects&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Then in your code, you can ask Spring to create an instance of MyConcreteClass like
so:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;IApplicationContext ctx = ContextRegistry.GetContext();&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;MyConcreteClass instance = (MyConcreteClass)ctx.GetObject(&lt;span style="color: #a31515"&gt;&amp;quot;TheClassIWant&amp;quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
That's all well and good.&amp;#160; In Phil's case, though, he wants to specify a way
to create an instance of MyConcreteClass &lt;em&gt;in code&lt;/em&gt; rather than configuration.&amp;#160;
Let's take that requirement more generally and assert that we know what concrete classes
we want to instantiate in our application, but just don't want the whole application
to know.&amp;#160; Maybe I need an instance of ISomeInterface in some part of my code,
but that code doesn't know how to get an ISomeInterface.&amp;#160; What I want is some
global mechanism to define how to get an instance of some type, and then a way to
get the type.&amp;#160; Now, how do we do that in code?
&lt;/p&gt;
&lt;h3&gt;Simple Service Locator
&lt;/h3&gt;
&lt;p&gt;
I had some spare time while at DevConnections, and decided to create just that - a
code-based service locator.&amp;#160; The basic idea is that we'll have a ServiceLocator
class that maps interface types to concrete types.
&lt;/p&gt;
&lt;p&gt;
At some point in your code, you register a concrete type for an interface:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;&lt;span style="color: #2b91af"&gt;ServiceLocator&lt;/span&gt; locator
= &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ServiceLocator&lt;/span&gt;();&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;locator.Register&amp;lt;&lt;span style="color: #2b91af"&gt;ITest&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Test&lt;/span&gt;));&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
This means that when we ask for instance of the interface ITest, ServiceLocator will
create and return an instance of Test (the implication of course is that Test implements
ITest).&amp;#160; Here's how we ask for an ITest:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;&lt;span style="color: #2b91af"&gt;ITest&lt;/span&gt; instance = locator.Get&amp;lt;&lt;span style="color: #2b91af"&gt;ITest&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
If you expose a singleton instance of ServiceLocator in your application, you can
register your types at startup, and then use the locator to instantiate the concrete
types from anywhere in the code.
&lt;/p&gt;
&lt;h3&gt;What about parameterized constructors?
&lt;/h3&gt;
&lt;p&gt;
Default constructors are the trivial case.&amp;#160; How do we handle creation of concrete
types that require constructor parameters?&amp;#160; We have two cases:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
The parameter is an interface that we want ServiceLocator to instantiate 
&lt;/li&gt;
&lt;li&gt;
The parameter is a value that we want to provide explicitly. 
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
Here's how we handle the first case:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;locator.Register&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Cat&lt;/span&gt;), &lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;IOwner&lt;/span&gt;));&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;locator.Register&amp;lt;&lt;span style="color: #2b91af"&gt;IOwner&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Owner&lt;/span&gt;));&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&amp;#160;&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt; instance = locator.Get&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Here we're saying that if we want an ICat, we need to create a Cat with the constructor
Cat(IOwner).&amp;#160; By registering IOwner to create an Owner, ServiceLocator is able
to create a Cat by first instantiating an Owner and passing that value to the Cat
constructor.
&lt;/p&gt;
&lt;p&gt;
In the second case, we have some value that ServiceLocator doesn't know how to create.&amp;#160;
Let's suppose the Cat constructor takes an IOwner and a string:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;locator.Register&amp;lt;&lt;span style="color: #2b91af"&gt;IOwner&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Owner&lt;/span&gt;));&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;locator.Register&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;Cat&lt;/span&gt;), &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;TypeParameter&lt;/span&gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;IOwner&lt;/span&gt;)), &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;TypeParameter&lt;/span&gt;(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: blue"&gt;string&lt;/span&gt;), &lt;span style="color: #a31515"&gt;&amp;quot;Kitty&amp;quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt; cat = locator.Get&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
In this case, ServiceLocator will call the constructor Cat(IOwner, string) with an
IOwner it creates, and the string &amp;quot;Kitty&amp;quot;.
&lt;/p&gt;
&lt;h3&gt;And Singletons?
&lt;/h3&gt;
&lt;p&gt;
Sometimes we always want the same instance of an object:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;&lt;span style="color: #2b91af"&gt;Cat&lt;/span&gt; kitty = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;Cat&lt;/span&gt;();&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;locator.Register&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;(kitty);&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt; cat = locator.Get&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Here we always return the instance kitty when an ICat is requested.&amp;#160; We all know
how hard it is to work with a large number of cats.
&lt;/p&gt;
&lt;h3&gt;Le Delegate
&lt;/h3&gt;
&lt;p&gt;
Yes, there is a Santa Claus.&amp;#160; I might have some code that is responsible for
creating an object.&amp;#160; Perhaps it's responsible for managing a pool of objects,
or just has some complexity that would be difficult to express in configuration.&amp;#160;
I want to register a delegate that will provide the instance.
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new"&gt;
&lt;pre style="margin: 0px"&gt;locator.Register&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;(&lt;span style="color: blue"&gt;delegate&lt;/span&gt;()
{ &lt;span style="color: blue"&gt;return&lt;/span&gt; kitty.IsSleeping ? buffy : kitty; });&lt;/pre&gt;
&lt;pre style="margin: 0px"&gt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt; cat = locator.Get&amp;lt;&lt;span style="color: #2b91af"&gt;ICat&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
Here I provided an anonymous method in the Register() call, but I could just as easily
register some other class method.
&lt;/p&gt;
&lt;p&gt;
So there you have it - a configuration-free service locator with quite a bit of flexibility
in object creation.
&lt;/p&gt;
&lt;p&gt;
You can download the source for my ServiceLocator &lt;a href="http://www.teamjohnston.net/files/ServiceLocator.zip"&gt;here&lt;/a&gt;.&amp;#160;
The project was built in Visual Studio 2008.
&lt;/p&gt;
&lt;h3&gt;Should I Use it?
&lt;/h3&gt;
&lt;p&gt;
If it works for you!&amp;#160; It's free of course.&amp;#160; However, I conjured this up
in an hour or two, so it's not likely that ServiceLocator offers anywhere near the
capabilities of a full-fledged dependency injection framework.&amp;#160; I'd encourage
you to look closely at &lt;a href="http://www.castleproject.org/container/index.html"&gt;Castle
Windsor&lt;/a&gt;, &lt;a href="http://www.springframework.net/"&gt;Spring.NET&lt;/a&gt; and &lt;a href="http://structuremap.sourceforge.net/Default.htm"&gt;StructureMap&lt;/a&gt;.&amp;#160;
I'm sure that there are other great frameworks too.
&lt;/p&gt;
&lt;p&gt;
I'd be grateful for any feedback as always.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=95a12ae3-4be8-4521-bf2b-7e7a0c3ae253" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,95a12ae3-4be8-4521-bf2b-7e7a0c3ae253.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=6c3a2764-d132-4db0-a646-12b9b01cea31</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,6c3a2764-d132-4db0-a646-12b9b01cea31.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,6c3a2764-d132-4db0-a646-12b9b01cea31.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=6c3a2764-d132-4db0-a646-12b9b01cea31</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Today's entry is dedicated to environmental appreciation.
</p>
        <p>
In the early ages of man, the earth was wild, cold, and full of danger.  We have
waged war on the unruly forces of nature for thousands of years.  Compared to
our savage upbringings, we live now in an unimaginable paradise of warmth, comfort
and plenty.  A few isolated families scattered over a wide dark land now find
themselves amongst a crowd of constant companionship and entertainments.  So
far we have come.
</p>
        <p>
We have laid low mountains, dammed rivers, harnessed the atom.  Nothing can withstand
us.  Yet with our great advances, we've lost many of the empty spaces in our
world.  Most is paved, groomed and domesticated.  So much so that few of
us could live without civilization.  We could not feed or shelter ourselves,
or find our way through a wild land.  Our very souls are tamed by the comfort
and convenience of modern life.
</p>
        <p>
That is why I value what wilderness and open spaces we have left.  Walking amongst
the mountains and woods of nature is a breath-taking experience of the natural beauty
and majesty of creation, so absent from our everyday modern reality.
</p>
        <p>
          <a href="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/BlogActionDay_137A6/2468_2.jpg">
            <img style="border-right: 0px; border-top: 0px; margin: 0px 10px 0px 0px; border-left: 0px; border-bottom: 0px" height="184" alt="2468" src="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/BlogActionDay_137A6/2468_thumb.jpg" width="244" align="left" border="0" />
          </a>It's
an opportunity to recapture the simple joy of challenging ourselves against primal
forces.  Hiking long distances, climbing, finding food, making fire and shelter. 
Having to rely on your own problem-solving abilities and carry your own water. 
Can we claim to be human without doing these things?
</p>
        <p>
Every year I take my family on a pilgrimage to the woods.  Every time there are
aches and pains, cold mornings, and often rain.  And yet it's always the best
week of the year.
</p>
        <p>
In the struggle against nature, we have defined ourselves.  Now that we are victorious,
we have the luxury to choose how we relate to nature.  I'm grateful that we have
chosen to preserve at least some of it, and hopeful that we will be good stewards
to what is left of this crucible of humanity.  We have enough pavement.
</p>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=6c3a2764-d132-4db0-a646-12b9b01cea31" />
      </body>
      <title>Blog Action Day</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,6c3a2764-d132-4db0-a646-12b9b01cea31.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,6c3a2764-d132-4db0-a646-12b9b01cea31.aspx</link>
      <pubDate>Tue, 16 Oct 2007 06:09:49 GMT</pubDate>
      <description>&lt;p&gt;
Today's entry is dedicated to environmental appreciation.
&lt;/p&gt;
&lt;p&gt;
In the early ages of man, the earth was wild, cold, and full of danger.&amp;nbsp; We have
waged war on the unruly forces of nature for thousands of years.&amp;nbsp; Compared to
our savage upbringings, we live now in an unimaginable paradise of warmth, comfort
and plenty.&amp;nbsp; A few isolated families scattered over a wide dark land now find
themselves amongst a crowd of constant companionship and entertainments.&amp;nbsp; So
far we have come.
&lt;/p&gt;
&lt;p&gt;
We have laid low mountains, dammed rivers, harnessed the atom.&amp;nbsp; Nothing can withstand
us.&amp;nbsp; Yet with our great advances, we've lost many of the empty spaces in our
world.&amp;nbsp; Most is paved, groomed and domesticated.&amp;nbsp; So much so that few of
us could live without civilization.&amp;nbsp; We could not feed or shelter ourselves,
or find our way through a wild land.&amp;nbsp; Our very souls are tamed by the comfort
and convenience of modern life.
&lt;/p&gt;
&lt;p&gt;
That is why I value what wilderness and open spaces we have left.&amp;nbsp; Walking amongst
the mountains and woods of nature is a breath-taking experience of the natural beauty
and majesty of creation, so absent from our everyday modern reality.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/BlogActionDay_137A6/2468_2.jpg"&gt;&lt;img style="border-right: 0px; border-top: 0px; margin: 0px 10px 0px 0px; border-left: 0px; border-bottom: 0px" height="184" alt="2468" src="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/BlogActionDay_137A6/2468_thumb.jpg" width="244" align="left" border="0"&gt;&lt;/a&gt;It's
an opportunity to recapture the simple joy of challenging ourselves against primal
forces.&amp;nbsp; Hiking long distances, climbing, finding food, making fire and shelter.&amp;nbsp;
Having to rely on your own problem-solving abilities and carry your own water.&amp;nbsp;
Can we claim to be human without doing these things?
&lt;/p&gt;
&lt;p&gt;
Every year I take my family on a pilgrimage to the woods.&amp;nbsp; Every time there are
aches and pains, cold mornings, and often rain.&amp;nbsp; And yet it's always the best
week of the year.
&lt;/p&gt;
&lt;p&gt;
In the struggle against nature, we have defined ourselves.&amp;nbsp; Now that we are victorious,
we have the luxury to choose how we relate to nature.&amp;nbsp; I'm grateful that we have
chosen to preserve at least some of it, and hopeful that we will be good stewards
to what is left of this crucible of humanity.&amp;nbsp; We have enough pavement.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=6c3a2764-d132-4db0-a646-12b9b01cea31" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,6c3a2764-d132-4db0-a646-12b9b01cea31.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=e1af67f6-fe7a-4567-9d1a-ce75000aa327</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,e1af67f6-fe7a-4567-9d1a-ce75000aa327.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,e1af67f6-fe7a-4567-9d1a-ce75000aa327.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=e1af67f6-fe7a-4567-9d1a-ce75000aa327</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Note: You can download the complete implementation <a href="http://www.teamjohnston.net/files/ObjectListView.zip">here</a>.
</p>
        <p>
I just posted a new version of ObjectListView that fixes a couple of bugs and
adds some minor usability enhancements.
</p>
        <p>
I've been using ObjectListView more in different projects, and I'm feeling the pain
points.  Foremost, a complete IBindingListView implementation means that interaction
with Windows Forms controls works smoothly, but that doesn't mean it's easy for the
developer to use.
</p>
        <h3>PropertyDescriptors Everywhere
</h3>
        <p>
I don't like working with PropertyDescriptors as method parameters.  In order
to find a list item via IBindingList,.Find(), you need to get the descriptors for
the list item type from TypeDescriptor, and then look up the correct one by the property
name.  Awkward.  Moreover, all that Find() gives you is the first item
found for which one property equals a specified value.  I've added two more useful
Find() overloads.  One takes a string expression that can be an arbitrarily complex
set of property comparisons (using the same syntax as the Filter property). 
The other allows you to specify a Predicate delegate to provide a comparison in code. 
Given these, the original Find() required for IBindingList seems unlikely to be used,
so I changed it to an explicit interface implementation.  This has the effect
of hiding the overload from the publicly exposed class methods, but still making it
available to consumers of IBindingList.
</p>
        <h3>Select
</h3>
        <p>
One of the useful methods of DataTable is Select(), which returns the set of DataRows
in the table that match a given criteria.  Now clearly, you could iterate over
the items in the view yourself and evaluate each, but having this built in to ObjectListView
is very convenient.  As with Find(), I added two versions, one that takes a string
expression, and the other that takes a delegate.  The return value of Select
is a list of items that match the criteria.
</p>
        <h3>Property Paths
</h3>
        <p>
Something I've had in mind for a while is being able to filter on list items based
on the values of properties of properties.  You could use FilterPredicate to
specify such a filter with a delegate, but it would be even more convenient to use
an expression like "Customer.AccountRep.Department = 2".  The new version 1.0.0.11
supports this kind of property path in the Filter property, Find() and Select(). 
Currently, changing the value of one of the sub-properties specified in a Filter property
path will <strong>not</strong> cause the view to be updated.  I need to
do more work before I have an efficient implementation of the notification logic.
</p>
        <h3>Item Deletion Events
</h3>
        <p>
ObjectListView has always provided the ListChanged event, which specifies an action
type (ListChangedType).  One of the actions reported is Deleted, indicating that
a list item has been removed.  Unfortunately, only the index of the item deleted
is available at the time the event is raised; the item has already been removed. 
I've added the RemovingItem event, which is raised just before an item is removed
from the list.  This event is only raised when an item is removed through a method
of ObjectListView (for example, view.Remove() or view.RemoveAt()).  If an item
is removed through a method of the underlying list, the deletion is reported to ObjectListView
after the fact, so RemovingItem cannot be raised.
</p>
        <h3>Bugs
</h3>
        <p>
As always, a few bugs are fixed, and some minor clean-up done.  See the change
log for details.
</p>
        <h3>What's Cooking?
</h3>
        <p>
As I mentioned, there's work yet to be done in keeping the view up to date as sub-properties
specified in the Filter expression change.  I'm also working on dynamic properties
that can be added to the view.  These would be analogous to the expression columns
supported by DataTable.
</p>
        <p>
I'm also excited to be presenting ObjectListView at the <a href="http://pdx.techevents.info/codecamp/3/default.aspx">Portland
Code Camp</a> in two weeks!  I think it will be hard to explain it all in an
hour.  I'll just have to talk really, really fast.
</p>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=e1af67f6-fe7a-4567-9d1a-ce75000aa327" />
      </body>
      <title>ObjectListView Update (1.0.0.11): Find, Select, &amp;amp; Property Paths</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,e1af67f6-fe7a-4567-9d1a-ce75000aa327.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,e1af67f6-fe7a-4567-9d1a-ce75000aa327.aspx</link>
      <pubDate>Mon, 07 May 2007 05:03:09 GMT</pubDate>
      <description>&lt;p&gt;
Note: You can download the complete implementation &lt;a href="http://www.teamjohnston.net/files/ObjectListView.zip"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
I just posted a new version of&amp;nbsp;ObjectListView that fixes a couple of bugs and
adds some minor usability enhancements.
&lt;/p&gt;
&lt;p&gt;
I've been using ObjectListView more in different projects, and I'm feeling the pain
points.&amp;nbsp; Foremost, a complete IBindingListView implementation means that interaction
with Windows Forms controls works smoothly, but that doesn't mean it's easy for the
developer to use.
&lt;/p&gt;
&lt;h3&gt;PropertyDescriptors Everywhere
&lt;/h3&gt;
&lt;p&gt;
I don't like working with PropertyDescriptors as method parameters.&amp;nbsp; In order
to find a list item via IBindingList,.Find(), you need to get the descriptors for
the list item type from TypeDescriptor, and then look up the correct one by the property
name.&amp;nbsp; Awkward.&amp;nbsp; Moreover, all that Find() gives you&amp;nbsp;is the first item
found for which one property equals a specified value.&amp;nbsp; I've added two more useful
Find() overloads.&amp;nbsp; One takes a string expression that can be an arbitrarily complex
set of property comparisons (using the same syntax as the Filter property).&amp;nbsp;
The other allows you to specify a Predicate delegate to provide a comparison in code.&amp;nbsp;
Given these, the original Find() required for IBindingList seems unlikely to be used,
so I changed it to an explicit interface implementation.&amp;nbsp; This has the effect
of hiding the overload from the publicly exposed class methods, but still making it
available to consumers of IBindingList.
&lt;/p&gt;
&lt;h3&gt;Select
&lt;/h3&gt;
&lt;p&gt;
One of the useful methods of DataTable is Select(), which returns the set of DataRows
in the table that match a given criteria.&amp;nbsp; Now clearly, you could iterate over
the items in the view yourself and evaluate each, but having this built in to ObjectListView
is very convenient.&amp;nbsp; As with Find(), I added two versions, one that takes a string
expression, and the other that takes a delegate.&amp;nbsp; The return value of Select
is a list of items that match the criteria.
&lt;/p&gt;
&lt;h3&gt;Property Paths
&lt;/h3&gt;
&lt;p&gt;
Something I've had in mind for a while is being able to filter on list items based
on the values of properties of properties.&amp;nbsp; You could use FilterPredicate to
specify such a filter with a delegate, but it would be even more convenient to use
an expression like "Customer.AccountRep.Department = 2".&amp;nbsp; The new version 1.0.0.11
supports this kind of property path in the Filter property, Find() and Select().&amp;nbsp;
Currently, changing the value of one of the sub-properties specified in a Filter property
path&amp;nbsp;will &lt;strong&gt;not&lt;/strong&gt; cause the view to be updated.&amp;nbsp; I need to
do more work before I have an efficient implementation of the notification logic.
&lt;/p&gt;
&lt;h3&gt;Item Deletion Events
&lt;/h3&gt;
&lt;p&gt;
ObjectListView has always provided the ListChanged event, which specifies an action
type (ListChangedType).&amp;nbsp; One of the actions reported is Deleted, indicating that
a list item has been removed.&amp;nbsp; Unfortunately, only the index of the item deleted
is available at the time the event is raised; the item has already been removed.&amp;nbsp;
I've added the RemovingItem event, which is raised just before an item is removed
from the list.&amp;nbsp; This event is only raised when an item is removed through a method
of ObjectListView (for example, view.Remove() or view.RemoveAt()).&amp;nbsp; If an item
is removed through a method of the underlying list, the deletion is reported to ObjectListView
after the fact, so RemovingItem cannot be raised.
&lt;/p&gt;
&lt;h3&gt;Bugs
&lt;/h3&gt;
&lt;p&gt;
As always, a few bugs are fixed, and some minor clean-up done.&amp;nbsp; See the change
log for details.
&lt;/p&gt;
&lt;h3&gt;What's Cooking?
&lt;/h3&gt;
&lt;p&gt;
As I mentioned, there's work yet to be done in keeping the view up to date as sub-properties
specified in the Filter expression change.&amp;nbsp; I'm also working on dynamic properties
that can be added to the view.&amp;nbsp; These would be analogous to the expression columns
supported by DataTable.
&lt;/p&gt;
&lt;p&gt;
I'm also excited to be presenting ObjectListView at the &lt;a href="http://pdx.techevents.info/codecamp/3/default.aspx"&gt;Portland
Code Camp&lt;/a&gt; in two weeks!&amp;nbsp; I think it will be hard to explain it all in an
hour.&amp;nbsp; I'll just have to talk really, really fast.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=e1af67f6-fe7a-4567-9d1a-ce75000aa327" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,e1af67f6-fe7a-4567-9d1a-ce75000aa327.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=a77d0675-8d15-48c2-bdce-43096ba7dbce</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,a77d0675-8d15-48c2-bdce-43096ba7dbce.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,a77d0675-8d15-48c2-bdce-43096ba7dbce.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=a77d0675-8d15-48c2-bdce-43096ba7dbce</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I just got a new notebook PC with Vista pre-installed.  After removing all the
OEM applications and finally re-paving to remove a wasted (er, "recovery") partition,
I'm installing all my development tools.
</p>
        <p>
One tool I've really come to appreciate is the <a href="http://ankhsvn.tigris.org/">AnkhSVN</a> plugin
for Visual Studio 2005.  Ankh integrates the <a href="http://subversion.tigris.org/">Subversion</a> (SVN)
source code control system with VS.  I've used Subversion at work for the last
two years, and I have to say I'm a fan.  Even so, my prior history was with Visual
SourceSafe, and I've kept that on as my source control system at home.  No more
- I've decided to take the plunge and move to SVN everywhere.
</p>
        <p>
Unfortunately, after installing AnkhSVN and restarting Visual Studio, I received a
not-too-helpful error message from Visual Studio: "The Add-in AnkhSVN failed to load
or caused an exception, etc etc...Class not registered  Error number: 80040154".
</p>
        <p>
Well.
</p>
        <p>
Googling turned up a <a href="http://www.nabble.com/AnkhSVN-users-Installation-problems-with-Vista-t3038769.html">thread</a> between
Jon Skeet and Arild Fines discussing the problem.  Jon was able to successfully
install Ankh after uninstalling it, adding the following registry keys, and then reinstalling
AnkhSVN:
</p>
        <p>
[HKEY_CLASSES_ROOT\AnkhUserControlHost.Ankh] <br />
[HKEY_CLASSES_ROOT\AnkhUserControlHost.Ankh\CLSID] <br />
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl] <br />
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl\CLSID] <br />
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl.1\CLSID] <br />
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl.1\CLSID] 
</p>
        <p>
I tried this and it didn't work at all.  After trying a number of over things
(also starting with "reg"), I re-tried the above steps, but chose to install for ALL
USERS instead of just me.  It worked!  Whew.
</p>
        <p>
If you're still using Visual SourceSafe, you might try giving Subversion and AnkhSVN
a shot.  I've used sccs, rcs, PVCS, VSS, CVS, and Subversion, and the Subversion
tool set is the clear winner in my opinion.  It's free, too!
</p>
        <p>
          <font color="#ff0000">Update (2/13/08):</font>  The current development pre-releases
of AnkhSVN support Vista and VS2008 with no registry changes.  I've been using
version 1.0.3.2800 for a few weeks now and it's working great.  You can get the
latest <a href="http://ankhsvn.tigris.org/servlets/ProjectDocumentList?folderID=9289&amp;expandFolder=9289&amp;folderID=7315">here</a>.
</p>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=a77d0675-8d15-48c2-bdce-43096ba7dbce" />
      </body>
      <title>Installing AnkhSVN on Vista</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,a77d0675-8d15-48c2-bdce-43096ba7dbce.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,a77d0675-8d15-48c2-bdce-43096ba7dbce.aspx</link>
      <pubDate>Thu, 26 Apr 2007 06:03:04 GMT</pubDate>
      <description>&lt;p&gt;
I just got a new notebook PC with Vista pre-installed.&amp;nbsp; After removing all the
OEM applications and finally re-paving to remove a wasted (er, "recovery") partition,
I'm installing all my development tools.
&lt;/p&gt;
&lt;p&gt;
One&amp;nbsp;tool I've really come to appreciate&amp;nbsp;is&amp;nbsp;the &lt;a href="http://ankhsvn.tigris.org/"&gt;AnkhSVN&lt;/a&gt; plugin
for Visual Studio 2005.&amp;nbsp; Ankh integrates the &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt; (SVN)
source code control system with VS.&amp;nbsp; I've used Subversion at work for the last
two years, and I have to say I'm a fan.&amp;nbsp; Even so, my prior history was with Visual
SourceSafe, and I've kept that on as my source control system at home.&amp;nbsp; No more
- I've decided to take the plunge and move to SVN everywhere.
&lt;/p&gt;
&lt;p&gt;
Unfortunately, after installing AnkhSVN and restarting Visual Studio, I received a
not-too-helpful error message from Visual Studio: "The Add-in AnkhSVN failed to load
or caused an exception, etc etc...Class not registered&amp;nbsp; Error number: 80040154".
&lt;/p&gt;
&lt;p&gt;
Well.
&lt;/p&gt;
&lt;p&gt;
Googling turned up a &lt;a href="http://www.nabble.com/AnkhSVN-users-Installation-problems-with-Vista-t3038769.html"&gt;thread&lt;/a&gt; between
Jon Skeet and Arild Fines discussing the problem.&amp;nbsp; Jon was able to successfully
install Ankh after uninstalling it, adding the following registry keys, and then reinstalling
AnkhSVN:
&lt;/p&gt;
&lt;p&gt;
[HKEY_CLASSES_ROOT\AnkhUserControlHost.Ankh]&amp;nbsp;&lt;br&gt;
[HKEY_CLASSES_ROOT\AnkhUserControlHost.Ankh\CLSID]&amp;nbsp;&lt;br&gt;
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl]&amp;nbsp;&lt;br&gt;
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl\CLSID]&amp;nbsp;&lt;br&gt;
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl.1\CLSID]&amp;nbsp;&lt;br&gt;
[HKEY_CLASSES_ROOT\AnkhUserControlHost.AnkhUserControlHostCtl.1\CLSID]&amp;nbsp;
&lt;/p&gt;
&lt;p&gt;
I tried this and it didn't work at all.&amp;nbsp; After trying a number of over things
(also starting with "reg"), I re-tried the above steps, but chose to install for ALL
USERS instead of just me.&amp;nbsp; It worked!&amp;nbsp; Whew.
&lt;/p&gt;
&lt;p&gt;
If you're still using Visual SourceSafe, you might try giving Subversion and AnkhSVN
a shot.&amp;nbsp;&amp;nbsp;I've used sccs, rcs, PVCS, VSS, CVS, and Subversion, and the Subversion
tool set is the clear winner in my opinion.&amp;nbsp;&amp;nbsp;It's free, too!
&lt;/p&gt;
&lt;p&gt;
&lt;font color=#ff0000&gt;Update (2/13/08):&lt;/font&gt;&amp;nbsp; The current development pre-releases
of AnkhSVN support Vista and VS2008 with no registry changes.&amp;nbsp; I've been using
version 1.0.3.2800 for a few weeks now and it's working great.&amp;nbsp; You can get the
latest &lt;a href="http://ankhsvn.tigris.org/servlets/ProjectDocumentList?folderID=9289&amp;amp;expandFolder=9289&amp;amp;folderID=7315"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=a77d0675-8d15-48c2-bdce-43096ba7dbce" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,a77d0675-8d15-48c2-bdce-43096ba7dbce.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=3b7c2a76-8663-4bb6-8a32-b023abf5a241</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,3b7c2a76-8663-4bb6-8a32-b023abf5a241.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,3b7c2a76-8663-4bb6-8a32-b023abf5a241.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=3b7c2a76-8663-4bb6-8a32-b023abf5a241</wfw:commentRss>
      <slash:comments>1</slash:comments>
      <title>Serialization Problems and Solutions</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,3b7c2a76-8663-4bb6-8a32-b023abf5a241.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,3b7c2a76-8663-4bb6-8a32-b023abf5a241.aspx</link>
      <pubDate>Mon, 09 Apr 2007 04:11:42 GMT</pubDate>
      <description>&lt;p&gt;
.NET serialization is a very simple concept, yet often fails to work the way we'd
expect.&amp;nbsp; The basic idea is that you're converting objects from their in-memory
format to some other form, and then back again.
&lt;/p&gt;
&lt;p&gt;
Today I'll walk through some common scenarios that you might encounter when serializing
objects to a file with the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter(vs.80).aspx"&gt;BinaryFormatter&lt;/a&gt;.&amp;nbsp;
The complete set of code examples is provided for download &lt;a href="http://www.teamjohnston.net/files/FunWithSerialization.zip"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;h3&gt;The Serializable Attribute
&lt;/h3&gt;
&lt;p&gt;
In order to enable serialization, you must annotate the class to be serialized with
the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.serializableattribute(vs.80).aspx"&gt;Serializable&lt;/a&gt; attribute:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; [&lt;span style="color: #2b91af"&gt;Serializable&lt;/span&gt;]
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&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: #2b91af"&gt;CustomerSerializable&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; id;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; company;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; ...
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
To convert an object from it's in-memory form and&amp;nbsp;write it to a file, we use
a BinaryFormatter:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;BinaryFormatter&lt;/span&gt; formatter = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;BinaryFormatter&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;CustomerSerializable&lt;/span&gt; customer1 = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;CustomerSerializable&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
customer1.City = &lt;span style="color: #a31515"&gt;"Bothell"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
customer1.Region = &lt;span style="color: #a31515"&gt;"WA"&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;FileStream&lt;/span&gt; stream
= &lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.Create(&lt;span style="color: #a31515"&gt;"Serialized.dat"&lt;/span&gt;))
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; formatter.Serialize(stream, customer1);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Once&amp;nbsp;we have persisted an object to a file using the above code, we can reverse
the process by reading the object from the file and rehydrating it in memory:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;BinaryFormatter&lt;/span&gt; formatter = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;BinaryFormatter&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;CustomerSerializable&lt;/span&gt; customer2 = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;FileStream&lt;/span&gt; stream
= &lt;span style="color: #2b91af"&gt;File&lt;/span&gt;.OpenRead(&lt;span style="color: #a31515"&gt;"Serialized.dat"&lt;/span&gt;))
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; customer2 = (&lt;span style="color: #2b91af"&gt;CustomerSerializable&lt;/span&gt;)formatter.Deserialize(stream);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Pretty simple, huh?&amp;nbsp; Of course there are complications in the real world, as
we shall see.
&lt;/p&gt;
&lt;h3&gt;How Does it Work?
&lt;/h3&gt;
&lt;p&gt;
Essentially, in the simple case shown above, the formatter finds all of the fields
of your class using Reflection, and reads their values during serialization.&amp;nbsp;
During deserialization, the data is read from the file and restored to a new empty
object.&amp;nbsp; Interestingly, in the simple case, no constructor of your serialized
class is called during deserialization.
&lt;/p&gt;
&lt;h3&gt;&lt;a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.iserializable(VS.80).aspx"&gt;ISerializable&lt;/a&gt;
&lt;/h3&gt;
&lt;p&gt;
You might have heard about the ISerializable interface.&amp;nbsp; Isn't implementing that
just another way of saying that my class is serializable?&amp;nbsp; Not quite.&amp;nbsp; You
still have to apply the Serializable attribute to the class.&amp;nbsp; ISerializable just
allows us to serialize and deserialize the data in a customized way.&amp;nbsp; Usually,
this means saving only some of the data, or transforming the data before saving it.&amp;nbsp;
Again, you must still apply the Serializable attribute to your class.&amp;nbsp; If you
don't, BinaryFormatter.Serialize() will throw a SerializationException, even though
your class supports ISerializable.
&lt;/p&gt;
&lt;h3&gt;Unserializable Fields and Bases
&lt;/h3&gt;
&lt;p&gt;
Adding the Serializable attribute to your class is all well and good if the base class
(and it's base, etc) and all of the fields of your class are also serializable.&amp;nbsp;
But what if they aren't?&amp;nbsp; In either case, the Serializable attribute isn't enough
- this is where ISerializable is needed.&amp;nbsp; Let's suppose the base class isn't
serializable:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;BaseNotSerializable&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;int&lt;/span&gt; totalOrders;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;int&lt;/span&gt; OrderTotal
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;get&lt;/span&gt; { &lt;span style="color: blue"&gt;return&lt;/span&gt; totalOrders;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;set&lt;/span&gt; { totalOrders
= &lt;span style="color: blue"&gt;value&lt;/span&gt;; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
[&lt;span style="color: #2b91af"&gt;Serializable&lt;/span&gt;]
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;CustomerBaseNotSerializableISerializable&lt;/span&gt; : &lt;span style="color: #2b91af"&gt;BaseNotSerializable&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;ISerializable&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; id;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; company;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ...
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
By declaring support for ISerializable, we're telling BinaryFormatter to do two things.&amp;nbsp;
First, when serializing, our &lt;a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.iserializable.getobjectdata(VS.80).aspx"&gt;GetObjectData&lt;/a&gt; method
should be called instead of using the Reflection-based mechanism for reading our object's
data.&amp;nbsp; Secondly,&amp;nbsp;during deserialization a special constructor should be
called instead of rehydrating the object in the normal way.&amp;nbsp; In each case, we'll
be provided with a &lt;a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.serializationinfo(vs.80).aspx"&gt;SerializationInfo&lt;/a&gt; object
that contains the data being transferred to or from the object.&amp;nbsp; Our job in GetObjectData()
is to save the data&amp;nbsp;from our object and&amp;nbsp;from the unserializable base of
our object:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;void&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ISerializable&lt;/span&gt;.GetObjectData(&lt;span style="color: #2b91af"&gt;SerializationInfo&lt;/span&gt; info, &lt;span style="color: #2b91af"&gt;StreamingContext&lt;/span&gt; context)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;// Serialize data from the base.&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"OrderTotal"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.OrderTotal);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Address"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.address);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"City"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.city);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Company"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.company);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"ContactName"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.contactName);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"ContactTitle"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.contactTitle);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Country"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.country);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Fax"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.fax);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Id"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.id);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Phone"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.phone);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Region"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.region);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"ZipCode"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.zipcode);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
If our class contained a field that wasn't serializable, we could just skip it in
GetObjectData(), or save some other piece of serializable information that we could
use later to restore the value.
&lt;/p&gt;
&lt;p&gt;
During deserialization, the special constructor is called, allowing us to read the
data back into our object:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;public&lt;/span&gt; CustomerBaseNotSerializableISerializable(&lt;span style="color: #2b91af"&gt;SerializationInfo&lt;/span&gt; info, &lt;span style="color: #2b91af"&gt;StreamingContext&lt;/span&gt; context)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;// Deserialize data to the base.&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.OrderTotal = info.GetInt32(&lt;span style="color: #a31515"&gt;"OrderTotal"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.address = info.GetString(&lt;span style="color: #a31515"&gt;"Address"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.city = info.GetString(&lt;span style="color: #a31515"&gt;"City"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.company = info.GetString(&lt;span style="color: #a31515"&gt;"Company"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.contactName = info.GetString(&lt;span style="color: #a31515"&gt;"ContactName"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.contactTitle = info.GetString(&lt;span style="color: #a31515"&gt;"ContactTitle"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.country = info.GetString(&lt;span style="color: #a31515"&gt;"Country"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.fax = info.GetString(&lt;span style="color: #a31515"&gt;"Fax"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.id = info.GetString(&lt;span style="color: #a31515"&gt;"Id"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.phone = info.GetString(&lt;span style="color: #a31515"&gt;"Phone"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.region = info.GetString(&lt;span style="color: #a31515"&gt;"Region"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.zipcode = info.GetString(&lt;span style="color: #a31515"&gt;"ZipCode"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Something to note about this constructor is that it is required when ISerializable
is implemented, but it is not part of the ISerializable interface, so it is easy to
accidentally omit.&amp;nbsp; The compiler won't complain, because you have met the ISerializable
implementation requirements by providing GetObjectData().&amp;nbsp; A SerializationException
will be thrown at run-time if the constructor is not present.&amp;nbsp; As I mentioned
earlier, no constructor is&amp;nbsp;called in the simple case where ISerializable is not
implemented.
&lt;/p&gt;
&lt;h3&gt;But it's not my class!
&lt;/h3&gt;
&lt;p&gt;
Implementing ISerializable is a great solution when you're writing your own class.&amp;nbsp;
Sometimes, however, you need to serialize an object provided by a third-party library
or the .NET framework itself.&amp;nbsp; If the class wasn't implemented with the Serializable
attribute, you might think that you're&amp;nbsp;stuck.&amp;nbsp; Fortunately, there's a way
around this obstacle, too.&amp;nbsp; Enter the serialization surrogate.
&lt;/p&gt;
&lt;p&gt;
A serialization surrogate is a class that implements &lt;a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.iserializationsurrogate(vs.80).aspx"&gt;ISerializationSurrogate&lt;/a&gt;,
and knows how to serialize and deserialize some other class.&amp;nbsp; We inject this
knowledge into the serialization process by attaching the surrogate to the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.runtime.serialization.formatters.binary.binaryformatter.surrogateselector(VS.80).aspx"&gt;SurrogateSelector&lt;/a&gt; of
the BinaryFormatter:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;BinaryFormatter&lt;/span&gt; formatter = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;BinaryFormatter&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;SurrogateSelector&lt;/span&gt; selector = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;SurrogateSelector&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
selector.AddSurrogate(&lt;span style="color: blue"&gt;typeof&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt;), &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;StreamingContext&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;StreamingContextStates&lt;/span&gt;.All), &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;CustomerNotSerializableSerializationSurrogate&lt;/span&gt;());
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
formatter.SurrogateSelector = selector;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt; customer1 = &lt;span style="color: blue"&gt;new&lt;/span&gt; &lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt;();
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; (FileStream stream = File.Create(&lt;span style="color: #a31515"&gt;"Serialized.dat"&lt;/span&gt;))
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; formatter.Serialize(stream, customer1);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt; customer2 = &lt;span style="color: blue"&gt;null&lt;/span&gt;;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;using&lt;/span&gt; (FileStream stream = File.OpenRead(&lt;span style="color: #a31515"&gt;"Serialized.dat"&lt;/span&gt;))
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; customer2 = (&lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt;)formatter.Deserialize(stream);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Now when formatter.Serialize() and formatter.Deserialize() are called, the SurrogateSelector
is consulted, and methods of the provided CustomerNotSerializableSerializationSurrogate
class are called to perform the needed operations:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;class&lt;/span&gt; &lt;span style="color: #2b91af"&gt;CustomerNotSerializableSerializationSurrogate&lt;/span&gt; : &lt;span style="color: #2b91af"&gt;ISerializationSurrogate&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;// GetObjectData is called to serialize
the object.&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;void&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ISerializationSurrogate&lt;/span&gt;.GetObjectData(&lt;span style="color: blue"&gt;object&lt;/span&gt; obj, &lt;span style="color: #2b91af"&gt;SerializationInfo&lt;/span&gt; info, &lt;span style="color: #2b91af"&gt;StreamingContext&lt;/span&gt; context)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt; customer
= (&lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt;)obj;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Address"&lt;/span&gt;,
customer.Address);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"City"&lt;/span&gt;,
customer.City);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Company"&lt;/span&gt;,
customer.Company);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"ContactName"&lt;/span&gt;,
customer.ContactName);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"ContactTitle"&lt;/span&gt;,
customer.ContactTitle);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Country"&lt;/span&gt;,
customer.Country);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Fax"&lt;/span&gt;,
customer.Fax);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Id"&lt;/span&gt;,
customer.Id);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Phone"&lt;/span&gt;,
customer.Phone);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Region"&lt;/span&gt;,
customer.Region);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"ZipCode"&lt;/span&gt;,
customer.ZipCode);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;// SetObjectData is called to deserialize
the object.&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;object&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ISerializationSurrogate&lt;/span&gt;.SetObjectData(&lt;span style="color: blue"&gt;object&lt;/span&gt; obj, &lt;span style="color: #2b91af"&gt;SerializationInfo&lt;/span&gt; info, &lt;span style="color: #2b91af"&gt;StreamingContext&lt;/span&gt; context, &lt;span style="color: #2b91af"&gt;ISurrogateSelector&lt;/span&gt; selector)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt; customer
= (&lt;span style="color: #2b91af"&gt;CustomerNotSerializable&lt;/span&gt;)obj;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.Address = info.GetString(&lt;span style="color: #a31515"&gt;"Address"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.City = info.GetString(&lt;span style="color: #a31515"&gt;"City"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.Company = info.GetString(&lt;span style="color: #a31515"&gt;"Company"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.ContactName = info.GetString(&lt;span style="color: #a31515"&gt;"ContactName"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.ContactTitle = info.GetString(&lt;span style="color: #a31515"&gt;"ContactTitle"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.Country = info.GetString(&lt;span style="color: #a31515"&gt;"Country"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.Fax = info.GetString(&lt;span style="color: #a31515"&gt;"Fax"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.Id = info.GetString(&lt;span style="color: #a31515"&gt;"Id"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.Phone = info.GetString(&lt;span style="color: #a31515"&gt;"Phone"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.Region = info.GetString(&lt;span style="color: #a31515"&gt;"Region"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; customer.ZipCode = info.GetString(&lt;span style="color: #a31515"&gt;"ZipCode"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;return&lt;/span&gt; customer;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
You've probably noticed some similarity between the surrogate class and an implementation
of ISerializable.&amp;nbsp; It's essentially the same thing, with the surrogate being
decoupled from the class being serialized.
&lt;/p&gt;
&lt;h3&gt;The Evil Conspiracy of Event Handlers
&lt;/h3&gt;
&lt;p&gt;
.NET events are a great architectural feature, but they can pose unexpected problems
in serialization.&amp;nbsp; When you're serializing an object that contains an event,
you potentially could be serializing objects of &lt;strong&gt;any&lt;/strong&gt; .NET class.&amp;nbsp;
How could this possibly be, you ask?
&lt;/p&gt;
&lt;p&gt;
Events are sneaky.&amp;nbsp; Very sneaky.&amp;nbsp; Think about it for a minute.&amp;nbsp; An
event is just a delegate field with some sugary syntax to make it more convenient.&amp;nbsp;
A delegate is a list of zero or more methods to call when the event is raised.&amp;nbsp;
Each method in the delegate's list references a specific&amp;nbsp;object (if it is an
instance method).&amp;nbsp; If any event handlers have been added to your event, these
objects will be serialized&amp;nbsp;when you serialize the object containing the event!
&lt;/p&gt;
&lt;p&gt;
Typically, you just don't want to serialize the delegate field of an event.&amp;nbsp;
You might also have other fields in your class that aren't serializable or that you
just don't need to persist.&amp;nbsp; For these cases, the &lt;a href="http://msdn2.microsoft.com/en-us/library/system.nonserializedattribute(vs.80).aspx"&gt;NonSerialized&lt;/a&gt; attribute
can be applied to the field, and the serialization mechanism will ignore the field
during serialization and deserialization.&amp;nbsp; Consider these fields of a class:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; id;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; company;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: blue"&gt;string&lt;/span&gt; contactName;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
[&lt;span style="color: #2b91af"&gt;NonSerialized&lt;/span&gt;]
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyDescriptor&lt;/span&gt; lastPropertyChanged;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
[&lt;span style="color: #2b91af"&gt;NonSerialized&lt;/span&gt;]
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyDescriptorCollection&lt;/span&gt; properties;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
[&lt;span style="color: #2b91af"&gt;NonSerialized&lt;/span&gt;]
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;private&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler&lt;/span&gt; propChanged;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;event&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler&lt;/span&gt; PropertyChanged
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;add&lt;/span&gt; { propChanged = (&lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler&lt;/span&gt;)&lt;span style="color: #2b91af"&gt;Delegate&lt;/span&gt;.Combine(propChanged, &lt;span style="color: blue"&gt;value&lt;/span&gt;);
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;remove&lt;/span&gt; { propChanged = (&lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler&lt;/span&gt;)&lt;span style="color: #2b91af"&gt;Delegate&lt;/span&gt;.Remove(propChanged, &lt;span style="color: blue"&gt;value&lt;/span&gt;);
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
Here we have a couple of fields that aren't serializable; neither PropertyDescriptor
nor PropertyDescriptorCollection can be serialized.&amp;nbsp; I've annotated these with
[NonSerialized] so that the formatter won't attempt to serialize or deserialize them.&amp;nbsp;&amp;nbsp;Making
the PropertyChanged event&amp;nbsp;non-serialized requires the event to be broken up into
an declared delegate field and an event with explicit add and remove accessors.&amp;nbsp;
The delegate field (propChanged above) is then annotated&amp;nbsp;with [NonSerialized].&amp;nbsp;
If I had declared the event in the conventional way, I couldn't have applied the NonSerialized
attribute to the event.&amp;nbsp; The layout shown above, with an explicit delegate field
(propChanged) and event accessors acting on the delegate mirrors exactly the structure
that you would get by specifying the event conventionally:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;public&lt;/span&gt; &lt;span style="color: blue"&gt;event&lt;/span&gt; &lt;span style="color: #2b91af"&gt;PropertyChangedEventHandler&lt;/span&gt; PropertyChanged;
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
The code above is perfect for ignoring certain fields during serialization and deserialization.&amp;nbsp;
However, it may be the case that after deserialization, these fields really do need
valid values.&amp;nbsp; There are a few ways to handle this.&amp;nbsp; We could implement
ISerializable and restore the values in the special deserializing constructor.&amp;nbsp;
Alternatively, we could&amp;nbsp;provide a surrogate and restore the values in the surrogate's
SetObjectData() method.
&lt;/p&gt;
&lt;p&gt;
In the example above, lastPropertyChanged represents the last property that was changed.&amp;nbsp;
Even though PropertyDescriptor is not serializable, I can save a memento of the value
in ISerializable.GetObjectData(), and then restore the value from the memento in the
deserialization constructor:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: green"&gt;// Called during serialization (because support for ISerializable
is declared).&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;void&lt;/span&gt; &lt;span style="color: #2b91af"&gt;ISerializable&lt;/span&gt;.GetObjectData(&lt;span style="color: #2b91af"&gt;SerializationInfo&lt;/span&gt; info, &lt;span style="color: #2b91af"&gt;StreamingContext&lt;/span&gt; context)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Address"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.address);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"City"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.city);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"Company"&lt;/span&gt;, &lt;span style="color: blue"&gt;this&lt;/span&gt;.company);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ...
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt; (lastPropertyChanged != &lt;span style="color: blue"&gt;null&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; info.AddValue(&lt;span style="color: #a31515"&gt;"LastPropertyChanged"&lt;/span&gt;,
lastPropertyChanged.Name);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: green"&gt;// Called during deserialization (because support for ISerializable
is declared).&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;public&lt;/span&gt; CustomerSerializableFieldsNonSerialized(&lt;span style="color: #2b91af"&gt;SerializationInfo&lt;/span&gt; info, &lt;span style="color: #2b91af"&gt;StreamingContext&lt;/span&gt; context)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.address = info.GetString(&lt;span style="color: #a31515"&gt;"Address"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.city = info.GetString(&lt;span style="color: #a31515"&gt;"City"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;this&lt;/span&gt;.company = info.GetString(&lt;span style="color: #a31515"&gt;"Company"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; ...
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;try&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;string&lt;/span&gt; propertyName
= info.GetString(&lt;span style="color: #a31515"&gt;"LastPropertyChanged"&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;if&lt;/span&gt; (propertyName
!= &lt;span style="color: blue"&gt;null&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; lastPropertyChanged = &lt;span style="color: #2b91af"&gt;TypeDescriptor&lt;/span&gt;.GetProperties(&lt;span style="color: blue"&gt;this&lt;/span&gt;)[propertyName];
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: blue"&gt;catch&lt;/span&gt; (&lt;span style="color: #2b91af"&gt;SerializationException&lt;/span&gt;)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; {
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: green"&gt;// LastPropertyChanged
was not added when the object was serialized (see GetObjectData).&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; }
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
The key here is that even though lastPropertyChanged is not serializable, the memento
that I save instead (lastPropertyChanged.Name) is serializable.
&lt;/p&gt;
&lt;h3&gt;IDeserializationCallback
&lt;/h3&gt;
&lt;p&gt;
Another, simpler way of restoring non-serialized data, is to implement IDeserializationCallback
on the class being serialized:
&lt;/p&gt;
&lt;div style="border-right: black 1px solid; padding-right: 10px; border-top: black 1px solid; padding-left: 10px; font-size: 10pt; background: #eeeeee; padding-bottom: 10px; margin: 10px; overflow: scroll; border-left: black 1px solid; color: black; line-height: 10pt; padding-top: 10px; border-bottom: black 1px solid; font-family: courier new" ;?&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: green"&gt;// Called after deserialization (because support for IDeserializationCallback
is declared).&lt;/span&gt;
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&lt;span style="color: blue"&gt;void&lt;/span&gt; &lt;span style="color: #2b91af"&gt;IDeserializationCallback&lt;/span&gt;.OnDeserialization(&lt;span style="color: blue"&gt;object&lt;/span&gt; sender)
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
{
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; properties = &lt;span style="color: #2b91af"&gt;TypeDescriptor&lt;/span&gt;.GetProperties(&lt;span style="color: blue"&gt;this&lt;/span&gt;);
&lt;/p&gt;
&lt;p style="margin: 0px"&gt;
}
&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;
There's just one method to be provided, as shown.&amp;nbsp; It is called after deserialization
is complete.&amp;nbsp; In this example, the properties field is a collection of PropertyDescriptors
for the type being serialized.&amp;nbsp; This is the kind of data that is a perfect candidate
for IDeserializationCallback - something that can be restored without specific knowledge
of the object, or that has a reasonable default value.
&lt;/p&gt;
&lt;h3&gt;Whew.
&lt;/h3&gt;
&lt;p&gt;
Serialization can be a little complicated.&amp;nbsp; It's easier if you just remember
a few things:
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
The Serializable class attribute must always be applied OR a serialization surrogate
provided.&lt;/li&gt;
&lt;li&gt;
Unserializable bases or fields can be serialized with an ISerializable implementation
OR&amp;nbsp;by a&amp;nbsp;serialization surrogate.&lt;/li&gt;
&lt;li&gt;
Fields and events can be omitted from serialization with the NonSerialized attribute.&lt;/li&gt;
&lt;li&gt;
Non-serialized data can be restored in the ISerializable deserialization constructor
OR in the SetObject() method of a serialization surrogate OR in IDeserializationCallback.OnDeserialization().&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
And that's all I have to say about that.&amp;nbsp; Download the &lt;a href="http://www.teamjohnston.net/files/FunWithSerialization.zip"&gt;sample
code&lt;/a&gt; if you'd like to explore more.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=3b7c2a76-8663-4bb6-8a32-b023abf5a241" /&gt;</description>
      <comments>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,3b7c2a76-8663-4bb6-8a32-b023abf5a241.aspx</comments>
    </item>
    <item>
      <trackback:ping>http://www.teamjohnston.net/cs/blogs/jesse/Trackback.aspx?guid=1f38e29a-0ce0-40d2-9f24-113ff7924a02</trackback:ping>
      <pingback:server>http://www.teamjohnston.net/cs/blogs/jesse/pingback.aspx</pingback:server>
      <pingback:target>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,1f38e29a-0ce0-40d2-9f24-113ff7924a02.aspx</pingback:target>
      <dc:creator>Jesse</dc:creator>
      <wfw:comment>http://www.teamjohnston.net/cs/blogs/jesse/CommentView,guid,1f38e29a-0ce0-40d2-9f24-113ff7924a02.aspx</wfw:comment>
      <wfw:commentRss>http://www.teamjohnston.net/cs/blogs/jesse/SyndicationService.asmx/GetEntryCommentsRss?guid=1f38e29a-0ce0-40d2-9f24-113ff7924a02</wfw:commentRss>
      <slash:comments>2</slash:comments>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
Note: You can download the complete implementation <a href="http://www.teamjohnston.net/files/ObjectListView.zip">here</a>.
</p>
        <p>
For those of you just tuning in, ObjectListView is my answer to the .NET need for
a DataView-like construct for ordinary objects.  With ObjectListView, you can
have a sorted and filtered view of any IList or IList&lt;T&gt;.  You can bind
this view to controls like the DataGridView.
</p>
        <p>
This new version adds a debugger visualizer and includes a few other small enhancements
and bug fixes.
</p>
        <h3>Bug Fixes
</h3>
        <p>
Ecki found a bug in the Master/Details demo where I was doing an invalid cast in the
New button click handler.  I also found that .NET 1.1 style property change events
weren't wired properly for items already in the list at the time an ObjectListView
was constructed.  Those two are fixed.
</p>
        <p>
Boris reported that changing a list item property while iterating over ObjectListView
with a foreach loop would cause an InvalidOperationException to be thrown.  Indeed! 
This is by design; any change to a .NET collection must invalidate all enumerators
of the collection.   ObjectListView is really a view over a collection,
though, and not a collection itself.  This view presents the appearance of a
collection.  This virtual collection does change when items are added, removed,
or replaced in the underlying collection.  When the value of a list item property
changes, however, the virtual collection only changes in certain circumstances. 
Fortunately, these circumstances are well-understood:  if the property is not
included in either the ObjectListView sort or filter, the virtual collection does
not change.  In this case, there is no need to invalidate any enumeration in
progress.  In the updated version, ObjectListView allows enumeration to continue
following a list item property change if the property does not belong to the
sort or the filter criteria.
</p>
        <h3>Small Changes
</h3>
        <p>
I added a ToArray() method, as I find it irritating to have to declare an array and
copy into it with CopyTo() in two steps.  By request, OnListChanged(), OnSorted()
and OnAddingNew() are now protected virtual, for extensibility.  These methods
follow the usual convention of event-raising methods in .NET.  If you override
one of them, be sure to call the base version so that the event will in fact be raised.
</p>
        <h3>License
</h3>
        <p>
Since more than a few have asked, I've added the license terms to the Readme.txt file
of the download.  ObjectListView is free - no strings attached.
</p>
        <h3>The Visualizer
</h3>
        <p>
This is the big cool addition in my estimation.  If you're debugging a program
that uses ObjectListView, you can see a nice dialog that shows you the current state
of the ObjectListView and it's underlying list.  At a breakpoint, move the mouse
over the variable that is the ObjectListView, and click the little magnifying glass. 
You'll see something like this:
</p>
        <p>
          <img style="border-right: 0px; border-top: 0px; margin: 5px 0px 5px 20px; border-left: 0px; border-bottom: 0px" height="370" src="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/ObjectListViewUpdate.9DebuggerVisualizer_1002C/Visualizer%5B4%5D.jpg" width="640" border="0" />
        </p>
        <p>
On the left side, you'll see information about the type of objects in the underlying
list ("List Item Type"), and below that, information about the list itself ("List
Type").  If the ObjectListView is sorted, the sort properties and sort direction of
each are listed.  Below that is the current filter expression, if any. 
If you're using a filter predicate (as I am in the example), it will tell you that.
</p>
        <p>
The right side shows two tabs.  The one on the top ("View") shows the list items
that are currently exposed by the ObjectListView, in the order defined by the current
sort, and excluding any items that are filtered out.  This is exactly what you
would see in a foreach loop, enumerating the items in the ObjectListView.  The
second tab ("List") shows all of the list items in the underlying list, in the order
in which they appear in the list.  Cool, huh?
</p>
        <p>
But wait, there's more!  If you're having problems getting ObjectListView to
work the way that you expect it to, check out the Analysis button in the lower left. 
If you click that, you'll see a synopsis of how the list and list item types work
with ObjectListView.  It will tell you about any potential problems, and recommend
a solution.  Here's what it looks like:
</p>
        <p>
          <img style="border-right: 0px; border-top: 0px; margin: 5px 0px 5px 20px; border-left: 0px; border-bottom: 0px" height="366" src="http://www.teamjohnston.net/cs/blogs/jesse/content/binary/WindowsLiveWriter/ObjectListViewUpdate.9DebuggerVisualizer_1002C/Analysis%5B4%5D.jpg" width="640" border="0" />
        </p>
        <p>
I hope that the visualizer is helpful.  Debug visualizers are really not very
hard to write, and I encourage you to write your own for any complex types that you're
coding up.  Take a look at the source in ObjectListViewVisualizer.cs to see how
to do it.  The only significant constraint on your code is that the type you're
visualizing needs to be serializable.
</p>
        <p>
Enjoy - and please don't hesitate to speak up if you have questions or thoughts about
ObjectListView!
</p>
        <img width="0" height="0" src="http://www.teamjohnston.net/cs/blogs/jesse/aggbug.ashx?id=1f38e29a-0ce0-40d2-9f24-113ff7924a02" />
      </body>
      <title>ObjectListView Update (1.0.0.9): Debugger Visualizer</title>
      <guid isPermaLink="false">http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,1f38e29a-0ce0-40d2-9f24-113ff7924a02.aspx</guid>
      <link>http://www.teamjohnston.net/cs/blogs/jesse/PermaLink,guid,1f38e29a-0ce0-40d2-9f24-113ff7924a02.aspx</link>
      <pubDate>Mon, 12 Mar 2007 01:46:41 GMT</pubDate>
      <description>&lt;p&gt;
Note: You can download the complete implementation &lt;a href="http://www.teamjohnston.net/files/ObjectListView.zip"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
For those of you just tuning in, ObjectListView is my answer to the .NET need&amp;nbsp;for
a DataView-like construct for ordinary objects.&amp;nbsp; With ObjectListView, you can
have a sorted and filtered view of any IList or IList&amp;lt;T&amp;gt;.&amp;nbsp; You can bind
this view to&amp;nbsp;controls like the DataGridView.
&lt;/p&gt;
&lt;p&gt;
This new version adds a debugger visualizer and includes a few other small enhancements
and bug fixes.
&lt;/p&gt;
&lt;h3&gt;Bug Fixes
&lt;/h3&gt;
&lt;p&gt;
Ecki found a bug in the Master/Details demo where I was doing an invalid cast in the
New button click handler.&amp;nbsp; I also found that .NET 1.1 style property change events
weren't wired properly for items already in the list at the time an ObjectListView
was constructed.&amp;nbsp; Those two are fixed.
&lt;/p&gt;
&lt;p&gt;
Boris reported that changing a list item property while iterating over ObjectListView
with a foreach loop would cause an InvalidOperationException to be thrown.&amp;nbsp; Indeed!&amp;nbsp;
This is by design;&amp;nbsp;any change to a .NET collection must invalidate all enumerators
of the collection.&amp;nbsp;&amp;nbsp; ObjectListVi