Какова область действия моего Ininject ObjectContext в моем пользовательском MembershipProvider (с использованием области запроса)? - PullRequest
7 голосов
/ 10 марта 2011

Я использую Entity Framework 4 и ASP.NET MVC 3. Я создал пользовательский поставщик членства и использую Ninject для внедрения в него EFAccountRepository (привязанный IAccountRepository к EFAccountRepository).

В этом хранилище учетной записи вставлен ObjectContext. Я также использую этот репозиторий (и другие) в моих контроллерах. По этой причине, когда я связал IContext с моим ObjectContext, я установил область действия «на запрос», чтобы ObjectContext жил только в одном запросе и был разделен между репозиториями.

Иногда я получаю следующую ошибку при попытке войти в систему: «Экземпляр ObjectContext был удален и больше не может использоваться для операций, требующих подключения.»

Интересно, как часто создается поставщик членства. Я внедрил репозиторий в провайдер членства, пометив свойство репозитория [Inject] и вызвав Kernel.Inject в функции Application_Start в файле global.asax.

Если провайдер получит инстанцию ​​более одного раза, мне придется вводить снова, я полагаю. Тем не менее, я не получаю исключение нулевого указателя, поэтому я не думаю, что это все.

Обновление 1

Вот код:

MyNinjectModule.cs

    public override void Load()
    {
        Bind<IMyContext>().To<MyObjectContext>().InRequestScope();
        // put bindings here
        Bind<IAccountRepository>().To<EFAccountRepository>
    }

Global.asax

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        var kernel = new StandardKernel(new MyNinjectModule());
        ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(kernel));
        kernel.Inject(Membership.Provider);
    }

MyMembershipProvider.cs

    [Inject]
    public IAccountRepository accountRepository { get; set; }

    public override bool ValidateUser(string username, string password)
    {
        // I get the exception here.
        return (from a in accountRepository.Accounts
                where a.UserName == username 
                 && a.Password == password
                select true).SingleOrDefault();
    }

EFAccountRepository.cs

    private readonly IMyContext context;

    public EFAccountRepository(IMyContext context)
    {
        this.context = context;
    }

    public IQueryable<Account> Accounts
    {
        get { return context.Accounts; }
    }

MyObjectContext.cs

public class MyObjectContext : ObjectContext, IMyContext
{
    public IObjectSet<Account> Accounts { get; private set; }

    public FlorenceObjectContext()
        : this("name=DomainModelContainer")
    {
    }

    public FlorenceObjectContext(string connectionString)
        : base(connectionString, "DomainModelContainer")
    {
        Accounts = CreateObjectSet<Account>();
    }
}

PS: я всегда открыт для комментариев к моему коду вообще;).

Ответы [ 2 ]

3 голосов
/ 11 марта 2011

Исключение говорит о том, что вы неправильно обрабатываете удаление своего контекста. Где-то вы звоните context.Dispose (или имеете контекст в using), но после этого вы хотите снова использовать контекст, что невозможно, поскольку контекст уже удален. Если вы используете контекст для каждого запроса, вы должны утилизировать контекст только один раз в конце обработки запроса (когда вы уверены, что ни один код не будет использовать этот контекст).

0 голосов
/ 27 ноября 2012

Вы не указали область для привязки EFAccountRepository, поэтому по умолчанию используется .InTransientScope (). Это означает, что новый экземпляр объекта будет создаваться при каждом разрешении IAccountRepository [см. https://github.com/ninject/ninject/wiki/Object-Scopes].

Кроме того, временные объекты области видимости

  1. автоматически удаляется мусором, как только на них нет ссылок [Ninject не кэширует их]
  2. автоматически не утилизируется никем

Напротив, вы связали MyObjectContext с IObjectContext .InRequestScope (). Это означает, что он будет использоваться повторно, когда вы выполняете ту же операцию обработки HTTP-запроса.

Также объект области запроса

  1. не будет собирать мусор, пока ваш http-запрос не будет выполнен
  2. может автоматически удаляться после выполнения HTTP-запроса, если он может быть IDisposable. [Не знаю точно, когда, но из других вопросов, которые я видел, я подозреваю, что это зависит от версии Ninject]

Теперь ObjectContext является IDisposable, поэтому кажется разумным сделать вывод, что

  • существует ссылка на объект IObjectContext, и вы используете IObjectContext вне HTTP-запроса, в котором он был создан.
  • Ninject автоматически удалил его, поскольку HTTP-запрос завершен.

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

[обратите внимание, что на вопрос уже есть принятый ответ, но я думаю, что принятый ответ было довольно трудно понять.]

...