1

I twist myself around a workable solution to use several databases in RavenDB for an ASP.Net MVC app using Castle Windsor for the wiring.

This is the current installer

public class RavenInstaller : IWindsorInstaller
{

    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(
            Component.For<IDocumentStore>().Instance(CreateDocumentStore()).LifeStyle.Singleton,
            Component.For<IDocumentSession>().UsingFactoryMethod(GetDocumentSesssion).LifeStyle.PerWebRequest
            );
    }

    static IDocumentStore CreateDocumentStore()
    {
        var store = new DocumentStore { ConnectionStringName = "RavenDb_CS9" };
        store.Initialize();
        IndexCreation.CreateIndexes(typeof(Users).Assembly, store);
        return store;
    }

    static IDocumentSession GetDocumentSesssion(IKernel kernel)
    {
        var store = kernel.Resolve<IDocumentStore>();
        return store.OpenSession();
    }

}

The above works perfect but only for one Database.

I can't find the proper thinking how to handle another database. The whole chain starts with a domain service asking for an IDocumentSession. Then the flow is as specified in the above installer. But where/how do I ask for a "SessionToDb1" or a "SessionToDb2"?

The important is of course what connection string to use (where the DB property is specified) but also what indexes to create in respective DB / DocumentStore.

Did anyone accomplish this using Windsor? Am I thinking/attacking it wrong here?

Thanks!

Community
  • 1
  • 1
Max
  • 3,280
  • 2
  • 26
  • 30
  • This link may help you: http://stackoverflow.com/questions/3531552/castle-windsor-how-to-resolve-components-based-on-constructor-parameters – Maciej May 31 '13 at 13:29
  • Thanks! I'm currently looking into the configuration option .Named() where you can name each registration and use that (instead of type) when resolving. Promising. Your link put me in the right direction. – Max Jun 04 '13 at 14:32

2 Answers2

1

Because you have:

Component.For<IDocumentSession>()
         .UsingFactoryMethod(GetDocumentSesssion)
         .LifeStyle.PerWebRequest

Your GetDocumentSession method is going to be called any time you inject an IDocumentSession. This is good.

When working with multiple databases, you need to pass the database name as a parameter to OpenSession. So, you need some way to resolve which database you would like to connect to based on the current web request.

You need to modify the GetDocumentSession method to implement whatever custom logic you are going to use. For example, you may want to look at a cookie, asp.net session item, current thread principal, or some other criteria. The decision is custom to your application, all that matters is somehow you open the session with the correct database name.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Exactly my issue :) This have been a bit strange to me. I'm currently looking into the .Named() component registration option. I also think that some kind of "global" condition would not be appropriate, calling code should define it. Thanks! – Max Jun 04 '13 at 14:37
0

I've run into this problem before with nhibernate.

I found the best solution is to create a SessionManager class which wraps the Creation of the document store and the Session..

So I.E.

public interface ISessionManager
{
    void BuildDocumentStore();
    IDocumentSession OpenSession();
}

public interface ISiteSessionManager : ISessionManager
{

}

public class SiteSessionManager : ISiteSessionManager
{
    IDocumentStore _documentStore;

    public SiteSessionManager()
    {
        BuildDocumentStore();
    }

    public void BuildDocumentStore()
    {
        _documentStore = new DocumentStore
        {
            Url = "http://localhost:88",
            DefaultDatabase = "test"
        };

        _documentStore.Initialize();
        IndexCreation.CreateIndexes(typeof(SiteSessionManager).Assembly, _documentStore);
    }

    public IDocumentSession OpenSession()
    {
        return _documentStore.OpenSession();
    }
}

// And then!. 
Container.Register(Component.For<ISiteSessionManager>().Instance(new SiteSessionManager()).LifestyleSingleton());

// And then!.
public class FindUsers
{
    readonly ISiteSessionManager _siteSessionManager;

    public FindUsers(ISiteSessionManager siteSessionManager)
    {
        _siteSessionManager = siteSessionManager;
    }

    public IList<User> GetUsers()
    {
        using (var session = _siteSessionManager.OpenSession())
        {
            // do your query
            return null;
        }
    }
}

Rinse and repeat for multiple databases.!

Chris Kolenko
  • 1,020
  • 17
  • 32