The Relationship Zoo

  • January 25, 2010 10:11 pm

Dependency Injection, unsurprisingly, is all about the relationships between components.

Components rarely exist or perform any useful task alone. A system that achieves a business function may use tens, hundreds or even thousands of different components, all working in collaboration to get a job done.

Early IoC containers understood one kind of relationship: “A needs a B.”

interface B { }

class A
{
    public A(B b) { ... }
}

More complex relationships, like “A creates instances of B” required the author of component A to deal directly with the container to get things done, by calling container.Resolve<B>(), for example.

Since a majority of relationships are, in fact, simple direct dependencies, this was an acceptable point from which to start developing IoC containers as a technology. Recently, more powerful, declarative ways of specifying “higher-order” dependencies have emerged. In this article we’ll look at a selection of them, using Autofac 2 as an example implementation.

I was first introduced to the term “higher-order dependencies” by Mircea Trofin at Microsoft. I’m not sure I’m using it here in precisely the same sense. The .NET Composition Primitives, which Mircea was instrumental in creating, have some elegant mechanisms for handling them – in a future article I hope to cover this in more detail.

A Catalog of Relationships

It turns out that there are a lot of different ways that one component may relate to another.

A-depends-on-B

Here’s a partial list to fill in the question mark above:

  1. A needs a B
  2. A needs a B at some point in the future
  3. A needs a B until some point in the future
  4. A needs to create instances of B

    • and provides parameters of types X and Y
  5. A needs all the kinds of B
  6. A needs to know X about B before using it

This list is chosen carefully, because each of these relationships can be expressed declaratively through simple adapter types.

Relationship Adapter Type Meaning
A needs a B None Dependency
A needs a B at some point in the future Lazy<B> Delayed instantiation
A needs a B until some point in the future Owned<B> Controlled lifetime
A needs to create instances of B Func<B> Dynamic instantiation
A provides parameters of types X and Y to B Func<X,Y,B> Parameterisation
A needs all the kinds of B IEnumerable<B> Enumeration
A needs to know X about B before using it Meta<B,X> Metadata interrogation

Some of the types above will be familiar: Lazy<T>, Func<T> and IEnumerable<T> are all .NET BCL types, and are used here with their standard semantics.

Owned<T> and Meta<T> are introduced by Autofac, and fill some of the gaps in the BCL. They’re very simple types that could be replicated in an application that wanted to use them independently.

Lazy<T>

A lazy dependency is not instantiated until its first use. This appears where the dependency is infrequently used, or expensive to construct.

class A
{
    Lazy<B> _b;
   
    public A(Lazy<B> b) { _b = b }
   
    public void M()
    {
        // The component implementing B is created the
        // first time M() is called
        _b.Value.DoSomething();
    }
}

Owned<T>

An owned dependency can be released by the owner when it is no longer required. Owned dependencies usually correspond to some unit of work performed by the dependent component.

class A
{
    Owned<B> _b;
   
    public A(Owned<B> b) { _b = b }
   
    public void M()
    {
        // _b is used for some task
        _b.Value.DoSomething();
   
        // Here _b is no longer needed, so
        // it is released
        _b.Dispose();
    }
}

In an IoC container, there’s often a subtle difference between releasing and disposing a component: releasing and owned component goes further than disposing the component itself. Any of the dependencies of the component will also be disposed. Releasing a shared component is usually a no-op, as other components will continue to use its services.

Func<T> and Func<X,Y,T>

The ‘factory’ adapters imply creation of individual instances of the dependency. The parameterised versions allow initialisation data to be passed to the implementing component.

class A
{
    Func<int, string, B> _b;
   
    public A(Func<int, string, B> b) { _b = b }
   
    public void M()
    {
        var b = _b(42, "http://hel.owr.ld");
        b.DoSomething();
    }
}

IEnumerable<T>

Dependencies of an enumerable type provide multiple implementations of the same service (interface).

class A
{
    IEnumerable<B> _bs;
   
    public A(IEnumerable<B> bs) { _bs = bs }
   
    public void M()
    {
        foreach (var b in bs)
            b.DoSomething();
    }
}

Meta<T,M>

