<!--------------------------------------------------------------------------->
<!-- INTRODUCTION
The Code Project article submission template (HTML version)
Using this template will help us post your article sooner. To use, just
follow the 3 easy steps below:
1. Fill in the article description details
2. Add links to your images and downloads
3. Include the main article text
That's all there is to it! All formatting will be done by our submission
scripts and style sheets.
-->
<!--------------------------------------------------------------------------->
<!-- IGNORE THIS SECTION -->
<html>
<head>
<title>The Code Project</title>
<Style>
BODY, P, TD { font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 10pt }
H2,H3,H4,H5 { color: #ff9900; font-weight: bold; }
H2 { font-size: 13pt; }
H3 { font-size: 12pt; }
H4 { font-size: 10pt; color: black; }
PRE { BACKGROUND-COLOR: #FBEDBB; FONT-FAMILY: "Courier New", Courier, mono; WHITE-SPACE: pre; }
CODE { COLOR: #990000; FONT-FAMILY: "Courier New", Courier, mono; }
</style>
<link rel="stylesheet" type=text/css href="http://www.codeproject.com/styles/global.css">
</head>
<body bgcolor="#FFFFFF" color=#000000>
<!--------------------------------------------------------------------------->
<!------------------------------- STEP 1 --------------------------->
<!-- Fill in the details (CodeProject will reformat this section for you) -->
<pre>Title: Configuration Manager for the Enterprise
Author: Randar Puust
Email: Developer@Puust.com
Member ID: 1690860
Language: C# 2.0, XML, XSD
Platform: Windows, .NET 2.0
Technology: ASP.NET, COM+, Web Services, NUnit, NUnitASP, XSDObjectGen, Test Driven Development
Level: Intermediate
Description: SysConfiguration is a component that allows the storing of configuration data, for an
enterprise application. It is intended to be an improved version of the System.Configuration class
or the Enterprise Library (Microsoft Patterns and Practices).
Section C# Programming
SubSection Applications
</pre>
<!------------------------------- STEP 2 --------------------------->
<!-- Include download and sample image information. -->
<ul class=download>
<li><a href="SysConfiguration.zip">Download solution - 1006 Kb </a></li>
</ul>
<p><img src="Images\ClassDiagram.jpg" alt="SysConfiguration"/></p>
<!------------------------------- STEP 3 --------------------------->
<!-- Add the article text. Please use simple formatting (<h3>, <p> etc) -->
<h2>Introduction</h2>
<p>SysConfiguration is a component that allows the storing of
configuration data, for an enterprise application. It is intended to be an
improved version of the System.Configuration class or the Enterprise Library
(Microsoft Patterns and Practices).</p>
<h3>Enterprise Configuration</h3>
<p>I work for a group at <a href="http://www.t4g.com/">T4G Limited</a>, which creates complex custom applications
for large enterprises.
It�s not uncommon that a single application has
multiple user interfaces (consumer, call center, B2B, etc.). As a result, we
often have multiple architectures (web, web services, WinForm, COM+, etc.)
running in parallel. As a technology services company, there is a high degree
of requirement volatility, which means we have frequent deployments to multiple
environments (Development, Test, Staging, User Acceptance Testing, Production,
etc.). In line with our companies atmosphere, the goals of this component were:</p>
<ul style='margin-top:0cm' type=disc>
<li>Automatically detect if a configuration setting was
missing.
<ul style='margin-top:0cm' type=circle>
<li><strong>Problem: </strong>A big frustration with the App.Config is that
it�s loosely typed. This means that if there is setting that is used by
a component, you have to actually test that component before you can
determine whether it�s there or not. </li>
<li><strong>Solution:</strong> SysConfiguration uses a strongly typed class.
The very first time it�s loaded, it will validate the configuration data
against a schema to ensure that all mandatory settings are there, while
still allowing for optional settings. This is a huge benefit when moving
code through the environments (e.g. Development to Testing to Production)</li>
</ul>
</li>
<li>Works for multiple architectures
<ul style='margin-top:0cm' type=circle>
<li><strong>Problem:</strong> If you have an application that has multiple
architectures, each one stores their configuration in different place:
Web.config for web applications and web services, App.config for WinForm
and console applications, registry for COM+, etc. The Enterprise Library
does have the FileConfigurationSource class, which allows you to call a
centralized configuration file, which is an improvement over the default
.Net Framework.</li>
<li><strong>Solution:</strong> SysConfiguration can use the same file for all
architectures. The only difference is the location of two entries that
point to the location of the configuration file and the schema that
validates it. This provides a degree of flexibility, because systems can
share the same configuration, or point to different locations if you want
to keep them distinct.</li>
</ul>
</li>
<li>Strongly Typed Hierarchical Data
<ul style='margin-top:0cm' type=circle>
<li><strong>Problem:</strong> Although you can create hierarchies with
System.Configuration, when you actually access the property, you still
have to use <em>AppSettings[�LooselyCoupledKey�]</em>.
This does not allow typos
to be detected at compile time, only at runtime.</li>
<li><strong>Solution:</strong> SysConfiguration generates a hierarchical
object model that represents the configuration class. This means you get
code that is easy to understand, caught at compile time and can use
IntelliSense (e.g. <em>SysConfiguration.Data.AppConfig.ConnectionStrings.Core</em>).
</li>
</ul>
</li>
<li>Standardized configuration entries
</li>
<ul style='margin-top:0cm' type=circle>
<li><strong>Problem:</strong> At T4G, we tend to share components whenever we
can. If you want to pass a component to another person, it would be
desirable to reliably pass the configuration entries specific to that
component. If you use something like App.Config, all you can do is hope
that somebody has commented it well enough to indicate which settings
belong to which components.</li>
<li><strong>Solution:</strong> SysConfiguration is designed in a way that the
hierarchical structure of the configuration can be broken up into many
files. For example, they could be broken up into: AppConfig, which
stores settings that are specific to the current application, T4GToolbox,
which stores all of the settings for our re-usable framework and
RightsConfig which stores the settings for a re-usable security component,
etc.
SysConfiguration is designed to merge all of these definitions into
a single configuration file, so there is only one file to maintain per
environment.</li>
</ul>
</ul>
<p>
<img id="IMG1" src="Images\Deployment.GIF" alt="SysConfiguration Deployment Diagram" /> </p>
<h3>Flexible Singleton</h3>
<p>An ideal design pattern for storing configuration data is
the <a href="http://www.dofactory.com/Patterns/PatternSingleton.aspx">Singleton</a>.
You want the configuration data to be loaded from disk once and then kept
somewhere fast so that it can be accessed quickly. The problem with the
Singleton, is that almost all the examples just keep it in memory. If this was
used in a web context, it would re-load the data for each request. If it was
used in COM+ component, it would release that memory as soon as it was idle for
a period of time.</p>
<p>SysConfiguration detects the context it is running as, and
then stores it in an appropriate storage:</p>
<ul>
<li>For web applications and web services, it uses the Web
Cache.</li>
<li>For WinForm and Console applications, it uses memory.</li>
<li>For COM+, it uses the Shared Property Manager.</li>
</ul>
<p>
<img src="Images\Data Persistence.GIF" alt="Data Persistence" /> </p>
<h3>Test Driven Development</h3>
<p>I also wanted to mention that this project was entirely
built using Test Driven Development (TDD), although I probably didn�t follow
the principles of "You Ain't Gonna Need It" (<a href = "http://c2.com/xp/YouArentGonnaNeedIt.html">YAGNI</a>) as closely as I
could have, I feel it was the correct balance of optimization and future use.
Although I�ve used TDD for components before, I used this project as a test bed
for some of the claims made by proponents of TDD and see for myself whether
they are true. See <i>Conclusions about Test Driven Development</i>.</p>
<p>In terms of the process I followed, I consistently wrote the
test first, failed it (red), got the code to work according to the test
(green), refactored the unit test and started the cycle all over again.
</p>
<p>I�ve included all the unit tests, which may be of interest
because I feel I built out a fairly good process when testing a single
component across all the architectures.
The most important design decision is
that there are a set of tests, called by NUnit, but in many cases those tests
call other tests residing in different processes.
So there is a central
assembly that NUnit calls, but the actual unit testing logic is stored
somewhere else. This ensures I can call all of the unit tests at once any time
I need to.</p>
<p>
<img src="Images\Unit Testing.GIF" alt="Unit Testing Classes" /> </p>
<p></p>
<h2>Using the Code</h2>
<p>
The install includes optional steps depending on your goals. The first set of steps are
for those people who are interested in the configuration component. The second
set of steps are additional steps, if you want to learn more about Test Driven
Development.</p>
<p>I should mention, there are some manual steps for setting
this up, but once it has been integrated, it is very easy to maintain.</p>
<h3>Pre-Requisites for SysConfiguration</h3>
<ol>
<li>The project was built using the .Net Framework 2.0 and Visual
Studio 2005.
</li>
<li>You will need to install XSDObjectGen (<a href ="http://www.microsoft.com/downloads/details.aspx?familyid=89e6b1e5-f66c-4a4d-933b-46222bb01eb0&displaylang=en">http://www.microsoft.com/downloads/details.aspx?familyid=89e6b1e5-f66c-4a4d-933b-46222bb01eb0&displaylang=en</a>).
This is used to generate the configuration class generated by the schema.
It assumes the default install path is used, which will put the VS2005
version into C:\Program Files\XSDObjectGenerator\vs2005.</li>
</ol>
<h3>Additional Steps to Use Unit Tests (optional)</h3>
<p>If you are interested in looking at executing the Unit
Tests, there are a few more additional steps.</p>
<ol>
<li>Install the latest version of NUnit. At the time of this
article, it was up to version 2.4 (<a href="http://www.nunit.org/">http://www.nunit.org/</a>).</li>
<li>Download NUnitASP (<a
href="http://nunitasp.sourceforge.net/">http://nunitasp.sourceforge.net/</a>).
At the time of this article, it was version 1.5.1. Extract the zip file
to C:\Program Files\NUnitASP.</li>
<li>Install NUnit 2.2 from the bin directory of NUnitASP. You
will be able to run both NUnits in parallel.</li>
<li>I had to add <supportedRuntime version="v2.0.50727"
/> to the nunit.exe.config and nunit-console.exe.config. You may have
to do the same depending on the .Net runtimes installed on your machine. </li>
<li>You will need to be on an operating system that supports
Component Services or COM+.
There is a class with tests that are
installed using the regsvcs.exe command line tool.</li>
<li>There are some constants in UnitTestCommon\Constants.cs
that will have to be changed.
These are set to paths that it expects back,
which may differ from your file system.
You should be able to figure
these out the first time you run the unit tests and it fails.</li>
<li>Open the properties for the UnitTests project. Go to Debug. Choose the Start Action to be "Start External Program". Select the latest version of nunit.exe.</li>
<li>Open up the properties for the WebTestHarness project. Go to Web. Select "Don't open a page. Wait for a request from an external application."</li>
<li>Open the solution properties. Go to Startup Project, select "Multiple startup projects" and choose "UnitTests" and "WebTestHarness" to both start.</li>
</ol>
<h3>Adding SysConfiguration</h3>
<ol>
<li>The project is not designed as a standalone component.
There is a class that is automatically generated based on the schema file,
each time the project is built.
This file is then compiled, along with
the rest of the project. Therefore, it needs to be added to the solution
of your application.
<ol style='margin-top:0cm' start=1 type=a>
<li>If you don�t care about unit tests, copy the
Configuration project into your solution.</li>
<li>If you want the unit tests, copy the Configuration
project to your main solution.
Copy all of the other projects to
wherever you are keeping your unit tests.
In my case, I kept them in a
folder in my Solution so there is a clear separation.
See SysConfigurationWithUnitTests.sln
for an example.</li>
</ol>
</li>
</ol>
<p>
<img src="Images\Solution.JPG" style="border-right: thin solid; border-top: thin solid; border-left: thin solid; border-bottom: thin solid" alt="Screenshot of Solution" /> </p>
<ol style='margin-top:0cm' start=2 type=1>
<li>You will have to configure your application to find the configuration file and the
schemas that validate it.
<ol style='margin-top:0cm' start=1 type=a>
<li>If it is a COM+ component, SysConfiguration needs to use
the registry to find the paths. There is a sample .reg file SetupComPlus.reg
provided. It will put two keys (<em>ConfigurationPath</em> and <em>ConfigurationSchemaPath</em>)
into the <span style='font-size:10.0pt;font-family:"Courier New"'><em>HKEY_LOCAL_MACHINE\SOFTWARE\Name.Randar</em>
</span>key. </li>
<li>For any web based application, add the following to the
Web.config and point the paths to the correct location. For a .Net
application, make the same changes, but to the App.config. </li>
</ol> </li>
</ol>
<pre><?xml version="1.0" ?>
<configuration>
<!-- Add these items to your configuration file and point them at the location that has the configuration and schema-->
<appSettings>
<strong><!-- Development Configuration Path -->
<add key="ConfigurationPath" value="C:\Projects\SysConfiguration\Code\Configuration\Development\Configuration.xml" />
<!-- Production Configuration Path -->
<!-- <add key="ConfigurationPath" value="C:\Projects\SysConfiguration\Code\Configuration\Development\Configuration.xml" /> -->
<!-- Path to Schema used to validate configuration files-->
<add key="ConfigurationSchemaPath" value="C:\Projects\SysConfiguration\Code\Configuration\Schemas\Settings.xsd" />
</strong> </appSettings>
</configuration>
</pre>
<p></p>
<ol start=3 type=1>
<li>If there are dependent schemas, you will have to change
the absolute paths of the <span style='font-size:10.0pt;font-family:"Courier New";
color:maroon'>xs:include</span> in Settings.xsd. There does not seem to
be way to make the path relative, which is unfortunate. I would recommend
you try to keep the same file structure on disk across the various
environments (development, staging, etc.) or make sure to not overwrite
your Settings.xsd when you update the code. </li>
</ol>
<h3>SysConfiguration Tasks</h3>
<p>The following is a �help file� of common tasks you would
need to perform to use SysConfiguration.</p>
<p><b>To add a configuration element</b></p>
<p>The following describes the steps to add a new configuration
setting to the application, once the pre-requisite steps have been followed.
SysConfiguration is designed to allow developers to quickly add new
configuration settings and allow them to define the validation required.</p>
<ol>
<li>If you would like to add a configuration element, simply
change the definition in one of the schemas (e.g. AppConfig.xsd,
RightsConfig.xsd, etc.). Do not add configuration elements to
Settings.xsd. This is a central hub of the various configuration
definitions.It will generate a class that has all references to all the
other configuration files. Simliar in concept to a project file.</li>
<li>The following are some examples that are supported:
<ol>
<li>Data types. If you set the type of a <em>xs:element</em>, it will
create a valid .Net type.</li>
<li>minOccurs and maxOccurs. This allows you to create
collections if the maxOccurs is unbounded, and optional settings if
minOccurs is 0.</li>
</ol>
</li>
</ol>
<p><b>To add configuration data</b></p>
<p>Once the structure has been defined, the following are the
steps to add the configuration data.</p>
<ol>
<li>Open up Configuration.xml in your favourite XML editor.
If you are using Visual Studio, it should have the targetNamespace setup
so that that Intellisense will allow you to build the hierarchy and add
the data.</li>
</ol>
<p><b> </b> <b>To access a configuration element</b></p>
<p>Once the configuration definition has been defined, and the
data added, the following describes how the application would access that data.</p>
<ol>
<li>Add a reference to Name.Randar.Configuration.dll.</li>
<li>Add a using statement for the namespace (i.e.
<em>using Name.Randar.Configuration</em>)</li>
<li>Access the configuration hierarchy, starting with the
Singleton called SysConfiguration.
You can access the data either through the static Data or Instance.SettingsData.
Both are identical. Some
examples:
<ol>
<li>SysConfiguration.Data.AppConfig.ConnectionStrings.Core</li>
<li>SysConfiguration.Instance.SettingsData.AppConfig.ConnectionStrings.Core</li>
<li>SysConfiguration.Data.DebugSettings.LogToFile</li>
<li>SysConfiguration.Instance.SettingsData.AppConfig.NumberOfRetries</li>
<li>SysConfiguration.Data.AppConfig.CloseOutDate</li>
<li>SysConfiguration.Instance.SettingsData.AppConfig.MaxAllowed</li>
</ol>
</li>
</ol>
<p><b>To access a list of configuration elements</b></p>
<p>SysConfiguration supports single name\value pairs as well as
lists. The following describes how to access a list of data.</p>
<ol>
<li>It stores lists as a strongly typed sub-class of the
ArrayList class. So you can access it by index or iterating through the
list.
<ol style='margin-top:0cm' start=1 type=a>
<li>SysConfiguration.Data.RightsConfig.RightCollection[0].Name</li>
<li>SysConfiguration.Data.RightsConfig.RightCollection.Count</li>
</ol>
</li>
</ol>
<pre>// Search through the roles until you find the one we are looking
int findRole = -1;
for (int i = 0; i < settings.RightsConfig.RightCollection.Count; i++ )
{
if (settings.RightsConfig.RightCollection[i].Name == Constants.RoleToSearchFor)
findRole = i;
}
</pre>
<p><b>To add a configuration definition</b></p>
<p>If you would like to extend the configuration definition,
but leave the main definition alone, you can use xs:include to include other
schemas.
This allows you to break up the configuration definition based on
components or other requirements.</p>
<ol>
<li>Create your schema that defines your configuration. Make
sure it has a root element.</li>
<li>Modify <em>Settings.xsd</em>:
<ol style='margin-top:0cm' start=1 type=a>
<li>Add a <em>xs:include</em> and point it at the new file.</li>
<li>Create an element that references the base element of the
other schema file.</li>
</ol>
</li>
</ol>
<pre><?xml version="1.0" encoding="utf-8"?>
<xs:schema id="Settings" targetNamespace="http://Randar.Name/Settings.xsd" elementFormDefault="qualified"
xmlns="http://Randar.Name/Settings.xsd" xmlns:mstns="http://Randar.Name/Settings.xsd"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:include schemaLocation="C:\Projects\SysConfiguration\Code\Configuration\Schemas\AppConfig.xsd">
</xs:include>
<xs:include schemaLocation="C:\Projects\SysConfiguration\Code\Configuration\Schemas\RightsConfig.xsd">
</xs:include>
<xs:element name="Settings">
<xs:complexType>
<xs:sequence>
<xs:element ref="AppConfig">
</xs:element>
<xs:element ref="RightsConfig">
</xs:element>
<!-- Add new elements here that reference other schema files-->
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
</pre>
<p><b>To reload the configuration data</b></p>
<p>You should setup your application so there is a way to clear
the cache and force it to re-load the data next time it is used. Otherwise,
you will have to restart the process somehow to clear the data. The following
steps describe how this can be done:</p>
<ol>
<li>You will have to create something that can be called
manually. For example:
<ol style='margin-top:0cm' start=1 type=a>
<li>A web page in an admin area with a button called �Clear
Cache�.</li>
<li>A web service with a web method called �ClearCache�.</li>
<li>A button on the Help->About screen that has a button
�Reload Configuration�.</li>
</ol>
</li>
<li>In all of these cases, the method should call <em>SysConfiguration.ClearCache()</em>.
</li>
</ol>
<h2>
Out of Scope</h2>
<p>
The following scenarios have not been tested or are not fully supported</p>
<ul>
<li><strong>Backwards compatibility. </strong>I have purged my development machine
of all older development environments, including VB6. Therefore, I haven�t
tested it on anything older than the .Net 2.0 Framework.</li>
<li>
<ul type=circle>
<li>I was able to register to the component using Regasm.exe, view it in Ole Viewer,
but none of the classes had methods. I haven�t needed to do COM\.Net Integration
since 2002, so I�m sure there is something small I have forgotten, but didn�t feel
this was a priority.</li>
<li>If you need to port it to the 1.0 framework:
<ul>
<li>You will have to use an older solution file, or manually edit the solution using
a text editor.</li>
<li>Collapse the SysConfiguration into a single class instead of using a Partial class.</li>
<li>Use the legacy classes instead of 2.0 System.Configuration Namespace.</li>
</ul>
</li>
</ul>
</li>
<li><b>Inheritance. </b>Unfortunately, it is hard to make to make the Singleton
design pattern inheritable, without some sort of hack, such as the base class knowing
of the super class. It is unfortunate, because I can think of many scenarios
where SysConfiguration could be a good base class. My best compromise to this
was to break up the Singleton and configuration functionality using Partial classes.</li>
<li><b>C# only. </b>It was enough work building this once. I didn�t have
time to create it in VB.Net as well.</li>
<li><b>Centralized configuration data. </b>Some third party configuration managers have
a central location for configuration data, that all local and remote processes access.
I�ve never liked this architecture because you have so many cross process\network
calls. If you really wanted this, you could load it into Component Services
and make all the calls through there, but you will get a performance hit.</li>
<li><b>Configuration structural changes require recompilation. </b>As I mentioned
before, you cannot change the structure of the configuration, without recompiling.
This is because of the strongly typed nature of this project. I don�t feel
this is a deficiency because you would have to change your code to access the new
configuration element anyways, but wanted to bring it up. Obviously, you can
change the configuration data without recompilation, just not the structure.</li>
<li><b>Editing configuration.</b> There is no built in support for editing the
configuration data. There are probably reasons for doing this, but I�ve never
run across it. If the data is volatile, I will always store it in the database
so it can be shared across the server farm. At the end of the day, it�s just
XML, so you could edit it using the standard XML classes.</li>
<li><b>English only. </b>I didn�t make it multi-lingual and I probably should
have. Although the only information that is shown is error messages, so I
got a bit lazy.</li>
<li><b>Not CLS compliant.</b> Although my code is CLS compliant, the code generated
by XSDObjectGen is not. The generated code is a key item, that I felt it best
to mark the entire class as non CSL compliant.</li>
<li><b>Automatic file change detection. </b> A nice (or not nice) feature
of App.config and Web.config is that it will restart the process if the config file
changes, reloading the settings. I have not looked into replicating this feature
(or defect, depending on your point of view). I personally think I prefer
being able to force the reload manually, but would like to make this an optional
feature.</li>
</ul>
<h2>Points of Interest</h2>
<p>The following are some comments about the code and
development process that may be of interest to some people.</p>
<h3>Conclusions about Test Driven Development</h3>
<p>The following section describes my opinion of Test Driven
Development when compared to the traditional process of developing the code and
(maybe) creating automated unit tests. It not based on any empirical study and
should be treated as opinion, not fact.</p>
<p>I definitely feel that TDD helped me make a much more robust
component than using traditional development. It was very good for at testing
the various architectures quickly and repeatedly. A few times, I made some
major refactoring of the architecture and having a full regression test was
invaluable in helping me to get the component functional again.</p>
<p>In terms of whether I actually developed this faster using
TDD than traditional development methodologies, I am not sure I agree.
Creating and refactoring the unit tests does take time and can�t be discounted.
The argument is that creating the tests, takes less time than debugging the
problem. The only way to accurately test this would be to clone a person and
have them develop the identical component, under identical conditions but using
both techniques, which is just not possible. I do think you would see a much
greater return when you have a team larger than a single person, because the
scenario of another developer breaking somebody else�s code is much more
likely.</p>
<p>Some proponents of TDD will say that when tests fail
unexpectedly, reverting the code to the last version that passed all tests is
almost always more productive than debugging. I have to say, I did spend
considerably less time debugging than usual, but don�t feel I should have ever
rolled back. I think debugging was always the better option, especially
considering how good the debugger is in VS2005.</p>
<p>Even though this version was developed by a team of one, I
tried to act like I was working in a team. I tried to make sure to only check
in the test, when the underlying code passed (i.e. green). In theory, this
means that if we were using Continuous Integration, it would always pass. The
only issue was to fight the urge to check in the test once it was written. I�m
used to the mentality of keeping my changes small and check-ins frequent, but
you have to change your mentality slightly.</p>
<p>
One item of interest is the ratio of lines of code of the
unit tests vs. application code.
</p>
<ul style='margin-top:0cm' type=disc>
<li>4887 total lines of code</li>
<li>3401 lines of unit tests</li>
<li>1486 lines of application code</li>
</ul>
<p>So we end up with an approximate ratio of 2:1 of unit tests
to application code.
That is higher than typical, although many of the tests
are duplicates for different architectures which would explain the high ratio.</p>
<p>To answer the question, of whether I would suggest using TDD
on a project, the answer is yes, with caveats. Although you can�t tell from
this project, I would suggest using TDD for any component that is called by
other components. Writing effective unit tests for the web layer is still
difficult unless you build in some way to bypass authentication and session
data. I definitely feel it creates much more reliable code and makes changes
easier due to the extensive regression test it creates.</p>
<h3>Quality of code</h3>
<p>Since this is intended to be used and extended by a broad
range of people, I tried to:</p>
<ul style='margin-top:0cm' type=disc>
<li>Clearly comment the code as much as possible.</li>
<li>Conform to the C# Coding Standards for .NET by Lance Hunt
(<a
href="http://weblogs.asp.net/lhunt/pages/CSharp-Coding-Standards-document.aspx">http://weblogs.asp.net/lhunt/pages/CSharp-Coding-Standards-document.aspx</a>),
which is the standard used at T4G.</li>
<li>Use FxCop to clean up some exception handling and other
style issues.
Many of the exclusions were from the code
XSDObjectGen generated or simply didn�t apply to what I was trying to
accomplish (e.g. globalization).</li>
<li>I really wanted to use <a href="http://ncover.org/site/">NCover</a> to ensure I had 100% code
coverage with my unit tests.
This was actually harder than I expected. Many
of the tests are running in different processes (console, web, COM+,
etc.). NCover can�t figure out they are all running from the same set of
tests, so it showed poor coverage, even though the superset of all the
tests would probably be close to 100%.</li>
</ul>
<h3>XSDObjectGen.exe</h3>
<p>I wanted to make a few comments about the XSDObjectGen, aka
Sample Code Generator (<a href="http://www.microsoft.com/downloads/details.aspx?familyid=89e6b1e5-f66c-4a4d-933b-46222bb01eb0&displaylang=en">http://www.microsoft.com/downloads/details.aspx?familyid=89e6b1e5-f66c-4a4d-933b-46222bb01eb0&displaylang=en</a>).
</p>
<ul style='margin-top:0cm' type=disc>
<li>At one point, instead of using XSDObjectGen.exe, I did try
to use XSD.exe to generate my class files, but it suffers from one major
deficiency. No support for the <xs:import> tag. This forces you to
keep all of your definitions in one file, which is difficult to manage.</li>
<li>I find XSDObjectGen so much better than Strongly Typed
Datasets, because they are lighter and you can create deeper hierarchies
than row and column. The only issue is that you have to load the data
yourself.</li>
<li>If you ever need to create Data Transfer Objects (<a
href="http://en.wikipedia.org/wiki/Data_Transfer_Object">http://en.wikipedia.org/wiki/Data_Transfer_Object</a>),
you should seriously look at XSDObjectGen. It creates great lightweight
objects that serialize well.</li>
</ul>
<h2>Troubleshooting</h2>
<p><b>Problem: System is raising a </b><b><span style='font-size:8.5pt;
font-family:"MS Shell Dlg"'>System.IO.FileNotFoundException</span>.</b></p>
<p>It cannot find the configuration file or the schema used to
validate it. See step 2 of "Adding SysConfiguration".</p>
<p><b>Problem: The compiler is raising: Could not find a part of the
path 'C:\Projects\SysConfiguration\Code\Configuration\Schemas\RightsConfig.xsd'.
C:\Projects\SysConfiguration\Code\Configuration\Schemas\Settings.xsd</b></p>
<p>
<b></b><em>xs:import</em> seems to need the absolute path. Edit
<em>Settings.xsd</em> to point to the correct location.</p>
<p><b>Problem: The compiler is raising: Unable to copy file
"obj\Debug (With Sample Configuration)\Name.Randar.txUnitTests.dll"
to "bin\DebugWSC\Name.Randar.txUnitTests.dll". The process cannot
access the file 'bin\DebugWSC\Name.Randar.txUnitTests.dll' because it is being
used by another process.</b></p>
<p>The COM+ component is still running. Open up Component
Services, expand COM+ Application, right click on SysConfiguration Unit Tests
and choose �Shut Down�.</p>
<h2>Conclusion</h2>
I wrote the first version of this component in 2002. Since
then, it�s been rebuilt and refactored many times. At the same time, the
overall core design has changed very little and it�s weathered the test of
time. This latest version and the accompanying article took quite a bit of
time to write. You are free to incorporate it into your code and all I ask is
that you don�t take credit for my work and to please email me with feedback
(both good and bad) if you do use it.
<!------------------------------- That's it! --------------------------->
</body>
</html>