2015-02-27 2 views
1

Я пытаюсь использовать ASP.NET-котел для обработки моего проекта, и у меня есть одна серьезная проблема.ASP.NET Boilerplate - исключение «Объект ObjectContext исключено»

У меня есть 2 модели: Фото и комментарий:

public class Comment : Entity<int> 
{ 
    [DataType(DataType.MultilineText)] 
    public string Text { get; set; } 
    public string Author { get; set; } 

    public int ItemID { get; set; } 
    public virtual Item Item { get; set; } 
} 

public class Item : Entity<int> 
{ 
    public string Title { get; set; } 

    public string Description { get; set; } 

    public ItemSourceType SourceType { get; set; } 

    public byte[] PhotoBytes { get; set; } 

    public string Url { get; set; } 

    public virtual ICollection<Comment> Comments { get; set; } 

} 

Кроме того, я создал по умолчанию хранилища OOB на основе RepositoryBase<Item> и то же самое для Comment.

Проблема возникает, когда я пытаюсь получить позицию так:

public ActionResult Details(int? id) 
    { 
     if (id == null) 
     { 
      return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
     } 

     Item item = _repoItems.Get(id.Value); 
     if (item == null) 
     { 
      return HttpNotFound(); 
     } 
     return View(item); 
    } 

Когда я отладка этого кода я могу видеть, что item имеет это исключение в Comments собственности.

Я что-то упустил из ASP.NET Boilerplate или что?

Спасибо за помощь!

// Edit: Полное сообщение об исключении:

{"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."}

ответ

0

No. Проблема, скорее всего, в вашем хранилище, код которого вы, к сожалению, не включены. Если бы мне пришлось угадывать, я бы сказал, что вы используете что-то вроде следующего в этом методе репозитория:

using (var context = new ApplicationContext()) 
{ 
    // fetch something 
} 

Comments Ваше имущество является виртуальным, что означает, по умолчанию, Entity Framework будет ленивым нагрузка это, только на самом деле выдав запрос для этого в базу данных, как только вы попытаетесь получить доступ к свойству. Однако к этому моменту контекст был удален из-за того, что метод репозитория уже завершил свою работу, и ваш контекст был доступен только внутри блока using.

Существует несколько способов исправить это. Вы можете с нетерпением загружать комментарии внутри используемого блока:

return context.Items.Include("Comments").Find(id); 

Однако, это действительно просто заслоняет проблему. Лучшее, что вы можете сделать, это просто не использовать using. В идеале, ваш контекст должен быть создан один раз и только один раз для каждого запроса. Самый простой способ сделать это состоит в использовании контейнера инъекции зависимостей и добавить конструктор в репозиторий, который принимает контекст:

public class MyAwesomeRepository 
{ 
    private readonly ApplicationContext context; 

    public MyAwesomeRepository(ApplicationContext context) 
    { 
     this.context = context; 
    } 
} 

Конфигурация для DI контейнера будет варьироваться в зависимости от того, вы решите пойти с, но Как правило, вы хотите убедиться, что вы связываете свой контекстный класс с запросом области.

+0

Проблема в том, что моя реализация Репозитория - простая пустая реализация. Все методы (например, my Get (id)) - это OutOfBox, предоставляемые платформой ASP.NET Boilerplate. – Tomasz

+1

Ну, я бы посмотрел их документацию на использование инъекции зависимостей здесь: http://aspnetboilerplate.com/Pages/Documents/Dependency-Injection. Если они утверждают, что поддерживают DI, должен быть способ также ввести контекст, а затем ваш контейнер DI можно настроить таким образом, чтобы он всегда был одним и тем же экземпляром для области запроса. –

+0

эта структура использует его по умолчанию. Поэтому я не могу этого принудить. Для меня кажется, что в этой структуре есть некоторая ошибка внутри, или я использую ее неправильно :( – Tomasz

2

Я просто наткнулся на ту же проблему. Кажется, что реализация UnitOfWork создает и располагает новый DbContext для каждого «UnitOfWork»

Так, чтобы исправить эту конкретную проблему, попытаться придать «IUnitOfWorkManager» и вызвать

 

    public ActionResult Details(int? id) 
    { 
     if (id == null) 
     { 
      return new HttpStatusCodeResult(HttpStatusCode.BadRequest); 
     } 

     using(var uow = _unitOfWorkManager.Begin()) 
     { 
      try 
      { 
       Item item = _repoItems.Get(id.Value); 
       if (item == null) 
       { 
        return HttpNotFound(); 
       } 
       return View(item); 
      } 
      finally 
      { 
       uow.Complete() 
      }; 
     } 
    } 

, если это работает, рассмотрите возможность вызова «Begin()» в конструкторе вашего ApiController и «Complete()» в его переопределении «Dispose()». Надеюсь, что это поможет!

0

У меня была аналогичная проблема с ASP.NET Boilerplate и выяснили, что эта структура делает все это DI волшебство правильно, только если вы называете свои интерфейсы и классы в соответствии с их соглашениями об именах. Вы можете как-то это сделать вручную, но вам нужно углубиться в архитектуру ABP гораздо глубже, чем вы хотите.

Ссылка вывешено @ChrisPratt (см комментариев в своем ответе) говорит:

именование очень важно здесь. Например, вы можете изменить имя PersonAppService на MyPersonAppService или другое имя, которое содержит постфикс PersonAppService, поскольку IPersonAppService имеет этот постфикс. Но вы не можете назвать свой сервис как PeopleService. Если вы это сделаете, он автоматически не зарегистрирован для IPersonAppService (он зарегистрирован в каркасе DI, но с саморегистрацией, а не с интерфейсом), поэтому вам следует вручную зарегистрировать его, если хотите.

В моем случае у меня была служба под названием ProductService, реализующая интерфейс IProductAppService. Мне это не удалось с исключением ObjectDisposedException, пока я не переименовал мою службу в ProductAppService.

Я не думаю, что у ОП все еще есть эта проблема, но, надеюсь, это сэкономит несколько часов для людей, борющихся с ABP, таких как я. :-)

Смежные вопросы