AutoFac / .NET Core - регистрация DBcontext

У меня есть новый проект .NET Core Web API, который имеет следующую структуру проектов:

API -> Бизнес / Домен -> Инфраструктура

API очень тонкий, только методы API. Уровень Бизнес / Домен имеет всю мою бизнес-логику. И, наконец, на моем уровне инфраструктуры есть классы БД, использующие EF Core 2.0.

Я знаю, что с помощью встроенной в .NET Core инъекции зависимостей я могу добавить ссылку из проекта API в проект инфраструктуры, а затем добавить следующий код в файл StartUp.cs:

services.AddDbContext<MyContext>(options => options.UseSqlServer(connectionString));

Однако я хотел бы сохранить более традиционное разделение проблем. До сих пор я добавил модуль в свой уровень инфраструктуры, который пытается выполнить регистрацию следующим образом:

builder.Register(c =>
        {
            var config = c.Resolve<IConfiguration>();

            var opt = new DbContextOptionsBuilder<MyContext>();
            opt.UseSqlServer(config.GetSection("ConnectionStrings:MyConnection:ConnectionString").Value);

            return new MyContext(opt.Options);
        }).AsImplementedInterfaces().InstancePerLifetimeScope();

Однако DBContext не регистрируется. Любой класс, который пытается получить доступ к внедренному DBContext, не может разрешить параметр.

Есть ли способ зарегистрировать DBContext в отдельном проекте с помощью AuftoFac в проекте .NET Core Web API?

Также на будущее. «Это, однако, не работает». - это ничего не объясняет и не помогает нам понять вашу проблему, поэтому мы должны угадать, в чем ваша проблема. Вы должны написать, что именно происходит - сообщение об ошибке, возникшее исключение или что-то еще, что вы подразумеваете под «Это не работает». Это может привести к сбою вашей ОС, выключению компьютера или взрыву электростанции - мы этого не знаем и поэтому не можем дать содержательный совет.

Alexander Leonov 02.05.2018 02:01

@AlexanderLeonov Спасибо за отзыв. Я обновил вопрос, добавив больше информации.

Kyle Barnes 02.05.2018 02:14

Это лучше. Похоже, мое предположение было правильным - вы должны регистрировать класс MyContext напрямую, а не интерфейсы, которые он реализует.

Alexander Leonov 02.05.2018 02:18
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
30
3
18 602
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

В желаемом проекте вы можете создать метод расширения, который добавляет контекст в коллекцию

public static class MyDataExtensions {
    public static IServiceCollection AddMyData(this IServiceCollection services) {
        //...

        services.AddDbContext<MyContext>(options => options.UseSqlServer(connectionString));

        //...
    }
}

с этим тогда в вашем запуске это просто вопрос вызова расширения, предоставленного из другого проекта

services.AddMyData();

//...other settings

Проект API является корнем композиции, поэтому ему в любом случае необходимо знать все соответствующие зависимости. По крайней мере, с этим расширением вам не нужно делать прямую ссылку на используемый контекст db,

Ответ принят как подходящий

Думаю, проблема в том, что вы пытаетесь зарегистрировать MyContext() с помощью AsImplementedInterfaces(). Обычно DbContext не регистрируется. Вы должны зарегистрировать и разрешить сам класс.

Вы были правы. Я изменил .AsImplementedInterfaces () на .AsSelf (), и теперь он работает. Спасибо!

Kyle Barnes 02.05.2018 02:39

Я использую Autofac для регистрации как HttpContextAccessor, так и DbContext.

builder
    .RegisterType<HttpContextAccessor>()
    .As<IHttpContextAccessor>()
    .SingleInstance();

builder
    .RegisterType<AppDbContext>()
    .WithParameter("options", DbContextOptionsFactory.Get())
    .InstancePerLifetimeScope();

DbContextOptionsFactory

public class DbContextOptionsFactory
{
    public static DbContextOptions<AppDbContext> Get()
    {
        var configuration = AppConfigurations.Get(
            WebContentDirectoryFinder.CalculateContentRootFolder());

        var builder = new DbContextOptionsBuilder<AppDbContext>();
        DbContextConfigurer.Configure(
            builder, 
            configuration.GetConnectionString(
                AppConsts.ConnectionStringName));

        return builder.Options;
    }
}

DbContextConfigurer

public class DbContextConfigurer
{
    public static void Configure(
        DbContextOptionsBuilder<AppDbContext> builder, 
        string connectionString)
    {
        builder.UseNpgsql(connectionString).UseLazyLoadingProxies();
    }
}

Если я хочу изменить строку подключения на основе строки запроса запроса. Как получить доступ к HttpContext внутри класса DbContextOptionsFactory? Я не могу разрешить HttpContextAccessor внутри DbContextOptionsFactory, поскольку он не собирался, когда мы обращаемся к DbContextOptionsFactory.

Balagurunathan Marimuthu 08.05.2020 09:48

Еще одно простое решение для Autofac версии 4.8.1

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().AddControllersAsServices();

        services.AddDbContext<MyContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ConnectionStrings:MyConnection:ConnectionString")));

        var builder = new ContainerBuilder();

        builder.Populate(services);

        //...
        // Your interface registration
        //...

        builder.Build(Autofac.Builder.ContainerBuildOptions.None);
    }

Вот реализация, которую я использую - она ​​имитирует Регистрация EF Core 3.1 с Autofac 4.9.4. Обязательно отрегулируйте прицелы в соответствии с вашими требованиями.

public void RegisterContext<TContext>(ContainerBuilder builder)
    where TContext : DbContext
{
    builder.Register(componentContext =>
        {
            var serviceProvider = componentContext.Resolve<IServiceProvider>();
            var configuration = componentContext.Resolve<IConfiguration>();
            var dbContextOptions = new DbContextOptions<TContext>(new Dictionary<Type, IDbContextOptionsExtension>());
            var optionsBuilder = new DbContextOptionsBuilder<TContext>(dbContextOptions)
                .UseApplicationServiceProvider(serviceProvider)
                .UseSqlServer(configuration.GetConnectionString("MyConnectionString"),
                    serverOptions => serverOptions.EnableRetryOnFailure(5, TimeSpan.FromSeconds(30), null));

            return optionsBuilder.Options;
        }).As<DbContextOptions<TContext>>()
        .InstancePerLifetimeScope();

    builder.Register(context => context.Resolve<DbContextOptions<TContext>>())
        .As<DbContextOptions>()
        .InstancePerLifetimeScope();

    builder.RegisterType<TContext>()
        .AsSelf()
        .InstancePerLifetimeScope();
}

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