May 2004 - Posts

High-performance XML (III): returning well-formed XML from WebServices without XmlDocument

Note: this entry has moved.

Recently, Matt Powell wrote about returning XML from webservices, and I certainly agree with him that returning it as an opaque string is really bad. Later on, Matevz Gacnik suggested a couple points to consider when to choose one or the other. Matt continued his rant  this time tackling at the heart of the problem: why do you need to load a full-blown DOM just to get the nice XML returned from the webservice? At this point, I felt I should kick in.

You see, one of the greatest things about having a fully OO platform is that you can easily complement what's missing by simply inheriting a couple classes, plugging your stuff in the infrastructure. So, let me state it clear and loud: you don't have to load an XmlDocument to return well-formed XML from webservices. Let's see how this is accomplished.

As you may already know, the ASP.NET WebMethod framework uses the XmlSerializer to convert arguments and return values to their XML representations. When your webmethod returns an XmlDocument, it will serialize the XmlDocument.DocumentElement, effectively the root element. If you return an XmlNode, it will simply serialize it. So, you could either return an XmlDocument *if you already have it at hand*, or an XmlNode (this could even be the DocumentElement of the previous one). The client will see the same WSDL and the Visual Studio Add Web Reference feature will generate a proxy returning an XmlNode in either case. So, *both* methods below result in the same proxy class:

[WebMethod] 
public XmlDocument MyDocumentMethod()
{
//...
}



[WebMethod] public XmlNode MyNodeMethod()
{
//...
}


// Proxy code
MyService proxy = new MyService();
XmlNode xml = proxy.MyDocumentMethod();
// or xml = proxy.MyNodeMethod();

When the XmlSerializer used to build the SOAP Body for our return value realizes it's an XmlDocument/XmlNode, it will simply call its WriteTo(XmlWriter w) method. So, what can we do with all this knowledge? Well, we can leverage it to avoid loading full DOMs when we have other (better IMO) representations such as an XmlReader or an XPathNavigator. The process is simply to create a special-purpose XmlNode-derived class that will serve as our trojan horse (very appropriate now that Troy is in vogue ;)) into the webservice serialization infrastructure.

Implementation

Implementing the XmlNode.WriteTo() method with an XmlReader is all too easy:

private class XmlReaderNode : SerializableNode 
{
private XmlReader _reader;
private bool _default;

public XmlReaderNode() {}
public XmlReaderNode(XmlReader reader, bool defaultAttrs)
{
_reader = reader;
_reader.MoveToContent();
_default = defaultAttrs;
}

public override void WriteTo(XmlWriter w)
{
w.WriteNode(_reader, _default);
_reader.Close();
}
}

Note that we need to move the reader to the actual content, because we don't have to serialize the document declaration again, because the result is placed inside the SOAP body. We'll get to the base SerializableNode class in a minute. Basically it overrides everything and throws NotSupportedExceptions.

Implementing the XmlNode.WriteTo() method with an XPathNavigator is also easy, as we can take advantage of the Mvp.Xml project XPathNavigatorReader:

private class XPathNavigatorNode : SerializableNode 
{
private XPathNavigator _navigator;

public XPathNavigatorNode() {}
public XPathNavigatorNode(XPathNavigator navigator)
{
_navigator = navigator;
}

public override void WriteTo(XmlWriter w)
{
w.WriteNode(new XPathNavigatorReader(_navigator), false);
}
}

Note that in both cases, we use the built-in infrastructure by calling the XmlWriter.WriteNode() method. Specially in the case of the XmlReaderNode, that means we're never building an in-memory DOM. In the case of the XPathNavigatorNode it means that we're working with the existing in-memory infoset, and we're not loading another one for the serialization.

The only "trick" in the base SerializableNode is in its constructor, because the base XmlNode and XmlElement don't allow empty constructors. The workaround was to create an element with a dummy name and an empty owner document:

private abstract class SerializableNode : XmlElement 
{
public SerializableNode() : base("", "dummy", "", new XmlDocument()) {}

public override XmlNode AppendChild(XmlNode newChild)
{
throw new NotSupportedException(SR.XmlDocumentFactory_NotImplementedDOM);
}
//...all other members...
}

At this point you may be wondering why all these classes are private. Well, in order to isolate the user from the internal implementation details of these classes, I prefer to create a factory class that simply returns XmlNode values:

public class XmlNodeFactory 
{
private XmlNodeFactory() {}
 public static XmlNode Create(XPathNavigator navigator) 
{
return new XPathNavigatorNode(navigator);
}
public static XmlNode Create(XmlReader reader)
{
return Create(reader, false);
}
public static XmlNode Create(XmlReader reader, bool defaultAttrs)
{
return new XmlReaderNode(reader, defaultAttrs);
}
//...private inner classes follow...
}

