To test this, we decided to setup an interface and two derived classes. Then we added corresponding data to the database (we will build an intuitive graphical user interface eventually). Finally, we used the Container Singleton class to resolve our types and print out the results.
Class Diagram:

Database:
Windsor Component View
|
Lookup Name |
Namespace |
Contract |
Implementation |
Component Id |
Contract Id |
|
|
|
|
|
|
|
Test1 |
DBinsor.Svc.WCF.Client |
IMath |
Add |
1844d2e0-455e-4d44-a9ff-1c63f78e407b |
0aa71152-91d4-4e8f-a4a0-4124a98e2851 |
|
Test1 |
DBinsor.Svc.WCF.Client |
IMath |
Subtract |
5c3ee79a-926c-4438-8391-44a437bd8f47 |
0aa71152-91d4-4e8f-a4a0-4124a98e2851 |
Windsor Parameters View
|
Component Id |
Contract Id |
Parm Name |
Default |
Override |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5c3ee79a-926c-4438-8391-44a437bd8f47 |
0aa71152-91d4-4e8f-a4a0-4124a98e2851 |
a |
1 |
13 |
|
5c3ee79a-926c-4438-8391-44a437bd8f47 |
0aa71152-91d4-4e8f-a4a0-4124a98e2851 |
b |
2 |
NULL |
|
1844d2e0-455e-4d44-a9ff-1c63f78e407b |
0aa71152-91d4-4e8f-a4a0-4124a98e2851 |
a |
1 |
NULL |
|
1844d2e0-455e-4d44-a9ff-1c63f78e407b |
0aa71152-91d4-4e8f-a4a0-4124a98e2851 |
b |
2 |
NULL |
Classes:
Test:
IMath proxy = ContainerSingleton.Instance.Resolve<Add, IMath>();
Console.WriteLine(proxy.Calculate().ToString());
proxy = ContainerSingleton.Instance.Resolve<Subtract, IMath>();
Console.WriteLine(proxy.Calculate().ToString());
Console.WriteLine(ContainerSingleton.Instance.Xml);
Result:
3
11
<configuration>
<components>
<component id="DBinsor.Svc.WCF.Client.Add"
service="DBinsor.Svc.WCF.Client.IMath, DBinsor.Svc.WCF.Client" type="DBinsor.Svc.WCF.Client.Add, DBinsor.Svc.WCF.Client">
<parameters>
<a>1</a>
<b>2</b>
</parameters>
</component>
<component id="DBinsor.Svc.WCF.Client.Subtract"
service="DBinsor.Svc.WCF.Client.IMath, DBinsor.Svc.WCF.Client" type="DBinsor.Svc.WCF.Client.Subtract, DBinsor.Svc.WCF.Client">
<parameters>
<a>13</a>
<b>2</b>
</parameters>
</component>
</components>
</configuration>
One thing we have found useful over the years is to wrap a service proxy in a public interface Dynamic Link Library. Though this in one sense may contradict the idea of Service Oriented Architecture (SOA); in another sense it holds up the idea of refactoring.
In this project, we have created a singleton that loads the configuration file from the database. Furthermore, this singleton aggregates Windsor Container for easy of accessibility throughout ones program. One draw back is (depending on usage) the load time of ones program may suffer due to Service / Database Access.
Previously, we stated that DBinsor required each class to implement an interface. Thus, we ensured this by added our custom resolve method in the singleton. public T Resolve<T, S>()
where T : class, S
{
return this._container.Resolve<S>(typeof(T).ToString()) as T;
}
In future releases of this library, we will add more methods to the singleton to provide access to other functionality of the Windsor Container.
Again, we used the factory methodology to allow for multiple sources for the Windsor Container. That is, we plan to allow a user to pick from our database service, an application configuration file, a web configuration file or a standalone xml file as their source for the singleton.
The public interface uses the “app.config” or the “web.config” files for three things: lookup name, resource source and service binding. Here is a sample:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="LookupName" value="Test1" />
<add key="ResourceSource" value="Database" />
</appSettings>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ConfigSvcEndPoint" closeTimeout="00:01:00" openTimeout="00:01:00"
receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:3837/DBinsor.Svc.WCF.Host/Configuration.svc"
binding="basicHttpBinding" bindingConfiguration="ConfigSvcEndPoint"
contract="ConfigurationServiceProxy.ConfigurationServiceContract"
name="ConfigSvcEndPoint" />
</client>
</system.serviceModel>
</configuration>
In the last post, we purposely did not address the core question of how does one generate the xml configuration from the database. This used to require quite a bit of code; however, we have LINQ (praise the Microsoft Gods). I am by no means a LINQ expert, nevertheless I know enough to make it work.
The code is pretty straight forward; we used LINQ to SQL to select all rows from the database where the lookup name equals our requested name. Then we used LINQ to XML to put those rows into an XML file. This was almost too trivial of a task. using System;
using System.Linq;
using System.Xml.Linq;
using DBinsor.Svc.WCF.BusinessEntities;
using DBinsor.Svc.WCF.DataAccess;
namespace DBinsor.Svc.WCF.BusinessLogic
{
public class ResourceFromDatabase : IResource
{
public ConfigurationEntity GenerateXml(ConfigurationEntity entity)
{
if (entity == null)
{
throw new ArgumentException("Configuration Entity Was Null.", "entity");
}
if (string.IsNullOrEmpty(entity.LookupName) == true)
{
throw new ArgumentException("Lookup Name Was Null or Empty.", "entity");
}
using (DBinsorViewDataContext windsorDataAccess =
new DBinsorViewDataContext())
{
entity.Xml = new XElement("configuration",
new XElement("components",
from components in windsorDataAccess.WindsorComponents
where components.LookupName == entity.LookupName
orderby components.ImplementationName
select new XElement("component",
AddRequiredAttributes("id", components.Namespace + "." + components.ImplementationName),
AddRequiredAttributes("service", components.Namespace + "." + components.ContractName + ", " + components.Namespace),
AddRequiredAttributes("type", components.Namespace + "." + components.ImplementationName + ", " + components.Namespace),
AddOptionalAttributes("inspectionBehavior", components.InspectionBehavior),
AddOptionalAttributes("lifestyle", components.Lifestyle),
AddOptionalAttributes("customLifestyleType", components.CustomLifestyleType),
AddOptionalAttributes("initialPoolSize", components.InitialPoolSize.ToString()),
AddOptionalAttributes("maxPoolSize", components.MaxPoolSize.ToString()),
AddParameters(components.ComponentId, components.ContractId)
)
)
);
}
return entity;
}
private static XAttribute AddRequiredAttributes(string name, string value)
{
return new XAttribute(name, value);
}
private static object AddOptionalAttributes(string name, string value)
{
if (string.IsNullOrEmpty(value) == true)
{
return null;
}
return new XAttribute(name, value);
}
private static XElement AddParameters(Guid componentId, Guid contractId)
{
using (DBinsorViewDataContext windsorDataAccess =
new DBinsorViewDataContext())
{
return new XElement("parameters",
from parameters in windsorDataAccess.WindsorParmaters
where (parameters.ComponentId == componentId && parameters.ContractId == contractId)
orderby parameters.ParmName
select new XElement(parameters.ParmName,
ReturnDefaultOrOverride(parameters.ParmDefault, parameters.OverrideValue))
);
}
}
private static string ReturnDefaultOrOverride(string defaultValue, string overrideValue)
{
if (string.IsNullOrEmpty(overrideValue) == false)
{
return overrideValue;
}
return defaultValue;
}
}
}
The only concern I have is in the “AddParameters” function; does it make a round trip to the database on every select? I think it probably does; thus this may be a huge performance bottleneck. However, first we should build for proof of concept. Then we can go back and optimize.
Quite shockingly, we have etched out an n-tier service oriented system without writing a single line of code. Moreover, we are following best practices to decouple the data layer, business layer, service layer and presentation layer. Generally, we do this for two reasons: one, to promote the idea of separation of concerns and two, to allow for future flexibility when addressing change sets.
The wiring process can be summed up as adding business entities and logic to link the data layer to the service layer. Business entities should be though of as objects that hold state. Business logic should be thought of functions or processes that affect business entities. This is gray definition, because in some cases business entities might have functionality. An example of a business object is a person; who has a name and an age. However, this person may have an internal process called heartbeat: thus the grayness.
We will define one business entity (for now) called “ConfigurationEntity”. This entity will have two properties: “LookupName” and “Xml”. The “LookupName” will be used to find the castle configuration in the database. The “Xml” will hold the dynamically generated xml configuration from the database.
Before we proceed, generally I would unit test at this point. Test Driven Development (TDD) states: we should write tests first then code. However, because it would require the use of mocks, I will refrain until a later post.
Next, we will use a factory pattern to generate the xml from the database. Again, we are choosing a design that provides for flexibility during future change sets. The factory uses an enumeration to decide which type of process to return.
Finally, we have to generate translators to and from our service layer data contracts to our business layer business entities. These translators will be used in our service implementation to allow access to our business logic.
Class Diagram:

