Note: This question is indeed somewhat similar to this one, but I think I can put it in a simpler and more specific way.
I'm using Castle Windsor to intercept the URI passed to my Web API app to register the appropriate concrete class to the Controller's constructor.
What I want to be able to do is pass a "site number" on the URI, perhaps always as either the first or last arg. IOW, for site 42, instead of
http://localhost:28642/api/platypi/GetAll
...it would be:
http://localhost:28642/api/platypi/42/GetAll
-or:
http://localhost:28642/api/platypi/GetAll/42
When my Web API app first "sees"/intercepts the URI, I want to note that site number so that I can assign the desired concrete Repository to be registered by Castle Windsor. I want to be able to do this:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
if (siteNum == 42)
{
container.Register(
Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository42>().LifestylePerWebRequest(),
Component.For<IInventoryItemRepository>().ImplementedBy<InventoryItemRepository42>().LifestylePerWebRequest(),
. . .
}
else if (siteNum = 77)
{
container.Register(
Component.For<IDepartmentRepository>().ImplementedBy<DepartmentRepository77>().LifestylePerWebRequest(),
Component.For<IInventoryItemRepository>().ImplementedBy<InventoryItemRepository77>().LifestylePerWebRequest(),
. . .
}
In this way I can give site 42 its data, site 77 its data (each site uses a different database that share a common schema).
So: At which point in my Web API app's lifecycle can I hijack the URI, so as to assign the appropriate val to the global siteNum variable, so that it has been assigned before the IWindsorInstaller method runs?
UPDATE
Thanks to Mr. Slate, but if I were to do that, would this Controller code:
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository");
}
_deptsRepository = deptsRepository;
}
...become:
public DepartmentsController(IDepartmentRepository deptsRepository)
{
if (deptsRepository == null)
{
throw new ArgumentNullException("deptsRepository");
}
_deptsRepository = deptsRepository(siteNum);
}
...or???
And I'm still left with the problem of where do I intercept the incoming URI before Castle Windsor / the Controller gets it, so that I can set the appropriate value to the global / siteNum var?
There are a number of extensions points that you can use to achieve this, personally I use this one for a similar result.
Create a custom model binder by extending
IModelBinder
something like this:Okay so now we jus tneed to register our new ModelBinder:
Okay and now in our controller all we do is add the SiteManager as a parameter of any Action and it will get filled in by our ModelBinder.
Here is a different way you could try rather using Castle Windsor which might be better:
Create a repository factory like this:
Create a component selector to select the correct repository based on the name like this:
Register your repositories like this:
As long as Windsor is loading your controllers using a constroller factory you can now do this:
For reference my global.asax.cs:
And my repositories:
I'd change the constructor on DepartmentRepository() to pass the site num and use that to get the connectionstring. Then in your webconfig create a connectionstring for each site.