Usage

Now, let's get back to your webservice code. Most probably, specially if you have been reading my weblog and many others that advice against the XmlDocument, you'll already have an XmlReader or XPathNavigator you got from your business classes or your data access layer. With that at hand, you can simply use the following code:

[WebMethod] 
public XmlNode GetFromNavigator()
{
XPathNavigator nav;
// Get your navigator...
return XmlNodeFactory.Create(nav);
}
[WebMethod] 
public XmlNode GetFromReader()
{
XmlReader reader;
// Get your reader, maybe even from SQL Server?...
return XmlNodeFactory.Create(reader);
}

Note that I mention getting the reader from SQL Server. If you look at the XmlReaderNode code shown in the previous section, you'll notice that once the WriteTo() serialization method is invoked, the reader is closed.

The interesting thing in the XPathNavigator case is that you can position the navigator on the node you want to return, and have only that "fragment" serialized. For example:

[WebMethod] 
public XmlNode GetFromNavigator()
{
string xml = "<customer><order>25</order><info>Daniel Cazzulino</info></customer>";
XPathDocument doc = new XPathDocument(new StringReader(xml));
XPathNavigator nav = doc.CreateNavigator();
//Move to the customer node
nav.MoveToFirstChild();
//Move to the order node
nav.MoveToFirstChild();
return XmlNodeFactory.Create(nav);
}

The returned data will be only the <order>25</order> element (and any children it may have). Cool, huh? That's XPathNavigatorReader courtesy ;)

The full project source code belongs to the Mvp.Xml project and can be downloaded from SourceForge. Enjoy!

Check out the Roadmap to high performance XML.

Is ObjectSpaces officially dead?

Note: this entry has moved.

Looks like so...

Update: dead for Whidbey, live for Longhorn :(

New version of Whidbey is out!

Note: this entry has moved.

In case you haven't heard, the Visual Studio 2005 Community Technology Preview May 2004 is available to all MSDN subscribers! :D

It's funny how I found it, as it was released less than 2 days ago and not even the new MSDN Subscriber Downloads was updated, although I've just checked the Visual Studio 2005 Developer Center and it now contains the news. I was just about to report a bug through the new MSDN Feedback Center, when I had to choose the version, and guess what, a new one was there! :o)

I wish the feed was updated more often. In fact, that should be the first one, as it's probably the one requiring less work, IMO.
Posted 26 May 2004 04:49 AM by Daniel Cazzulino
Filed under:
EIF vs log4net

Note: this entry has moved.

I've been doing a comparison of both products recently. Before you read, I must say that I used log4net a lot (I even appear as a contributor :o), so I may be biased. On the other hand, I only evaluated EIF, looked at how it's used in a real world product, and read the documentation provided, as well as built the examples.

Here are my conclusions.

 

Conventions:

·          x: feature is supported equally.

·          -: feature is supported/implemented, but is not as good as the other product

·          +: feature is better supported/implemented than the other product 

 

Feature

EIF

log4net

General

Decoupling of event source and event sink

x

x

Arbitrary target event sinks

x

x

Number of built-in event sinks supported

3

20

Extensible

x

x

Configuration

-

(quite complex)

+

(very simple)

WMI supported built-in

x

 

Arbitrary log data

+

-

(built-in just text)

Multiple logging "domains" (ability to configure the framework by modules, i.e. each logical feature has its own config, repository and sinks)

 

+++

(a BIG plus for highly composed and pluggable apps)

Installation

-

(mostly requires admin permissions)

+

(xcopy)

Support

?

x

(excelent peer support)

Source provided

 

+

Supported Platforms

.NET

.NET, CF, Mono, SSCLI

 

 

 

Runtime

 

 

Performance with logging enabled

x

x

Performance with logging disabled for a certain event

-

++

(orders of magnitude faster)

Reconfiguration

-

(only possible with WMI or Windows Trace)

+

(full configuration monitoring & reloading)

 

 

 

API - Dev friendliness

 

 

Event (source) categorization

-

(uses the event Type. leads to increasingly big hierarchies of event types)

++

(combination of log level + logger name -dotted notation-)

Event source inheritance

 

++

(filters and sinks applied to all descendant sources)

Customization

x

+

(everything)

 

 

 

 

