Autoregistration without Binsor

May 13th, 2008

On my Global.cs I usually have:

private static void RegisterWebComponents()
{
    container.Register(AllTypes.Of<SmartDispatcherController>().
        FromAssembly(typeof(HomeController).Assembly));

    container.Register(AllTypes.Of<ViewComponent>().FromAssembly(typeof(Global).Assembly)
            .Configure(
                delegate(ComponentRegistration reg)
                {
                    reg.Named(reg.ServiceType.Name);
                }));

}

To get Windsor integration:

First, make the Global implement the IContainerAccessor

public class Global : HttpApplication, IContainerAccessor

Then add a static field to hold the container

private static WindsorContainer container;

The App_Start/End and the IContainerAccessor implementation:

protected void Application_Start(object sender, EventArgs e)
{
    container = new WindsorContainer(new XmlInterpreter());
    container.AddFacility("mr", new MonoRailFacility());

    RegisterWebComponents();
}

protected void Application_End(object sender, EventArgs e)
{
    container.Dispose();
}

public IWindsorContainer Container
{
    get { return container; }
}

To Configure MonoRail using code

Make the global implement IMonoRailConfigurationEvents and implement the method Configure:

public class Global : HttpApplication, IContainerAccessor, IMonoRailConfigurationEvents
{
    public void Configure(IMonoRailConfiguration configuration)
    {
        // Configuring ViewEngine
        configuration.ViewEngineConfig.ViewPathRoot = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Views");
        configuration.ViewEngineConfig.ViewEngines.Add(new ViewEngineInfo(typeof(NVelocityViewEngine), false));

        // You can configure other things, and hopefully in the future 
        // we can expose a kind of fluent interface to guide you on this process
    }
}

12 Responses to “Autoregistration without Binsor”

Torkel Says:

Great, the less xml the better!

The nice thing about the auto registration API is that it will skip components already added in the xml config. So you still have the power to change components with out a recompile.

João Marques Says:

How do you normally add generic components to the container (like a repository) without the need of xml config?

Steve Gentile Says:

Silly question for you:

If you are doing this automatically, how are you handling injected items?

ie. my controllers take Dao object(s) in the constructor and get injected.

Steven Radack Says:

Very nice. I wrote up a post about using this method to register MonoRail extensions as well: http://sradack.blogspot.com/2008/05/registering-monorail-extensions.html

cristian Says:

Hi and thank you for your work on the castle stack. Truly amazing stuff. I’ve been wondering about the IContainerAccessor and exposing the container through the application (as opposed to a public static somewhere).

Is there a reasoning behind you want to share?

Damon Carr Says:

Cool.. It seems like the ‘next phase’ of adoption in this area is all about optimization (such as minimizing config).

I would say a few minor words:

1) I would prefer to not create a hard-wired dependency (no pun intended) from ASP.NET (global.asax) and Windsor. Is is a nice element of reuse to use the HttpModule, but more importantly for my second point.

2) What I have discovered in creating a framework for Windsor attempting to all but eliminate not only config, but also provide a vendor ‘plug-in’ model so consumers can choose their favorite ‘container’ and it will still work.

I have found the concepts are evolved enough and in the offering I have, it exposes a Framework API covering the domain of ‘Interface Defined Services’ – whatever they may be for, 0 to X Concrete Implementations of services (doing who knows what, but REALLY doing it), and the surrounding rules, input to rules, and actions/delegates to occur (again 0..X) on rule success (with a meta layer of context driving an additional level of rule action specification).

I must say Lambadas make this experience much nicer, and although I’ve always advocated teams achieving reuse at the DELEGATE level (which most don’t think of for some reason) ever since 2.0, the concept seems to be slowly sinking in.

I often will say ‘look at the code you run inside the foreach to calculate ‘custom value X’… You could think of that as a code asset to be reused in your domain (as an executable item) and make it part of your API.

This is really most of what I have done. First, abstract the moving pieces, and decompose to your comfort level of functional primitives. It really is all about creating DSLs now I believe, be they formal or not. Be they in Boo or Microsoft’s DSL Designer. Who cares as long as FINALLY people start to get their heads out of the sand on the ‘excuse of technology’.

So the code to do injection usng MVP in ASP.NET consists of:

1) in web.config:

2) The Init is:

void IHttpModule.Init(HttpApplication context) {

context.EndRequest += NotifyContainerForWebLifeStyle;
context.PreRequestHandlerExecute += Context_OnPreRequestHandlerExecute; }

3) So the interesting part comes in the PreRequest:

private static void Context_OnPreRequestHandlerExecute(object sender, EventArgs e) {

// NOTE : Iteration removed for clarity.,..
Inject.Using(Elementals.TaskMVP, Elementals.ReverseInject);

}
So we are performing an injection using an ‘out of the box’ pattern for MVP defined as a Functor called TaskMVP. Then we have X number of actions we could perform post (the second paramater is a params if Action.

So here is what Elementals.TaskMVP looks like:

public static Func TaskMVP
{
get
{
return httpHandler => TryInjectPresenter(HttpContext.Current.Handler);
}
}

Very domain specific… If it can meet all the user defined requirements for what a Presenter is, and if it can actually find one, it will resolve it (and register if required) using a Transient or Page lifestyle.

The second part is optional, and is also a configuration. It simply injects the presenter into the view:

public static void ReverseInject(object presenter)
{

Inject.
UsingSet(Properties(presenter),
GetPropertyByName(“VIEW”),
SetProperty(presenter, HttpContext.Current.Handler));

}

The inject class looks like:

public static T1 Using(Func functor, T2 element2, params Action[] actionsPost)
{
var resultT1 = functor.Invoke(element2);

foreach (var action in actionsPost) {

action.Invoke(resultT1);
}
return resultT1;
}

It’s messy going deep into the internals, but moving out it is extremely fluent.

Kind Regards,

Damon Wilder Carr

Andy Hitcman Says:

Very elegant.

I’m trying to get rid of my XML config right now, but I’ve found a problem with extended properties and facilities (RemotingFacility in my case).

JIRA is out of action right now, so I can’t report or submit a patch.

To summarise, in ComponentRegistration.Register extended properties are added to the model after Kernel.ComponentModelBuilder.BuildModel is invoked, meaning that the facilities inspector gets no extended properties and therefore does not configure the component correctly.

I have a local patch that extends ComponentDescriptor with ApplyToRegistration and have refactored ExtendedProperitesDescriptor to use this to set up a dictionary to be passed to BuildModel.

I can submit this for review if you tell me how (or get JIRA up again).

Cheers,

Andy

Andy Hitcman Says:

Re previous comment on adding generic components:

You need to use the parameterised version of the For method to specify an open generic class:

Component.For(typeof(IRepositoryProvider))
.ImplementedBy(typeof(NHibernateRepository))

Andy Hitcman Says:

My angled brackets got removed from that code sample:

Component.For(typeof(IRepositoryProvider<>))
.ImplementedBy(typeof(NHibernateRepository<>))

Andy Hitcman Says:

Apologies for using your blog post as an issue tracker!

Having spent some time in the MicroKernel source code I now understand the difference between extended properties and configuration.

The RemotingFacility uses Configuration rather than ExtendedProperties as some other common Facilities like Startable.

It must be configured like:

Component.For<IRemoteAuthoriser>()
.Named(“RemoteAuthoriser”)
.Configuration(Attrib.ForName(“remoteclient”).Eq(“Singleton”))

Ivan Says:

Which assembly where i can find IMonoRailConfigurationEvents ?

Ivan Says:

I cant find the IMonoRailConfigurationEvents. i used the RC3.

Leave a Reply