I actually "solved" my issue with doing something similar with Castle this morning by just working around it. My issue that I mentioned in Friday's meeting was that we have two separate security contexts for our application (Online where the user has live access to the DB and Offline where the user just works against a local cache). Since we only identify the security context at login (we don't support switching between online and offline during the same session) I simply register the appropriate context with the container at startup. The psuedocode looks something like this...
if (IsOnline)
_container.Register<ISecurityContext, OnlineSecurityContext>
else
_container.Register<ISecurityContext, OfflineSecurityContext>
This works for us simply because we 'set it and forget it'. If the security context could switch any time in the same session then this wouldn't work and we'd have to use something like we talked about during the meeting, but for us this does the trick (simplest thing that works, right?)
Here's a link to the article that explains how to do something similar to the Autofac solution below with Castle. (I've never been able to get this example to work for me, though)
http://www.nablasoft.com/alkampfer/index.php/2007/05/19/windsor-container-resolveidictionary/
jeremy
One of the discussion points from the meeting was the scenario where you have a constructor where 1 or more parameters are to be injected and 1 or more parameters are to be supplied by the client code. I've been playing with Autofac a little bit and it has a really simple way to implement that. Here's my contrived example:
using System;
using Autofac;
using Autofac.Builder;
namespace AutofacTest
{
internal class Program
{
private static void Main()
{
var builder = new ContainerBuilder();
builder.Register<ConsoleLogger>().As<ILogger>();
builder.Register<LogCommand>();
builder.RegisterGeneratedFactory<LogCommandFactory>(new TypedService(typeof (LogCommand)));
builder.Register<HelloWorldThreeTimes>();
using (var container = builder.Build())
{
var helloWord = container.Resolve<HelloWorldThreeTimes>();
helloWord.Run();
}
}
}
internal class HelloWorldThreeTimes
{
private readonly LogCommandFactory commandFactory;
public HelloWorldThreeTimes(LogCommandFactory commandFactory)
{
this.commandFactory = commandFactory;
}
public void Run()
{
var command = commandFactory("Hello World.", 3);
command.Run();
}
}
internal delegate LogCommand LogCommandFactory(string message, int repeat);
internal class LogCommand
{
private readonly ILogger logger;
private readonly string message;
private readonly int repeat;
public LogCommand(string message, int repeat, ILogger logger)
{
this.message = message;
this.repeat = repeat;
this.logger = logger;
}
public void Run()
{
for (var i = 0; i < repeat; i++)
logger.Info(message);
}
}
internal interface ILogger
{
void Info(string message);
}
internal class ConsoleLogger : ILogger
{
public void Info(string message)
{
Console.WriteLine(message);
}
}
}
Using the RegisterGeneratedFactory() method to register a delegate as a factory method. Notice the LogCommandFactory takes 2 parameters while the LogCommand's constructor takes 3. Autofac glues them together automagically. Sweet.
--
Jeremy Jarrell
www.JeremyJarrell.com