Autofac: регистрация типа InstancePerRequest

189
12 марта 2019, 16:30

ASP.NET WebApi2, контроллер

public class BooksController : ApiController
{
    public IRepository Repository
    { get; set; }
    public BooksController(IRepository r)
    {
        Repository = r;
    }
    ...
}

Репозиторий:

public class BookRepository : IRepository, IDisposable
{
    public BookContext Context
    { get; set; }
     ...
    protected void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (Context != null)
            {
                Context.Dispose();
                Context = null;
            }
        }
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Контекст данных:

public class BookContext : DbContext
{
    public DbSet<Book> Books
    { get; set; }
}

В качестве IoC используется Autofac, контейнер конфигурируется в Global.asax:

protected void Application_Start()
{
        AutofacConfig.ConfigureContainer();
        . . . 
}
public class AutofacConfig
{
    public static void ConfigureContainer()
    {
        var builder = new ContainerBuilder();
        var config = GlobalConfiguration.Configuration;
        builder.RegisterType<BookRepository>().InstancePerRequest().As<IRepository>().WithProperty("Context", new BookContext());
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    }
}

Почему-то при такой регистрации типа BookRepository не создается новый экземпляр его свойства Context с новым http-запросом. То есть первый http-запрос в API работает, а на второй возвращается такая ошибка: The operation cannot be completed because the DbContext has been disposed.

Answer 1

Для начала, я бы вам посоветовал переписать ваш репозиторий. В нем мне не нравится 2 вещи:

  1. Инъекция в свойство. По моему мнению, если класс имеет обязательные зависимости, то они должны быть отражены в конструкторе. Иначе остается возможность создать класс и не инициализировать свойство, без которого класс не работает.

  2. Второе, что мне не нравится - это ваша реализация IDisposable. Зачем вам делить её на 2 функции? Вы планируете в наследниках добавлять финализатор? Я так не думаю. Я бы вообще наследование от этого класса запретил.

В итоге, после моих правок, репозиторий станет выглядеть как то так:

public sealed class BookRepository : IRepository, IDisposable
{
    public BookRepository(BookContext ctx)
    {
        _context = ctx;
    }
    private BookContext _context;   
    public void Dispose()
    {
        _context?.Dispose();
        _context = null;
    }
}

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

builder.RegisterType<BookContext>();
builder.RegisterType<BookRepository>().InstancePerRequest().As<IRepository>();

Никаких инъекций в свойство не надо, зависимость от контекста объявлена в конструкторе репозитория и должна подхватываться контейнером автоматом.

READ ALSO
Спавн пули относительно оружия

Спавн пули относительно оружия

Столкнулся с такой проблемой: Есть космический корабль, у него есть дочерние объекты - орудия на нужных позицияхНо пули спавнятся не там где...

170
Событие в C# WPF MVVM

Событие в C# WPF MVVM

Есть 2 ViewModel`и AuthViewModel и LoginViewModelВ LoginView есть Frame который контент которого LoginControl а у него контекст AuthViewModel

147
Как построить текстурированную сферу в SharpGL и разместить по определенным координатам?

Как построить текстурированную сферу в SharpGL и разместить по определенным координатам?

Хочу нарисовать Землю и Луну с использованием своего алгоритма вращения (те

140