Metadata is data-about-data. Requesting metadata with a dependency allows the dependent component to get infomation about the provider of a service without invoking it.

class A
{
    Meta<B,BMetadata> _b;
   
    public A(Meta<B,BMetadata> b) { _b = b }
   
    public void M()
    {
        if (_b.Metadata.SomeValue == "yes")
            _b.Value.DoSomething();
    }
}

The Relationship Zoo

If you’ve read this far, you’re probably desperate for an example that doesn’t use the components A and B. I feel your pain! The truth is, while these dependencies are useful in their own right, really interesting dependencies often combine multiple adapters!

Choosing a File Viewer

Metadata is excellent when there are multiple implementations of a service, and one must be selected to perform a task. The selection criterion mightn’t be inherent in the component itself, so properties make awkward choices for representing this data.

Let’s say we have a number of file viewers, and, via configuration, we associate each viewer with the file types that it should be used to view.

interface IViewer
{
    void View(string filename);
}

interface IViewerMetadata
{
    IEnumerable<string> FileTypes { get; }
}

class Browser
{
    IEnumerable<Meta<IViewer, IViewerMetadata>> _viewers;
   
    public Browser(IEnumerable<Meta<IViewer, IViewerMetadata>> viewers)
    {
        _viewers = viewers;
    }
   
    public void OnViewFile(string filename)
    {
        var ext = Path.GetExtension(filename);
        var viewer = _viewers.Single(v => v.FileTypes.Contains(ext));
        viewer.View(filename);
    }
}

In this example, IEnumerable<T> and Meta<T> are combined to express the two features of the relationship between Browser and IViewer.

Mixing in dynamic creation, controlled lifetime or lazy initialization would often also make sense in this kind of scenario.

You can see how metadata is associated with an Autofac component here, or examine one of the many examples based on the MEF APIs here.

Creating and Releasing a Message Handler

Another common combination is that of dynamic instantiation and ownership of the instances. A message pump may create, use, then release a handler for each incoming message:

interface IMessageHandler
{
    void Handle(Message message);
}

class MessagePump
{
    Func<Owned<IMessageHandler>> _handlerFactory;
   
    public MessagePump(Func<Owned<IMessageHandler>> handlerFactory)
    {
        _handlerFactory = handlerFactory;
    }
   
    public void Go()
    {
        while(true)
        {
            var message = NextMessage();
           
            using (var handler = _handlerFactory())
            {
                handler.Value.Handle(message);
            }
        }
    }
}

Many instances, with dynamic creation and controlled lifetime and parameters and and and whoah!

Yes, IEnumerable<Meta<Func<X,Y,Owned<T>>,M>> is in fact a valid relationship type. Glad you asked?

Common combinations can be eaiser to work with when they are baked into a single class. In MEF, for example, Meta<Lazy<T>> is represented as Lazy<T,M>. Likewise Func<Owned<T>> is represented as PartCreator<T>. You can plug these composite adapter types into Autofac via a custom registration source if you need them.

Custom delegate types can also ease angle-bracket-eyestrain if you use the parameterised factories a lot.

The core of Autofac 2 doesn’t have any special knowledge of any of these adapter types. They’re all plugged in as IRegistrationSource implementations, meaning that you are free to change or extend the set of adapter types as your needs dictate.

Muahahahahhahahaahhh!!!!

I heard that maniac laugh just then! Let me just slip in the disclaimer now: just because you can model almost any conceivable relationship type this way, doesn’t mean that you should. Where a simple direct dependency will suffice, don’t gouge out your eyes on six layers of nested angle brackets, or invest in new adapter types. Like all sharp tools, use context adapters with discretion.

At the same time, there’s practically no excuse to use IContainer or IComponentContext in your components anymore.

Conclusions and a Suggestion

You might not be using Autofac today, and might not have any desire to. That’s okay! Anything new and useful you see here will no doubt make its way back into the container you prefer – this is the magic of being part of an Open Source community.

If you do use Autofac, or are curious, download the .NET 4.0 version from the project site.

A note to container developers…

Although this is an Autofac-centric article, it draws on the combined experience of many passionate people who are driving .NET composition technology forward.