Factory: namespace DBinsor.Svc.WCF.BusinessLogic
{
public static class ResourceFactory
{
public static IResource GenerateResouce(ResourceLocations location)
{
switch (location)
{
case ResourceLocations.Database:
return new ResourceFromDatabase();
default:
throw new ArgumentException("Location Not Supported.", "location");
}
}
}
}Finally, we have to generate translators to and from our service layer data contracts to our business layer business entities. These translators will be used in our service implementation to allow access to our business logic. namespace DBinsor.Svc.WCF.ServiceImplementation
{
public static class TConfigurationEntityAndConfigurationResponse
{
public static ConfigurationResponse Convert(ConfigurationEntity from)
{
ConfigurationResponse to = new ConfigurationResponse();
to.ConfigurationPart = new ConfigurationPart();
to.ConfigurationPart.XmlConfiguration = new XmlConfiguration();
to.ConfigurationPart.XmlConfiguration.Config = from.Xml.ToString();
return to;
}
}
}namespace DBinsor.Svc.WCF.ServiceImplementation
{
public static class TConfigurationEntityAndConfigurationRequest
{
public static ConfigurationEntity Convert(ConfigurationRequest from)
{
return new ConfigurationEntity(from.CastleId.LookupName);
}
}
}namespace DBinsor.Svc.WCF.ServiceImplementation
{
public partial class ConfigurationService
{
public override ConfigurationResponse GetConfigurationDemand(ConfigurationRequest request)
{
IResource businessLogic = ResourceFactory.GenerateResouce(ResourceLocations.Database);
return TConfigurationEntityAndConfigurationResponse.Convert(
businessLogic.GenerateXml(
TConfigurationEntityAndConfigurationRequest.Convert(
request)));
}
}
}
At first glance these two new data access technologies seem to fulfill a common purpose. Though, from my basic understanding the ADO.NET Entity Framework [EF] acts more like an Object Relational Mapping [ORM] tool, where as the LINQ to SQL [LTOS] acts similar to an ADO.NET Dataset. This is my first observation and will most likely be discredited through further inspection.
Functionally, we are trying to use a technology to extract, insert, modify and delete from our database. Thus, it seems either technology would be well suited. For a production system, we would lean towards LTOS because EF is still in a beta 3 version. However, because we view this project as a learning exercise, we will employee both technologies.
Due to the fact the EF is much more like an ORM; we will use it for our data access to the tables of the database. Consequently, we will use LTOS for the data access associated with the views of the database. Basically, the idea is if we change the underlying table structure, our business object to relational mapping should not have to change.
In the above example, this should hold true (pending that EF does have a flexible Object to Relational Mapping portion). We will leave this argument unjustified for the moment, because most likely we will have to change the database later on.
ADO.NET Entity Framework Table Map:

LINQ to SQL View Map:

Component: SELECT dbo.Castle.Name AS LookupName, dbo.Contracts.Namespace, dbo.Implementations.Id, dbo.Contracts.Interface AS ContractName,
dbo.Implementations.Name AS ImplementationName, dbo.Components.InspectionBehavior, dbo.Components.Lifestyle,
dbo.Components.CustomLifestyleType, dbo.Components.InitialPoolSize, dbo.Components.MaxPoolSize, dbo.Components.Id AS ComponentId,
dbo.Contracts.Id AS ContractId
FROM dbo.Castle INNER JOIN
dbo.Components ON dbo.Castle.Id = dbo.Components.CastleId INNER JOIN
dbo.Implementations ON dbo.Components.ImplementationId = dbo.Implementations.Id INNER JOIN
dbo.Contracts ON dbo.Implementations.ContractId = dbo.Contracts.Id
Parameter: SELECT dbo.Components.Id AS ComponentId, dbo.Contracts.Id AS ContractId, dbo.ContractParameters.Name AS ParmName,
dbo.ContractParameters.DefaultValue AS ParmDefault, dbo.ComponentParameters.OverrideValue
FROM dbo.Components INNER JOIN
| |