MVC Code first и Ninject кэширование со сложными отображениями - PullRequest
2 голосов
/ 25 августа 2011

Мой вопрос очень похож на этот: Инструмент MVC3, использующий проблемы кэширования Entity Framework с Ninject , однако мое отображение немного сложнее, и когда я использую InRequestScope, я получаю следующую ошибку:

Операция не может быть завершена, поскольку был удален DbContext.

Если я не включу InRequestScope, все работает, кроме EF Code First, похоже, что кеширует мои сущности и этоне совпадает со значениями в БД.

Вот мое сопоставление nject, я использую пакет nuget ninject mvc3 (без InRequestScope):

kernel.Bind<MyContext>()
  .ToSelf()
  .WithConstructorArgument("connectionString", context => MvcApplication.GetConnectionStringName);

kernel.Bind<IUnitOfWork>().To<UnitOfWork>();

// Service Layer.
kernel.Bind<ICustomerService>().To<CustomerService>();
kernel.Bind<IMessageService>().To<MessageService>();
kernel.Bind<IUserService>().To<UserService>();

// Repository Layer.
kernel.Bind<IRepository<Customer>>().To<GenericRepository<Customer>>();
kernel.Bind<IRepository<Message>>().To<GenericRepository<Message>>();
kernel.Bind<IRepository<User>>().To<GenericRepository<User>>();

NinjectContainer.Initialize(kernel);

My IUnitOfWork

public interface IUnitOfWork
{
    IUserService UserService { get; }
    ICustomerService CustomerService { get; }
    IMessageService MessageService { get; }
    void CommitChanges();
}

Мой UnitOfWork

public class UnitOfWork : IUnitOfWork
{
    MyContext _context;

    private readonly IUserService _userService;
    private readonly ICustomerService _customerService;
    private IMessageService _messageService;

    public UnitOfWork(IUserService userService,
        ICustomerService customerService,
        IMessageService messageService,
        MyContext context)
    {
        _userService = userService;
        _customerService = customerService;
        _messageService = messageService;

        SetContext(optimaContext);
    }

    private void SetContext(MyContext context)
    {
        _context = context;
        _userService.Context = _context;
        _customerService.Context = _context;
        _messageService.Context = _context;
    }
    public void CommitChanges()
    {
        _context.SaveChanges();
    }

    public IUserService UserService { get { return _userService; } }
    public ICustomerService CustomerService { get { return _customerService; } }
    public IMessageService MessageService { get { return _messageService; } }
}

Мой ICustomerService

public interface ICustomerService
{
    DbContext Context { get; set; }
    IQueryable<Customer> All();
}

Мой CustomerService

public class CustomerService : ICustomerService
{
    IRepository<Customer> _customerRepo;

    public CustomerService(IRepository<Customer> customerRepo)
    {
        _customerRepo = customerRepo;
    }

    private DbContext _context;
    public DbContext Context
    {
        get { return _context; }
        set { _context = value; _customerRepo.Context = value; }
    }

    public IQueryable<Customer> All()
    {
        return _customerRepo.All();
    }
}

Другие мои службы следуют аналогичной схеме.

Мой IRepository

public interface IRepository<T> where T : class, new()
{
    DbContext Context { get; set; }

    T Single(Expression<Func<T, bool>> expression);
    T Find(object id);
    IQueryable<T> All();
    void Delete(Expression<Func<T, bool>> expression);
    void Delete(T item);
}

Мой репозиторий

public class GenericRepository<T> : IRepository<T> where T : class, new()
{
    DbContext _context;

    public DbContext Context
    {
        get { return _context; }
        set { _context = value; }
    }

    public virtual T Single(Expression<Func<T, bool>> expression)
    {
        return All().FirstOrDefault(expression);
    }

    public virtual T Find(object id)
    {
        return _context.Set<T>().Find(id);
    }

    public virtual IQueryable<T> All()
    {
        return _context.Set<T>();
    }

    public virtual void Delete(Expression<Func<T, bool>> expression)
    {
        var items = All().Where(expression);
        foreach (var item in items)
        {
            Delete(item);
        }
    }

    public virtual void Delete(T item)
    {
        _context.Set<T>().Remove(item);
    }
}

Если кто-то может помочь с отображением Ninject и правильным способом введения классов, это будет очень признательно.

1 Ответ

4 голосов
/ 25 августа 2011

Я обнаружил проблему, я использовал атрибут [Inject] с FilterAttribute, когда атрибут вызывался, это было до того, как мой контекст был инициализирован, и это привело к ошибке dbContext.

Я следовал за вики на сайте gitub njectject здесь , чтобы настроить ninject на FilterAttribute. По проблеме я нашел метод BindFilter, это скрыто Ninject.Web.Mvc.FilterBindingSyntax пространство имен.

Мои сопоставления теперь выглядят так:

kernel.Bind<MyContext>()
  .ToSelf()
  .InRequestScope()
  .WithConstructorArgument("connectionString", context => MvcApplication.GetConnectionStringName);

kernel.Bind<IUnitOfWork>().To<UnitOfWork>();

// Service Layer.
kernel.Bind<ICustomerService>().To<CustomerService>();
kernel.Bind<IMessageService>().To<MessageService>();
kernel.Bind<IUserService>().To<UserService>();

// Repository Layer.
kernel.Bind<IRepository<Customer>>().To<GenericRepository<Customer>>();
kernel.Bind<IRepository<Message>>().To<GenericRepository<Message>>();
kernel.Bind<IRepository<User>>().To<GenericRepository<User>>();

// Attributes
kernel.BindFilter<AuthorizeWithTokenAttribute>(FilterScope.Controller, 0)
            .WhenControllerHas<AuthorizeWithTokenFilter>()
            .WithConstructorArgumentFromControllerAttribute<AuthorizeWithTokenFilter>("roles", attribute => attribute.Roles)
            .WithConstructorArgumentFromControllerAttribute<AuthorizeWithTokenFilter>("users", attribute => attribute.Users);
...