I’m not sure yet that we share a common vision of the “v.Next” IoC container – one thing we do seem to agree on is that it is harmful to have the container abstraction leak through into components. Perhaps in the future, IoC containers will be completely transparent, but we have some way yet to go.

Common Service Locator (CSL) was a step forward in interoperability. A good range of applications and frameworks that need dynamic or lazy instantiation no longer have to depend on a specific IoC container; I think this is one way we’ve maintained diversity and a healthy ecosystem.

CSL is a stopgap though – a service locator that could handle all of the scenarios above would be a monster of an interface indeed! CSL also breaks the declarative nature of components that use it.

I’d be very interested to hear thoughts on a new project, Common Context Adapters, which would include types like Owned<T> and Meta<T,M> to fill gaps in the BCL while it evolves. It would also provide baseline documentation on how wiring of Func<T> etc. should work.

Common Context Adapters would play a similar role to CSL by isolating applications and frameworks from the specifics of an IoC container, but in a way that is compatible with declarative dependency wiring and inversion of control.

I’m prepared to put effort into making this happen if there is enough interest.

Building an External DSL in C#

  • January 19, 2010 12:12 am

Download the example as a VS2010 solution.

Our current project includes a small workflow for submission and approval of user account creation requests. This makes a good example to discuss domain-specific languages and Sprache, so I’ll paraphrase some of the requirements here.

The set of user account types is open-ended; currently “employee”, “contractor”, “temporary” and so on. To request a particular kind of account, a user must fill in a questionnaire associated with that account type.

In the data collection and approval parts of the system, the content of the questionnaire is irrelevant so long as the necessary information is recorded and presented to the administrator, who will ultimately approve or decline the request.

The Challenge

Much of the system design is driven by the fact that the set of possible account types (and thus different questionnaires) is open. Creating new questionnaires should be possible without redeploying the application. Furthermore, the content of a particular questionnaire needs to be easily extended and modified, possibly by end-users themselves.

There are many possible ways to represent the questionnaires:

  • Map a questionnaire domain model to relational database tables
  • Create an XML-based questionnaire format
  • Use Windows Workflow Foundation with loose XAML files
  • Read the questionnaires from CSV files or spreadsheets

Each has its pros and cons with regard to ease of implementation, maintainability, user-friendliness and flexibility.

In this article, we’ll examine another appealing option: building a user-friendly mini-language to represent questionnaires.

Questionnaire Definition Language

You may have read some discussion of the differences between internal and external DSLs.

An internal DSL is a specially-constructed API in a general-purpose language like C# that, when used, reads more like a definition of the problem than a program to solve it.

An external DSL is a standalone language that must be parsed from source text before a program can work with it. Importantly for this example, an external DSL encourages a minimum of syntactic noise, and can be read without any program compilation.

The example questionnaire DSL looks like:

identification  "Personal Details"
[
    name        "Full Name"
    department  "Department"
]

employment      "Current Employer"
[
    name        "Your Employer"
    contact     "Contact Number"
    #months     "Total Months Employed"
]

