asp.net-mvc-4ravendbmembership-providerroleproviderdocument-store

How to make RavenDB DocumentStore available to calling APIs


I have an MVC4 application using RavenDB as a datastore. The application has MVC/Web, Domain, Data, and Security layers.

I am writing custom membership and role providers that need to initialize the database and access the DocumentStore. I'm writing these class from the Security layer, and would like to use a singleton DocumentStore (set in the application), but I can't figure out how to access it.

Other, examples I see of writing custom providers for RavenDB create new DocumentStore instances within the Provider.Initialize() methods, but that seems to break the rule of having a single DocumentStore per server.

Currently, I create a single instance of the RavenDB DocumentStore in Application_Start(). I have a base controller in the MVC/Web layer that handles the DocumentStore.Session(s).

Is there a way of accomplishing this? Should I move my security logic into the MVC/Web layer to simplify things?


Solution

  • I came up with my own solution using a singleton pattern.

    What I did was create a singleton, that exposes a public IDocumentStore property, in the data layer of my application. It utilizes a static constructor which runs upon first request for static property (executed in Application_Start), and in turn instantiates an IDocumentStore object. The initial instance is then then returned for each reference to DocStore.Instance in a base controller and in other layers of my application (like the security layer f.ex.)

    public sealed class DocStore
    {
        protected static readonly IDocumentStore instance;
    
        static DocStore()
        {
            // instantiate documentStore
            instance = new DocumentStore { ConnectionStringName = Constants.ConnectionStrings.XXXXX };
            instance.Initialize();
    
            // instantiate tenants
            try
            {
                instance.DatabaseCommands.EnsureDatabaseExists(Constants.Tenants.XXXXX);
            }
            catch (Exception ex)
            {
    
                //TODO: catch exception
                throw ex;
            }
    
            // initialize indexed
            try
            {
                InitializeIndexes(instance);
            }
            catch (Exception ex)
            {
    
                //TODO: catch exception
                throw ex;
            }
        }
    
        private DocStore()
        {
    
        }
    
        public static IDocumentStore Instance
        {
            get { return instance; }
        }
    
        private static void InitializeIndexes(IDocumentStore store)
        {
            // builds all indexes defined in XXXXX.Data.dll
            var dataCatalog = new CompositionContainer(new AssemblyCatalog(typeof(DocStore).Assembly));
            IndexCreation.CreateIndexes(dataCatalog,
                                        store.DatabaseCommands.ForDatabase(Constants.Tenants.XXXXX),
                                        store.Conventions);
        }
    }