2

Before I begin I will say this: I have to extend DataContext in my repository because I'm calling stored procedures and ExecuteMethodCall is only available internally. Many people don't seem to know this, so please don't say "just don't extend DataContext".

I've just started using Windsor as my IoC container. My controller happily does the following:

public ContractsControlController(IContractsControlRepository contractsControlService)
{
    _contractsControlRepository = contractsControlService;
}

But my repository must have this constructor:

public ContractsControlRepository()
  : base(ConfigurationManager.ConnectionStrings["AccountsConnectionString"].ToString()) { }

But the IoC container is there to let you specify connection strings for your repository in the web.config. What must my constructor in the repository look like in order to do this? If I don't specify the one I've shown then it complains that there are no constructors that take zero arguments.

Cheers

EDIT

In global.asax.cs

ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory());

WindsorControllerFactory.cs (in the root)

public class WindsorControllerFactory : DefaultControllerFactory
{
  WindsorContainer container;

  public WindsorControllerFactory()
  {
    container = new WindsorContainer(new XmlInterpreter(new ConfigResource("castle")));

    var controllerTypes = from t in Assembly.GetExecutingAssembly().GetTypes() where typeof(IController).IsAssignableFrom(t) select t;

    foreach (Type t in controllerTypes)
    {
      container.AddComponentLifeStyle(t.FullName, t, LifestyleType.Transient);
    }
  }

  protected IController GetControllerInstance(Type controllerType)
  {
    return (IController)container.Resolve(controllerType);
  }
}

But the container isn't needed if nothing is going in web.config?

Kieran Senior
  • 17,960
  • 26
  • 94
  • 138

3 Answers3

2

David Kemp's suggestion is terse, but not type-safe. A more complex, but type-safe approach, would be using a factory method.

Imagine that the ContractsControlRepository class has been changed to take a connection string in its constructor. When that is the case, you can write something like this:

var connectionString = 
    ConfigurationManager.ConnectionStrings
        ["AccountsConnectionString"].ConnectionString;

var container = new WindsorContainer();
container.AddFacility<FactorySupportFacility>();
container.Register(Component
    .For<IContractsControlRepository>()
    .UsingFactoryMethod(k => new ContractsControlRepository(connectionString)));

Note that it is necessary to add the FactorySupportFacility to the container before the UsingFactoryMethod method will work.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • But then connection strings would need to be specified in code as opposed to through the web.config? One benefit of the IoC containers is being able to specify connection strings on the fly. – Kieran Senior Nov 09 '09 at 14:45
  • The connection string is pulled from web.config - just a different place in web.config. Does it matter that it is being pulled from the connectionStrings element instead of the castle element? Personally, I don't even use Castle's XML config features unless I have to... – Mark Seemann Nov 09 '09 at 19:48
  • Okay, but extending from `DataContext` doesn't seem to allow you to take a connection string as a parameter in the constructor, which I find very strange as there are four constructor definitions, on takes `IDbConnection` and the other takes `string fileOrServerOrConnection` – Kieran Senior Nov 10 '09 at 08:11
  • That is right, but you can always build a SqlConnection (implements IDbConnection) from a connection string. – Mark Seemann Nov 10 '09 at 08:39
  • But do I even need to do this? Can I not just have `k => new ContractsControlRepository()` then use the default constructor I've currently got specified that already picks up the accounts connection string? – Kieran Senior Nov 10 '09 at 09:05
  • Oh and also, where do you put the code you've got in your post? – Kieran Senior Nov 10 '09 at 09:07
  • Yes, you can also use the default constructor, but I read your original question as though you were asking about how you could register a component with a parameter. In any case, my answer waas only meant to provide you with some alternatives - I'm not saying that have to do it in this way... In ASP.NET MVC the container should be configured in global.asax - see here for more information: http://stackoverflow.com/questions/1410719/design-where-should-objects-be-registered-when-using-windsor/1410738#1410738 – Mark Seemann Nov 10 '09 at 09:13
  • Last question I promise. Does this mean I _don't_ require the WindsorControllerFactory, because that's used for web.config settings? – Kieran Senior Nov 10 '09 at 09:46
  • By WindsorControllerFactor I assume you mean the class from MVC contrib? You would still need that (or something similar) to wire up your Controller instances. – Mark Seemann Nov 10 '09 at 09:54
  • I've just made a quick edit to my original post to show you what I mean. – Kieran Senior Nov 10 '09 at 10:03
  • You don't need to configure your DI Container from web.config. I mostly do it via code. Even in your WindsorControllerFactory, you register all your Controllers so that it can later resolve the correct Controller, but if none of your Controllers use DI I can understand why it may seem redundant. – Mark Seemann Nov 10 '09 at 10:25
  • Uhm, test it? Sorry if this answer sounds a little glib, but I don't know what else to say... – Mark Seemann Nov 10 '09 at 15:55
1

Look at this question to see how to provide parameter constructors.

Community
  • 1
  • 1
kͩeͣmͮpͥ ͩ
  • 7,783
  • 26
  • 40
0

It works like this: you configure your repository as any other component, but you also provide the required connection string as a parameter in your configuration.

<component id="MyDataContext" service="yourservice" type="yourtype" lifestyle="singleton">
  <parameters>
    <connectionString>Data Source=localhost;Initial Catalog=YourCatalog;Integrated Security=SSPI</connectionString>
  </parameters>
</component>

Then, you add a parameter to the constructor of your own DataContext, the name of which is connectionString.

Venemo
  • 18,515
  • 13
  • 84
  • 125