Above is a two-step questionnaire that collects personal and employment details.

  • Each section has an id, a title, and a list of questions.
  • Each question has an id and some prompting text.
  • The declaration of a question id (e.g. #months) can be prefixed with a symbol to indicate what kind of data is being collected – the pound sign/hash in this case denotes a natural number.

The application will read the questionnaire definition associated with a particular kind of account request, and present the steps to the user in a wizard-like interface.

Approaches to Parsing the Questionnaire Definitions

Parsing is the process of taking text in a source language, like the questionnaire above, and converting it into a representation – usually some kind of object model – that a program can work with. For the C# programmer, there are several ways to achieve this.

Hand-built Parsers

The very simplest as well as the most complex parsers are often built by hand. The simple ones because the solution is readily evident to the programmer (e.g. “split the string by finding commas in a loop”) and the most complex because the programmer needs an extreme level of control (e.g. the C# compiler.) Parsing anything in between by hand is usually more trouble than it is worth, unless you’re really into languages and know what you’re doing (that definitely rules me out!)

Regular Expressions

These are a convenient way of matching and extracting patterns from text. .NET includes the built-in System.Text.Regex class for working efficiently with regular expressions, so they’re usually the first option to consider when faced with a parsing task. Beyond quite simple grammars, regular expressions rapidly become hard to read and maintain. This is perhaps the biggest of their shortcomings, but there are also many grammars that regular expressions are unable to parse (starting with those that allow nesting.)

Parser Construction Toolkits

Industrial-strength parser construction toolkits and ‘language workbenches’ allow a grammar to be specified in a declarative format. The toolkit includes build-time tools to generate classes in the target programming language (e.g. C#) that can parse the grammar. Using such a toolkit requires an investment in both learning how the toolkit works, and integrating it into a project’s build process. For small parsing tasks this can be overkill, but for anything of significant complexity or requiring high parsing throughput, learning and using to use such a toolkit is highly recommended.

Parser Combinators

This function-based technique is often used by default in functional languages like Haskell and F#, both of which have high-quality parser combinator libraries. C# also has a fledgling combinator library called Sprache, built by yours truly and used in the rest of the article. Sprache makes it very easy to write and maintain simple parsers, without a steep learning curve or build-time tasks. It fits very nicely with a test-driven development process. The drawbacks are currently speed, efficiency and sometimes the quality of error messages – none of which is a big deal when parsing simple DSLs.

Getting Started

First, download Sprache.dll. This article is organised in such a way that you should be able to follow along with the text by creating and testing parsers in Visual Studio with NUnit or similar.

Grammars are built from the bottom up. First, parsers are created for the low-level syntax elements like identifiers, strings and numbers. We then work upwards, combining these basic units into more complex ones until we have the complete language.

Parsing an Identifier

In our questionnaire definition language, the most-nested significant element is the question:

name    "Full Name"

The basic parts here are an identifier an some quoted text. The first task for our parser will be to parse the identifier, in this case ‘name’.

[Test]
public void AnIdentifierIsASequenceOfCharacters()
{
    var input = "name";
    var id = QuestionnaireGrammar.Identifier.Parse(input);
    Assert.AreEqual("name", id);
}

Parsers in Sprache are static methods on a class representing the grammar. QuestionnaireGrammar.Identifier is of type Parser<string>, i.e. it returns values of type string from the input.

The definition of the parser is:

public static readonly Parser<string> Identifier = Parse.Letter.AtLeastOnce().Text().Token();

This reads fairly well – we’re going to parse a non-empty sequence of letters and return the text representation of those letters. The elements of the parser here are:

Parse.Letter – the Sprache Parse class contains helper methods and properties for common parsing tasks. Letter is a simple parser of type Parser<char>, that reads a letter from the input and returns it as a char. If the next character on the input isn’t a letter, this parser won’t match.

AtLeastOnce() – all parsers created by Sprache support repetition this way. AtLeastOnce() takes a parser for a single element of type T and returns a new parser that will parse a sequence of elements, returning IEnumerable<T>.

Text() – the AtLeastOnce() modifier took our Parser<char> and converted it into a parser of type Parser<IEnumerable<char>>. The Text() helper function takes a parser of IEnumerable<char> and converts it into a Parser<string>, so that the result is more convenient to work with.

Token() – finally, the token modifier accepts then discards leading and trailing whitespace.

Simple?

There are a couple more tests we might be interested in for the Identifier parser.

[Test]
public void AnIdentifierDoesNotIncludeSpace()
{
    var input = "a b";
    var parsed = QuestionnaireGrammar.Identifier.Parse(input);
    Assert.AreEqual(“a”, parsed);
}

A Sprache parser will parse as much as it can before returning. In this test case the parser will succeed, but won’t consume all of the input. (Later we’ll see how to make assertions about end-of-input.)

[Test]
public void AnIdentifierCannotStartWithQuote()
{
    var input = "\"name";
    Assert.Throws<ParseException>(() => QuestionnaireGrammar.Identifier.Parse(input));
}

The Parse() extension method throws ParseException when the parser doesn’t match. You can alternatively use the non-throwing TryParse().

Once we’re happy that identifiers are being parsed correctly we can move on.

Parsing Quoted Text

Quoted text isn’t much harder to parse than an identifier – our basic version doesn’t support escaped characters or anything fancy.

Looking again at the input:

name    "Full Name"

To parse the quoted text, we need to match:

  1. The opening quote
  2. Anything except another quote
  3. The closing quote

The quotes themselves aren’t particularly interesting to the program, so we’ll return only the text between them.

One test for the parser will look like:

[Test]
public void QuotedTextReturnsAValueBetweenQuotes()
{
    var input = "\"this is text\"";
    var content = QuestionnaireGrammar.QuotedText.Parse(input);
    Assert.AreEqual("this is text", content);
}

Jumping straight to the parser:

public static readonly Parser<string> QuotedText =
    (from open in Parse.Char('"')
     from content in Parse.CharExcept('"').Many().Text()
     from close in Parse.Char('"')
     select content).Token();

This opportunistic repurposing of the Linq query comprehension syntax was first described (AFAIK) by Luke Hoban from the F# team. The from clauses lay out the individual units of the syntax, while the select clause transforms them into the return value of the overall parser.

Parsing the Question

You’ve probably noticed by now that parsers are strongly-typed: a parser for a character returns char, and a parser for text returns string. A parser for a question, will return – Question!

public class Question
{
    public Question(string id, string prompt)
    {
        Id = id;
        Prompt = prompt;
    }

    public string Id { get; private set; }

    public string Prompt { get; private set; }
}

This is a great strength of combinator-based parsing when constructing DSLs. Once a semantic model for the problem has been built, the parser can translate input directly into it.

public static readonly Parser<Question> Question =
    from id in Identifier
    from prompt in QuotedText
    select new Question(id, prompt);

A unit test for a basic question now passes:

[Test]
public void AQuestionIsAnIdentifierFollowedByAPrompt()
{
    var input = "name \"Full Name\"";
    var question = QuestionnaireGrammar.Parse(input);
    Assert.AreEqual("name", question.Id);
    Assert.AreEqual("Full Name", question.Prompt);
}

Parsing a Section

Parsing a section is just like parsing a question: first we build the semantic model, then use the existing parsers to translate the source text.

Remember a section looks like:

identification "Personal Details"
[
    name        "Full Name"
    department  "Department"
]

We can represent this in the object model as:

public class Section
{
    public Section(string id, string title, IEnumerable<Question> questions)
    {
        Id = id;
        Title = title;
        Questions = questions;
    }

    public string Id { get; private set; }

    public string Prompt { get; private set; }

    public IEnumerable<Question> Questions { get; private set; }
}

Building a parser is as easy as building the object model:

public static readonly Parser<Section> Section =
    from id in Identifier
    from title in QuotedText
    from lbracket in Parse.Char('[').Token()
    from questions in Question.Many()
    from rbracket in Parse.Char(']').Token()
    select new Section(id, title, questions);

To complete the example, we have one more model class to define:

public class Questionnaire
{
    public Questionnaire(IEnumerable<Section> sections)
    {
        Sections = sections;
    }

    public IEnumerable<Section> Sections { get; private set; }
}

Its corresponding parser (this time without the comprehension syntax):

public static Parser<Questionnaire> Questionnaire =
        Section.Many().Select(sections => new Questionnaire(sections)).End();

By affixing .End() to the parser, we require that the full input is parsed (i.e. there’s no trailing garbage.)

That’s all we need for the example without any data type qualifiers.

Supporting Answer Data Types

The finishing touches of our grammar add support for the answer type qualifiers.

#months "Total Months Employed"

We can use an enumeration for the possible answer types.

public enum AnswerType
{
    Natural,
    Number,
    Date,
    YesNo
}

This is a pretty limited set, so by brute force we’ll check for each possible qualifier.

public static Parser<AnswerType> AnswerTypeIndicator =
    Parse.Char('#').Return(AnswerType.Natural)
        .Or(Parse.Char('$').Return(AnswerType.Number))
        .Or(Parse.Char('%').Return(AnswerType.Date))
        .Or(Parse.Char('?').Return(AnswerType.YesNo));

The Question object is modified to accept an AnswerType as a constructor parameter, and a simple modification of the Question parser completes our work.

public static Parser<Question> Question =
    from at in AnswerTypeIndicator.Or(Parse.Return(AnswerType.Text))
    from id in Identifier
    from prompt in QuotedText
    select new Question(id, prompt, at);

Summary

The complete parser is just six rules, totaling about 25 nicely-formatted lines of code.

While robust parsing is a non-trivial task in the real world, I hope this article shows that there are simple, low-friction options that fill some of the gaps between regular expressions and language workbenches.

MVC Integration Changes in Autofac Beta 2.1.6

  • January 5, 2010 9:05 pm

Autofac 1.4 and earlier 2.1 versions used AutofacControllerModule as a way of finding and registering ASP.NET MVC controllers with the container.

In the Autofac 2.1 MVC integration, there is a new ContainerBuilder extension method called RegisterControllers.

var builder = new ContainerBuilder();

// Was:
// builder.RegisterModule(new AutofacControllerModule(...))
builder.RegisterControllers(Assembly.GetExecutingAssembly());

_containerProvider = new ContainerProvider(builder.Build());
ControllerBuilder.Current.SetControllerFactory(
                new AutofacControllerFactory(_containerProvider));

The reason for the switch is that RegisterControllers is a thin wrapper around the new assembly scanner, and supports the same syntax as the rest of Autofac’s registration methods:

builder.RegisterControllers(assembly)
  .InjectProperties()
  .OnActivated(e => Log.Information("Controller created: " + e.Instance));

Resolve Anything

  • January 3, 2010 10:36 am

Ward Bell, one of the most diligently pragmatic programmers out there, just wrote about bootstrapping Prism with containers other than Unity.

One of the pain points that Ward observes is Prism’s use of “resolve anything” – a Unity feature that causes the container to act as though all concrete types are registered.

// Works, even though Foo isn't registered,
// because Foo is concrete.
var container = new UnityContainer();
var foo = container.Resolve<Foo>();

Other containers have different behaivours – by default, Autofac will throw ComponentNotRegisteredException in this case.

I’m not a fan of Unity’s behaviour – I rarely use concrete types as services, and generally would want to configure them first anyway.

However, for those with different views, there are simple ways to make this work with Autofac.

Autofac 1.4 – RegisterTypesMatching()

Autofac 1.4 includes a configuration method that can help here. The parameter is a predicate on a requested Type, and if the result is true the container will happily resolve instances of the type.

var builder = new ContainerBuilder();
builder.RegisterTypesMatching(t => t.IsClass && !t.IsAbstract);
var container = builder.Build();

// Now works
var foo = container.Resolve<Foo>();

Autofac 2.1 – ResolveAnythingSource

Autofac 2 doesn’t have an equivalent to RegisterTypesMatching(). This is because Autofac 2’s assembly scanner, RegisterAssemblyTypes() does a much better job in similar scenarios.

Those who’ve been following along with this blog lately will have seen how registration sources provide a simple way to extend the container to understand new component types (like Lazy Dependencies.)

Well, the registration source to implement “resolve anything” is just a few lines, included here in its entirety. If you need this behaviour, feel free to include it in your project.

class ResolveAnythingSource : IRegistrationSource
{
    public IEnumerable<IComponentRegistration> RegistrationsFor(
        Service service,
        Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        var ts = service as TypedService;
        if (ts != null && !ts.ServiceType.IsAbstract && ts.ServiceType.IsClass)
        {
            var rb = RegistrationBuilder.ForType(ts.ServiceType);
            return new[] { RegistrationBuilder.CreateRegistration(rb) };
        }

        return Enumerable.Empty<IComponentRegistration>();
    }
}

Configuring the container to use the new source is easy.

var builder = new ContainerBuilder();
builder.RegisterSource(new ResolveAnythingSource());
var container = builder.Build();

// Works now
var foo = container.Resolve<Foo>();

One Small Caveat

You should probably be aware of one small gotcha that both of these samples exhibit. If you actually do register an implementation of Foo, then resolve all instances of Foo, you’ll find that both your registered component, plus the automatically-generated one, will be there. This is a very unlikely situation, but it might pay to keep it in mind.

If you found your way here looking for Autofac’s Prism integration, good news is right around the corner! The source for AutofacContrib.Prism is in the trunk, and just needs a few updates before it will get a proper release.

Parsing strings to System.Linq.Expression

  • January 3, 2010 8:57 am

The example included with the last post is probably a bit underwhelming, so I thought I’d include another.

LinqyCalculator

This variation on the “good old calculator example” takes a string input like 1 + 2 * (3 + 4) and produces an equivalent System.Linq.Expression that can be executed to get the numeric value.

You can also play around with the very minimal included error handling abilities.

Check out the code for the parser and the driver program.

Sprache C#

  • January 2, 2010 7:37 pm

No, I haven’t reverted to my ancestors’ tongue.* Sprache is a small library for parsing text from C#.

// Parse a number of capital 'A's in a row, e.g. "AAAA"
var parseA = Parse.Char('A').AtLeastOnce();

If you’ve spent any time with Haskell, you’ll be familiar with Parsec, a beautiful framework for building parsers in a functional manner.

Sprache is based on the same design (yes, the ‘m’ word applies here) ported to C# with some help from a couple of excellent tutorials.

I built Sprache as a learning exercise, but posted it to Google Code because there seems to be no other implementation with controlled source, an issue tracker, and a well-defined license. It could use some input from someone who really knows their stuff, so hopefully the public site will help find that person.

Check out the Sprache homepage for some examples and links.

*’Sprache C#’ as far as my limited German takes me, means ‘C# Language’.

Declarative Context Adapters in Autofac 2

  • January 1, 2010 10:39 am

The previous post on this blog showed how Autofac 2 can provide Lazy<T> dependencies whenever T is registered.

Other types that Autofac provides via the same mechanism are:

  • Func<T>, Func<T,U> &c., to create components on-the-fly;
  • Owned<T> to manually control the lifetime of a component;
  • IEnumerable<T> to get all implementers of a service; and
  • Instances of a particular generic type, e.g. IRepository<Customer>, when the open generic type, e.g. Repository<T>, is registered.

Each of these can be thought of as a declarative context adapter. Each of these types supports a scenario involving some kind of interaction between a component and the container that hosts it. Instead of having the component call the container directly, the component expresses requirements declaratively using these little adapter types, and the container provides the implementation.

Don’t worry if it is a stretch to imagine how each of these works. For today, we’ll examine the implementation of Lazy<T>, and that should give you enough background to figure out the others if you want to.

IRegistrationSource: a better Service Locator?

Context adapters like these are provided to Autofac via IRegistrationSources.

public interface IRegistrationSource
{
    IEnumerable<IComponentRegistration> RegistrationsFor(
        Service service,
        Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor);
}

A registration source is much like a Service Locator: when the container needs to provide service, it queries the registration source to get any available implementations.

The registration source can use the passed-in registrationAccessor to get information about other components registered with the container.

At first glance this seems to be a Service Locator plain and simple, however there is an important distinction. The IComponentRegistration’s returned from RegistrationsFor() tell the container how to make components supporting the service. They are not instances of the services themselves.

This means that among other benefits, a registration source is called only once for any particular service (e.g. Lazy<IFoo>) no matter how many times the service is resolved. The performance overhead, compared with using a Service Locator this way, is very low.

LazyRegistrationSource

If you’re using Autofac on .NET 4.0, you can use LazyRegistrationSource (by registering LazyDependencyModule) to get support for the context adapter System.Lazy<T>.

LazyRegistrationSource is a very simple implementation of IRegistrationSource.

class LazyRegistrationSource : IRegistrationSource
{
    public IEnumerable<IComponentRegistration> RegistrationsFor(
        Service service,
        Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        var swt = service as IServiceWithType;
        if (swt == null ||
            !swt.ServiceType.IsGenericType ||
            swt.ServiceType.GetGenericTypeDefinition() != typeof(Lazy<>))
            return Enumerable.Empty<IComponentRegistration>();

        var valueType = swt.ServiceType.GetGenericArguments()[0];

        var valueService = swt.ChangeType(valueType);

        var registrationCreator = CreateLazyRegistrationMethod.MakeGenericMethod(valueType);

        return registrationAccessor(valueService)
            .Select(v => registrationCreator.Invoke(null, new object[] { service, v }))
            .Cast<IComponentRegistration>();
    }

    static readonly MethodInfo CreateLazyRegistrationMethod = typeof(LazyRegistrationSource)
        .GetMethod("CreateLazyRegistration", BindingFlags.Static | BindingFlags.NonPublic);

    static IComponentRegistration CreateLazyRegistration<T>(
        Service providedService,
        IComponentRegistration valueRegistration)
    {
        var rb = RegistrationBuilder.ForDelegate(
            (c, p) => {
                var context = c.Resolve&ltIComponentContext>();
                return new Lazy<T>(() => (T)c.Resolve(valueRegistration, p));
            })
            .As(providedService);

        return RegistrationBuilder.CreateRegistration(rb);
    }
}

Let’s break this down.

RegistrationsFor()

The whole purpose of RegistrationsFor() is to map a service to components that can provide it:

public IEnumerable<IComponentRegistration> RegistrationsFor(
    Service service,
    Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{

In LazyRegistrationSource we’re looking for services that are based on the Lazy<T> type.

So, the first part of RegistrationsFor checks to see if the service fits this description, and if not, the method returns an empty list of components, since it can’t provide anything.

var swt = service as IServiceWithType;
if (swt == null ||
    !swt.ServiceType.IsGenericType ||
    swt.ServiceType.GetGenericTypeDefinition() != typeof(Lazy<>))
    return Enumerable.Empty<IComponentRegistration>();

If we get past this test, then we know we’re dealing with Lazy<T>. Since we provide Lazy<T> on top of T, we extract T and construct a Service with it so that we can find implementations.

var valueType = swt.ServiceType.GetGenericArguments()[0];
var valueService = swt.ChangeType(valueType);

Lazy<T> is a generic type, but we’re deep in the land of reflection here. Rather than clog our code up with tonnes of reflective goop, we use a generic method parameterised on T to switch over into strongly-typed code to create a registration for Lazy<T>.

var registrationCreator = CreateLazyRegistrationMethod.MakeGenericMethod(valueType);

We’ll come back to the implementation of CreateLazyRegistration in just a second.

Once we have a method that can create a IComponentRegistration for Lazy<T> based on a component registration for T, we use registrationAccessor to find all the T registrations, and use our function to map them to a result.

return registrationAccessor(valueService)
    .Select(v => registrationCreator.Invoke(null, new object[] { service, v }))
    .Cast<IComponentRegistration>();

Now to the implemenation behind registrationCreator.

CreateLazyRegistration

This method takes an IComponentRegistration for T and wraps it in an IComponentRegistration for Lazy<T>. The providedService parameter is the service that our registration is going to provie to the container (some kind of service based on Lazy<T>.)

static IComponentRegistration CreateLazyRegistration<T>(
    Service providedService,
    IComponentRegistration valueRegistration)
{

Autofac 2 provides some helpers for creating registrations. The syntax below is the implementaiton equivalent of calling Register((c, p) => ...).As(providedService) on a ContainerBuilder.

var rb = RegistrationBuilder.ForDelegate(
    (c, p) => {
        var context = c.Resolve&ltIComponentContext>();
        return new Lazy<T>(() => (T)c.Resolve(valueRegistration, p));
    })
    .As(providedService);

return RegistrationBuilder.CreateRegistration(rb);

Some noteworthy points stick out:

  • The context is re-resolved from c, since we need the underlying context and not the temporary one used for the current operation;
  • We’re using a new Resolve() overload that takes an IComponentRegistration; and
  • We forward the parameters p on to the value resolve call, so that parameters passed when resolving Lazy<T> will be available to T.

Wrapping Up

This isn’t the kind of code you’ll write day-to-day when using Autofac 2. What’s exciting though, is how easy it can be to write sophisticated IoC-driven applications without having infrastructure concerns scattered through your code.

Next time you hear the question “but how do I do X without calling the container directly?” remember that there’s probably a declarative context adapter for that, based on IRegistrationSource.