One of the "distinguishing" features of EIF is request tracing, but it is mostly irrelevant as it only works using the remoting CallContext, which reduces its applicability considerably. And remoting is not a long-term platform to rely on either... For request-like tracing on a single thread (important when there're multiple components involved in an operation happening on a single machine/thread) log4net offers similar functionality through its Nested Diagnostics Context.

For business events that rely on arbitrary objects being send, EIF has a clear advantage. I wonder, however, how many business notification scenarios are actually handled through logging... Through customization similar functionality could be implemented in log4net, however.

 

Overall: both seem like good logging packages. EIF may be more manageable as it has strong relationship with WMI. log4net, on the other hand, clearly wins on simplicity and in my opinion satisfies most common logging and tracing needs.

Except for the extra WMI stuff (which can also be implemented as custom extensions to log4net - I've done it) and arbitrary objects publication (also achievable, but requiring more work), I'd choose log4net.

 

Side Note

log4net "event source" (loggers): in log4net, you ask for a logger to the LogManager. Using a simple dotted syntax, you create hierarchycal loggers that inherit sinks, filters and threshold very easily. For example, the following code asks for a logger and logs an informational message:

 

ILog log = LogManager.GetLogger("Finance.Accounting.Customers.Administration");
if (Log.IsInfoEnabled)
{
  log.Info("Adding user " + _userId);
}

 

some other component in the same module may use the following:

 

ILog log = LogManager.GetLogger("Finance.Accounting.Orders");
if (Log.IsInfoEnabled)
{
  log.Info("Adding order " + _orderId);
}

 

All the "Finance" application, or the "Accounting" module can be configured in a single place, and affect both components. A common use is to pass the current component type to the GetLogger() method, therefore making the logger match class full names, which is also an easy way to configure groups of components or modules in an application. For example:

 

<!-- Enables all logging events in finance application (both components above) -->
<logger name="Finance ">
  <level value="ALL" />
</logger>
 
<!-- Enables INFO logging events in accounting module (both components above) -->
<logger name="Finance.Accounting">
  <level value="INFO" />
</logger>
 
<!-- Enables INFO logging events in Orders module (only for the last code above) -->
<logger name="Finance.Accounting.Orders">
  <level value="INFO" />
</logger>

 

Custom logger levels can be used directly, without previous definition, for example "BusinessEvent" or "CriticalOperation". This functionality, combined with hierarchycal loggers is very flexible and completely removes the need in EIF for defining custom types for every event. In addition, arbitrary key-value (only strings) can be logged by using a so-called Mapped Diagnostics Context. Functionality similar to request tracing in EIF is available through Nested Diagnostic Context, that is threads-specific.

 

 

I'd love to hear arguments in favor of EIF. I may be missing some other features it has to offer, or I may have misunderstood some of its functionality, as (like I said) I haven’t used it before.

Have you used both products? What do you think about the points made above?

High-performance XML: a practical guide

Note: this entry has moved.

Oleg mentions a must read document from the Patterns and Practices guys: Improving .NET Application Performance and Scalability. I'm glad I could contribute a couple ideas to the Improving XML Performance chapter.

When you read Compile Both Dynamic and Static XPath Expressions section, you'll know it's all about  dynamic XPath expressions compilation and its follower enhance XPath execution performance with XPathCache, both applied and available through the Mvp.Xml project, downloadable from from SourceForge.

Check out the Roadmap to high performance XML.

Mvp.Xml project: packed XML cool utilities

Note: this entry has moved.

I've released the seventh eighth "version" of the   Mvp.Xml project  on   SourceForge. This is a maintenance release with some bugs fixed in the XPathNavigatorReader. Thanks to Tom Smalley and Joost Ploegmakers!

 

So far, the package contains:

   

Each feature is explained in a corresponding weblog post.

Update: the Mvp.Xml project now also powers the Atom.NET project, as explained in the announcement post.

 

Enjoy!

XSD -> Classes Generator Custom Tool (radically new and extensible)

Note: this entry has moved.

This article is a companion to Code Generation in the .NET Framework Using XML Schema article published in the MSDN XML DevCenter. In that article, I introduce you to the main classes in the .NET framework that enable code generation from XSD files, the very clases the XSD.EXE tool uses. The ideas come from my initial post on Customizing XSD->Classes code generation, the "easy" way.
In this article I'll show how the VS.NET custom tool included in the MSDN article code download is created.

Building the XsdCodeGen Custom Tool

Creating a custom tool for VS.NET is extremely easy. Microsoft has released a project with all the necessary classes for that purpose, which can be downloaded from GotDotNet (http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=4AA14341-24D5-45AB-AB18-B72351D0371C). Everything we need to do is create a new class library project using that one as a skeleton, and add a new class inheriting from the BaseCodeGeneratorWithSite provided:

[Guid( "9B7CF25A-1782-433b-B534-0B94E76A7D62" )] [ComVisible( true )] public class XsdCodeGenerator : BaseCodeGeneratorWithSite

The generator is registered as a COM component, and that’s why we need to specify the GuidAttribute and the ComVisibleAttribute. The former should receive a new GUID which can be created from the Tools -> Create GUID menu. We call it a generator because that’s the registry key they are registered under. That key has two sub keys, one for the VB.NET and another for the C# generators. We should register our tool with both, as we’re using the language-agnostic CodeDom. Therefore, we define two constants that hold the GUIDs of such categories:

private static Guid CSharpCategory = new Guid( "{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}" ); private static Guid VBCategory = new Guid( "{164B10B9-B200-11D0-8C61-00A0C91E29D5}" );

We’ll also store the GUID assigned to the class itself for easy access, as we’ll need it for registration. We also define the custom tool name and description with constants. The former is important as it’s the one that is assigned to a file through the Property Browser in order to execute the tool:

private const string CustomToolName = "XsdCodeGen"; private const string CustomToolDescription = "MSDN Classes Generator";

The registry key we need to create looks like the following:

[HKLM\SOFTWARE\Microsoft\VisualStudio\{Version}\Generators\{C#/VB}\{ToolName}] @="{ToolDescription}" "CLSID"="{ToolGUID}" "GeneratesDesignTimeSource"=dword:00000001

As we don’t have any dependencies on any VS version, we should register under both keys, “7.0” and “7.1”, replacing the {Version} part. Also, we will register for both language categories. We will store as a constant the full registry key skeleton to format with the variable parameters. The registration methods are:

private const string KeyFormat = @"SOFTWARE\Microsoft\VisualStudio\{0}\Generators\{1}\{2}"; protected static void Register( Version vsVersion, Guid categoryGuid ) { using( RegistryKey key = Registry.LocalMachine.CreateSubKey( String.Format( KeyFormat, vsVersion, categoryGuid.ToString( "B" ), CustomToolName ) ) ) { key.SetValue( "", CustomToolDescription ); key.SetValue( "CLSID", CustomToolGuid.ToString( "B" ) ); key.SetValue( "GeneratesDesignTimeSource", 1 ); } } protected static void UnregisterCustomTool( Version vsVersion, Guid categoryGuid ) { Registry.LocalMachine.DeleteSubKey( String.Format( KeyFormat, vsVersion, categoryGuid.ToString( "B" ), CustomToolName ), false ); }

Finally, we have to call these methods at COM registration/unregistration time. We can specify the methods to be executed at that time, through the ComRegisterFunctionAttribute/ComUnregisterFunctionAttribute attributes:

[ComRegisterFunction] public static void RegisterClass( Type t ) { // Register for both VS.NET 2002 & 2003 (C#) Register( new Version( 7, 0 ), CSharpCategory ); Register( new Version( 7, 1 ), CSharpCategory ); // Register for both VS.NET 2002 & 2003 (VB) Register( new Version( 7, 0 ), VBCategory ); Register( new Version( 7, 1 ), VBCategory ); } [ComUnregisterFunction] public static void UnregisterClass( Type t ) { // Unregister for both VS.NET 2002 & 2003 (C#) Unregister( new Version( 7, 0 ), CSharpCategory ); Unregister( new Version( 7, 1 ), CSharpCategory ); // Unregister for both VS.NET 2002 & 2003 (VB) Unregister( new Version( 7, 0 ), VBCategory ); Unregister( new Version( 7, 1 ), VBCategory ); }

After compiling the project, we need to run the following command (in a VS.NET command prompt) on the project output folder to register the custom tool:

regasm /codebase XsdCodeGenerator.CustomTool.dll

And to unregister it:

regasm /unregister XsdCodeGenerator.CustomTool.dll

Alternatively, you can go to the project properties dialog, under Configuration Properties > Build, and set Register for COM Interop to true.
To run the custom tool for a file, we just need to set its Custom Tool property to XsdCodeGen.
Now we can finally move to the actual code generation inside the tool.

Generating Code

The first step is to factor out the code we used for the console application. We will associate the custom tool with XSD files, so we will already have the source filename in place. We won’t need the language because the BaseCodeGeneratorWithSite base class we used already provides access to a CodeDomProvider that is the appropriate one according to the current project type where the file lives in. Finally, as we specified at tool registration time that we would generate source at design-time (GeneratesDesignTimeSource registry value), VS.NET will automatically generate a new file dependent on the schema file, much like it does with a TypedDataset schema and its corresponding class file, a WebForm and its code-behind, a WinForm and its resource file, etc. All we need is implement the following method from the tool base class:

protected abstract byte[] GenerateCode( string inputFileName, string inputFileContent );

In order to better reuse code from the custom tool and the console app, we will separate the XSD processing in a new class and we will make the console app use this one by referencing the custom tool project. We could also create an entirely new class library just for this purpose, too.
So, the GenerateCode() method implementation is:

protected override byte[] GenerateCode( string inputFileName, string inputFileContent ) { string code = ""; try { // Process the file. CodeNamespace ns = Processor.Process( inputFileName, FileNameSpace ); // Generate code for it. CodeGeneratorOptions opt = new CodeGeneratorOptions(); opt.BracingStyle = "C"; StringWriter sw = new StringWriter(); GetCodeWriter().GenerateCodeFromNamespace( ns, sw, opt ); // Finaly assign it to the result to return. code = sw.ToString(); } catch( Exception e ) { code = String.Format( "#error Couldn't generate code!\n/*\n{0}\n*/", e ); } // Convert to bytes. return System.Text.Encoding.ASCII.GetBytes( code ); }

The new Processor class has almost the same code as the console app, but only generates the CodeNamespace, leaving the responsibility of generating the final source form to the caller. Note that the base class for the tool already provides access to the appropriate ICodeGenerator instance we mentioned, through the GetCodeWriter() method. We can also access the Custom Tool Namespace property that appears in the Property Browser for a file, through the FileNameSpace property.

We’re done with the tool now. We can start using it right away by associating the XsdCodeGen custom tool with any WXS file. Note that VS.NET locks the assembly when the tool is run for the first time. Should we want to keep modifying it and re-compiling, we will have to restart the IDE.

Extensions for codegen can be easily created to leverage the tool, simply by placing the extension assembly next to the custom tool installation folder, and adding the extension to the schema as follows:

<?xml version="1.0" encoding="utf-8" ?>
    <xs:schema
      ...etc...> <xs:annotation>
        <xs:appinfo> <Code xmlns= "http://weblogs.asp.net/cazzu">
        <Extension Type="XsdGenerator.Extensions.ArraysToCollectionsExtension, XsdGenerator.Library" />
        <Extension Type="XsdGenerator.Extensions.FieldsToPropertiesExtension, XsdGenerator.Library" />
        <Extension Type="MyExtensions.DoSomethingCool, MyExtension" />
      </Code>
    </xs:appinfo>
  </xs:annotation>

You'll need those extensions in order to modify the default output that matches the xsd.exe one. Enjoy!

ASP.NET Providers, reloaded

Note: this entry has moved.

Rob Howard wrote the second part on the provider design pattern they are using in Whidbey, and how to implement it in v1.x. An interesting reading. First of all, I'm really amazed at how open these guys are to good feedback from the community. Rob even dedicated a paragraph named "Extending configuration" that explains why they chose a NameValueCollection for provider initialization over an XmlNode, as I suggested (I'm sure other did too, it's a pretty obvious thing to ask). I really don't share the feeling that a NameValueCollection is *sooo much* easier than an XmlNode and its added flexibility, but at least I understand now why they did so: they expect complex providers to have their own section handler with all the information they need to work, which makes perfect sense!

There's a major performance issue in the implementation he suggests for v1.x, though, that has to do with the actual creation of the specific provider instance. There's a sort of mess in the naming and wording when this feature is explained. The article says:

When calling routines on the Membership class, internally it will always forwards those calls to an instance of the MembershipProvider—first creating an instance of MembershipProvider using a factory method, Instance(), and then calling the appropriate base class method on the retrieved instance.

Well, from the naming point of view, if Instance() is employed as a factory method, it should be called CreateProvider() or something like that, to denote that an instance will be created each time the method is called. And here comes the confusion, because Instance() more closely resembles the Singleton pattern rather than the Factory Method. If you think about it, there's no reason why we should instantiate a new membership object all the time. Not even the dynamic nature of providers justify this, because switching providers in the config file will cause an app restart anyway, loading the appropriate one afterwards.

And this is even more important than a mere wording because instantiating the provider dynamically requires using reflection. The abbreviated method shown in the article is:

public static MembershipProvider Instance() { // Use the cache because the reflection used later is expensive ...etc... // Load the configuration settings object[] paramArray = new object[1]; paramArray[0] = membershipProvider.Attributes["connectionString"]; return (MembershipProvider)( ((ConstructorInfo)cache[cacheKey]).Invoke(paramArray) ); }

Note that by caching only the constructor information, you're not earning much anyways. You end up using reflection at each method call anyway. So, if you convert this method from a factory method into a singleton, you directly cache the provider instance you create the first time the method is accessed. Furthermore, I'd directly move this singleton instance creation to the Membership (or similar for other provider-enabled features) altogether:

public class Membership { static MembershipProvider _instance; static Membership() { // Get the names of the providers MembershipConfiguration config = MembershipConfiguration.GetConfig(); // Read the configuration specific information for this provider Provider provider = (Provider) config.Providers[config.DefaultProvider]; // The assembly should be in \bin or GAC try { Type type = Type.GetType( provider.Type ); _instance = (MembershipProvider) Activator.CreateInstance( type ); // Initialize the provider with the attributes. _instance.Initialize( provider.Name, provider.Attributes ); } catch (Exception e) { throw new Exception("Unable to load provider", e); } } public static bool Validate( string username, string password ) { return _instance.Validate( username, password ); } public static void CreateUser( string username, string password ) { return _instance.CreateUser( username, password ); } }

You may have noticed that the original method in the article wrongly calls a special constructor passing a specific hardcoded attribute, "connectionString":

paramArray[0] = membershipProvider.Attributes["connectionString"]; // Special ctor?! return (MembershipProvider)( ((ConstructorInfo)cache[cacheKey]).Invoke(paramArray) );

It's obvious that by doing so the Instance() method is no longer generic, as it's expecting a provider to implement a specific ctor overload and receive a connection string! What if I have an XmlMembershipProvider? Given the base ProvideBase class all providers must implement, and what is explained in the article it makes much more sense to use the ProviderBase.Initialize method for provider initialization, as I did in the static ctor above:

Type type = Type.GetType( provider.Type ); _instance = (MembershipProvider) Activator.CreateInstance( type ); // Initialize the provider with the attributes. _instance.Initialize( provider.Name, provider.Attributes );

Anyway, it's good that we're having these discussions. The ASP.NET community needs these concepts to turn web applications into well architected solutions, leaving the ASP spaghetti programming style behind once and for all.

Sami Jaber (from DotNetGuru.org) article on lightweight containers

Note: this entry has moved.

Half the article is almost a straight copy of topics covered by Fowler's article. Trivial renaming is done to shadow this fact, basically replacing Fowler's MovieFinder example with BusinessObject one, which supposedly should be more attractive. And you only realize this if you read it entirely, and right at the bottom, find the link to Fowler's work and go read it (you realize in the first page if you already did, like myself).

He partially cites Fowler:

Martin Fowler's argument against this (Service Locator) pattern is its inaptitude to adapt to mock objects (for unit testing).

This reference is clearly distorted to make the previous discussion about Dependency Injection appear as supported and encouraged by Fowler. Initially, Fowler says: 

A common reason people give for preferring dependency injection is that it makes testing easier. The point here is that to do testing, you need to easily replace real service implementations with stubs or mocks.

Inmediately after, he states *his* view on the matter:

However there is really no difference here between dependency injection and service locator: both are very amenable to stubbing. I suspect this observation comes from projects where people don't make the effort to ensure that their service locator can be easily substituted.

Which is absolutely unquestionable.

The article is unnecessarily really hard to follow. The author makes too many assumptions in order for it to be understandable. For example, he assumes the reader is familiar with PetShopDNG. He makes a strong assertion like the following:

To summarize, the Abstract Factory and the dynamic code instantiation are a poor relation of the IOC approach. Why should we manage the life cycle of a dependency where an intermediary object could do it ? On another hand, if some techniques like code generation (AOP) allow to insert a behavior between client and provider, IOC gives a similar result with less effort.

Without clarifying a bit of it in the following paragraphs. He also says

When .NET IOC Frameworks will be ready (that's to say in some years ;))...

Well, as I showed in my previous article, the building blocks are in-place already, if you follow the ComponentModel architecture.

He shows an example where a class accesses a transaction object by using Transaction.Current:

public bool Buy(SharesInfo shares) { Transaction tx = Transaction.Current; // Execute against DB with tx

This is a very common approach in .NET, and it appears to be the one Indigo will be encouraging. The first drawback is that being a static property call, Transaction must be a specific implementation, not an interface. This was solved in ASP.NET Whidbey providers by having this class and its static members be just proxies on a concrete implementation instantiated as a singleton depending on config. The main drawback, however, is that if many services are potentially available, having [Service].Current for each of them makes for a highly descentralized service management. There's no way to administer, configure and provide all these services in a single place, therefore, maintainability and testability are hurt.

Posted 11 May 2004 11:36 AM by Daniel Cazzulino
Filed under:
Lightweight Containers and Plugin Architectures: Dependency Injection and Dynamic Service Locators in .NET

Note: this entry has moved.

Required reading: Inversion of Control Containers and the Dependency Injection pattern by Martin Fowler. If you haven't read it, you will not understand what I'm talking about, and I'm not fond of reproducing other's work here. It's better if you just read it, it's a very interesting article.

I'd like to analyze Fowler's article in the light of .NET and what we have now in v1.x. After reading his article, he seems to imply that lightweight containers are a new concept mainly fuelled by the Java community unsatisfied with heavyweight EJB containers. It turns out that .NET supported and heavily used this approach since its very early bits, released back in PDC'00 (July 14th 2000).

The basic building blocks for lightweight containers in .NET live in the System.ComponentModel namespace. Core interfaces are:

  • IContainer: the main interface implemented by containers in .NET.
  • IComponent: provides a very concrete definition of what a component is in this context. It's any class implementing this interface, and which can therefore participate in .NET containers.
  • ISite/IServiceProvider: the former inherits the later. It provides the vital link between a component and the container it lives in (its site), which enables service retrieval by the component. IComponent has a Site property of this type.
  • IServiceContainer: a default container for services, that IComponents can access through the ISite. Not actually required as the IContainer can store available services through other means.

The relationship between these clases can be depicted as follows:

Diagram showing interfaces relationship

A typical container/component/service interaction is:

  1. Specific container class is created by client code.
  2. Container initializes all services that components will have access to (optionally through an internal IServiceContainer). Client can optionally (if the container exposes its own IServiceContainer ) add further services at will.
  3. Either the container or client code adds components.
  4. Container "sites" these components by setting their IComponent::Site property, with an ISite implementation that offers services that are retrieved from the optional internal IServiceContainer or another implementation.
  5. Client code can access components by name or index through IContainer indexer.
  6. Components can perform actions requiring services that are retrieved through IComponent::Site::GetService(Type). This method is inherited from IServiceProvider actually.

So, in Fowler's terms, the IContainer implementation performs Interface Dependency Injection (through IComponent) of a single dependency, the Dynamic Service Locator (ISite : IServiceProvider). The former happens because the IContainer automatically sets the IComponent::Site property upon receiving the component to add through its IContainer::Add(IComponent) method. The later is the implementation of IServiceProvider::GetService(Type) method, which allows dynamic retrieval of services from the container.

Diagram of call sequence for IContainer/IComponent/ISite interaction

Fowler dislikes dynamic service locators because he says they rely on string keys and are loosely typed. In .NET IServiceProvider, you don't pass a string key but the actual Type of the service you request. What's more, the default interface implementation, System.ComponentModel.Design.ServiceContainer, checks that services published with a certain Type key are actually assignable to that type. Therefore, it's safe to cast them back upon retrieval. At most you get a null value from a provider, but never an InvalidCastException.

Following his example so that this is a natural adaptation to the .NET world, his MovieLister component will look like the following:

public class MovieLister : Component { public void Movie[] MoviesDirectedBy( string name ) { IMovieFinder finder = (IMovieFinder) GetService( typeof( IMovieFinder ) ); if ( finder == null ) return new Movie[0]; ArrayList all = finder.FindAll(); // Iterate, filter by name and return subset. }

It's common, that instead of implementing IComponent directly, concrete components inherit from its built-in default implementation Component, which provides a GetService shortcut method that also checks that the Site property is set before requesting a service from it.

Lifecycle of components is handled through three states:

  • IComponent::ctor: at construction time, the component is still not ready for work, as it can't access services.
  • IComponent::Site { set; }: the component is "sited", therefore it's fully functional now. At this (overridable) point, components can further configure themselves, for example by caching a reference to a service they use frequently: public class MovieLister : Component, IMovieLister { public override ISite Site { get { return base.Site; } set { base.Site = value; // Cache the finder. this._finder = (IMovieFinder) GetService( typeof(IMovieFinder) ); } }
  • IComponent::Dispose: when it's not needed anymore, a component may be diposed using the IDispose interface inherited by IComponent.

Fowler notes some drawbacks in general with regards to the service locator approach:

So the primary issue is for people who are writing code that expects to be used in applications outside of the control of the writer. In these cases even a minimal assumption about a Service Locator is a problem.
By standarizing on IComponent and ISite from System.ComponentModel, this isn't a problem anymore in .NET. Any component that uses these interfaces can be hooked into any container, and query services. This doesn't require dependencies on external products or unproven approaches: .NET uses extensively this feature.
Since with an injector you don't have a dependency from a component to the injector, the component cannot obtain further services from the injector once it's been configured.
As injection is being done for the service locator itself (the ISite : IServiceProvider instance), this isn't a problem anymore. Further services can be easily requested from it.
A common reason people give for preferring dependency injection is that it makes testing easier. The point here is that to do testing, you need to easily replace real service implementations with stubs or mocks. However there is really no difference here between dependency injection and service locator: both are very amenable to stubbing. I suspect this observation comes from projects where people don't make the effort to ensure that their service locator can be easily substituted.

I agree completely on this view. Aren't these architectures all about the ability to dynamically remove dependencies/hook/replace implementations dynamically? It's obvious to me that if such objective is not achieved, it's clearly not because injection vs service locator choice, but an implementation bug. Testing and stubbing with .NET containers is straightforward as components retrieve services by interface type, so stub impls. of those interfaces can be plugged into a testing IContainer implementation without problems.

Note that additionally, the IContainer can expose its internal IServiceContainer as yet another service, so that a component could publish a new service for consumption by others:

public class MovieLister : Component, IMovieLister { public override ISite Site { get { return base.Site; } set { base.Site = value; // Publish ourselves as new service. IServiceContainer container = (IServiceContainer) GetService( typeof(IServiceContainer) ); container.AddService( typeof(IMovieLister), this ); } }

This combination of IServiceProvider, IContainer and IComponent is in broad usage TODAY in Win and Web Forms platforms, as well as design-time and generally the IDE infrastructure. You're usin them everytime you create a Windows Form, Windows User Control, WebForm, etc.

Layering Service Containers

One scenario that .NET System.ComponentModel supports and that hasn't even been discussed by Fowler is that of chained service containers. Let's say you have a component, sited in a container, that performs some quite complex functionality. Now, let's say this complex functionality requires additional services that are provided by a specialized container and further components. In this case, the "main" component needs to instantiate a new container and execute further components. Needless to say, these components may require not only services from this new "child" container but also the parent one, the one where the "main" component lives.

Stacking service providers at this point is extremely useful. What you actually need is a Chain of Responsibility pattern where the service implementation is returned by the first provider in the chain that can respond to the request for it. This would allow you not only to chain different sets of services, but also to override implementations from a parent service provider. This is supported natively in .NET through the ServiceContainer implementation, and is heavily used in Visual Studio.NET IDE: some services are offered to components by a specific designer, or a VS package, or the IDE itself. Most requests for services propagate up the chain if necessary until they reach the IDE main container.

I've used exactly the same architecture for an upcoming automatic wizard framework for Shadowfax that acts as a child container inside the IDE. Some components need execution of yet another lower layer, a transformation engine that works with code templates to generate code (among other things), which is also a child container. At this point, the three layers, IDE, wizard and transformation engine, are chained together, so any component in the transformation engine, for example, can query services that are being offered by the IDE itself.

This is an extremely powerful and flexible approach, as you don't have to build monolythic container but can instead rely on components instantiating more specialized child containers to perform specific work.

Container Configuration

Of course, any good container should be configurable either programmatically and through configuration files. Fowler discusses the following with regards to configuration:

I often think that people are over-eager to define configuration files. Often a programming language makes a straightforward and powerful configuration mechanism. Modern languages can easily compile small assemblers that can be used to assemble plugins for larger systems. If compilation is a pain, then there are scripting languages that can work well also.

I agree absolutely. One usual dual config mechanism (XML + API) in .NET is creating an XSD for the file, get classes generated ready for XML Serialization, and support config either through the file reference, which is simply deserialized into the object model generated for the XSD, or through this object model itself, like so:

public class MyConfigurableContainer : <code>IContainer</code> { MyConfigurableContainer(string file) { ... } MyConfigurableContainer(MyConfigModel config) { ... } }

However, unless codegen customization is used, this raw XML serialization model is very poor when it comes to programmatic configuration, as classes only have parameterless ctors (so all initialization has to be done through property setters), there's no way to know which properties are required or optional, by default multi-value properties are arrays instead of typed collections, and so on.

Non-language configuration files work well only to the extent they are simple. If they become complex then it's time to think about using a proper programming language.

It's very interesting how most people nowadays perceive programmatic configuration APIs as a drawback over XML config files. I can't really understand why. With dynamic compilation becoming almost common place (i.e. ASP.NET v2 model, upcoming XAML, and so on), having a good programmatic API coupled with full programming language intellisense surely surpasses XML files in usability and productivity, specially for complex stuff.

It's usually the case (i.e. most of .NET) that after inventing a huge daunting configuration file format, admin UIs are created to manipulate them (i.e. .NET Framework Configuration, upcoming ASP.NET v2 admin console, etc.). At this point you start wondering: if nobody is ever going to touch those files except from those UIs, which is the advantage of having it in XML? Why don't just have those UIs generate compiled controllers that programmatically hook and configure everything? Just imagine the savings in parsing, validating, loading time... After all, you have to XCopy deploy those configs, just like the "assemblers" would...

The missing feature?

So, all the plumbing and required interfaces for implementing lightweight containers in .NET are already in-place. The framework doesn't contain any class to perform configuration of a container, though. This is not necessarily a bad thing, as it doesn't force any concrete file format or configuration API, leaving that to implementers. Creating such feature for an specific container (such as the Shadowfax Wizard container, or the transformation engine - code-named T3 for Templated Text Transformations) is almost trivial. Reading config, loading types, hooking services and components and that's it.

So, once more, we can see that .NET is the pioneer on supposedly "new" patterns. It's true that this pattern (and many others found throughout the .NET Framework) don't have enough advertising, and that may be the cause for their scarse use in .NET application architectures.

In a future post I'll discuss Apache Avalon and the Spring Framework, and how they compare to what's built-in .NET.

Update: maybe I should also mention that I've been using this tecnique with excelent results since the initial release of an opensource XML-based code generator back in Nov-2002
More Posts Next page »

Search