Как сделать RavenDB DocumentStore доступным для вызывающих API

У меня есть приложение MVC4, использующее RavenDB в качестве хранилища данных. Приложение имеет уровни MVC/Web, Domain, Data и Security.

Я пишу пользовательские поставщики членства и ролей, которые должны инициализировать базу данных и получить доступ к хранилищу документов. Я пишу эти классы из уровня безопасности и хотел бы использовать одноэлементный DocumentStore (установленный в приложении), но я не могу понять, как получить к нему доступ.

Другие примеры, которые я вижу при написании пользовательских провайдеров для RavenDB, создают новые экземпляры DocumentStore в методах Provider.Initialize(), но это, кажется, нарушает правило наличия одного DocumentStore на сервер.

В настоящее время я создаю один экземпляр RavenDB DocumentStore в Application_Start(). У меня есть базовый контроллер на уровне MVC / Web, который обрабатывает DocumentStore.Session(s).

Есть ли способ сделать это? Должен ли я переместить свою логику безопасности в слой MVC / Web, чтобы упростить вещи?

2 ответа

Решение

Я придумал собственное решение, используя шаблон синглтона.

Что я сделал, так это создал синглтон, который предоставляет публичное свойство IDocumentStore, на уровне данных моего приложения. Он использует статический конструктор, который запускается при первом запросе статического свойства (выполняется в Application_Start) и, в свою очередь, создает экземпляр объекта IDocumentStore. Затем первоначальный экземпляр возвращается для каждой ссылки на DocStore.Instance в базовом контроллере и на других уровнях моего приложения (например, уровень безопасности 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);
    }
}

Возможно, вы захотите использовать какое-то внедрение зависимости, либо используя автоматические инструменты, такие как TinyIoC, либо вручную.

Например, посмотрите, как RaccoonBlog делает это. Во-первых, он создает экземпляр DocumentStore в Application_Start и сохраняет эти ссылки в статических переменных различных базовых классов:

https://github.com/ayende/RaccoonBlog/blob/master/RaccoonBlog.Web/Global.asax.cs#L66

Затем он внедряет новый объект Session каждый раз, когда начинается новый сеанс:

https://github.com/ayende/RaccoonBlog/blob/master/RaccoonBlog.Web/Global.asax.cs#L31

И этот элемент извлекается из базового класса контроллера:

https://github.com/ayende/RaccoonBlog/blob/master/HibernatingRhinos.Loci.Common/Controllers/RavenController.cs#L16

Я бы сделал это немного лучше, используя правильный IoC или, по крайней мере, не используя словарь Предметов, но вы понимаете, в чем дело.

Просто держите DocumentStore где-нибудь публично и добавляйте открытые сессии в базовые классы

Другие вопросы по тегам