我的自定义 MembershipProvider 中 Ninject 注入的 ObjectContext 的范围是什么(使用 Request 范围)?

发布于 2024-10-21 00:42:00 字数 2656 浏览 2 评论 0原文

我使用 Entity Framework 4 和 ASP.NET MVC 3。我创建了一个自定义成员资格提供程序,并使用 Ninject 将 EFAccountRepository 注入其中(将 IAccountRepository 绑定到 EFAccountRepository)。

该帐户存储库已注入一个 ObjectContext。我还在我的控制器中使用这个存储库(和其他存储库)。因此,当我将 IContext 绑定到 ObjectContext 时,我将范围设置为“每个请求”,以便 ObjectContext 仅存在于一个请求中并在存储库之间共享。

我在尝试登录时有时会收到以下错误:“ObjectContext 实例已被释放,无法再用于需要连接的操作。”

我想知道会员资格提供者多久被实例化一次。我通过使用 [Inject] 标记存储库属性并在全局的 Application_Start 函数中调用 Kernel.Inject 将存储库注入到成员资格提供程序中。 .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:一般来说,我总是愿意接受对我的代码的评论;)。

I use Entity Framework 4 and ASP.NET MVC 3. I made a custom membership provider and use Ninject to inject an EFAccountRepository into it (Bound IAccountRepository to EFAccountRepository).

This account repository has an ObjectContext injected into it. I also use this repository (and others) in my controllers. For this reason when I bound IContext to my ObjectContext, I set the scope to "per request" so the ObjectContext only lives in one request and is shared between the repositories.

I am sometimes get the following error when trying to log in:"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."

I wonder how often the membership provider gets instantiated. I injected the repository into the membership provider by marking the repository property with [Inject] and calling Kernel.Inject in the Application_Start function in the global.asax file.

If the provider gets instantiated more than once I would have to inject again I suppose. However, I don't get a null pointer exception, so I don't think that's it.

Update 1

Here's some code:

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: I'm always open to comments on my code in general ;).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

日久见人心 2024-10-28 00:42:00

异常表明您错误地处理了上下文。在某个地方您调用了context.Dispose(或者在using中拥有上下文),但之后您想再次使用上下文,这是不可能的,因为上下文已经被释放。如果您使用每个请求上下文,则必须在请求处理结束时仅处理一次上下文(当您确定没有代码将使用该上下文时)。

The exception says that you are incorrectly handling disposing of your context. Somewhere you call context.Dispose (or have context in using) but after that you want to use context again which is not possible because context is already disposed. If you are using per request context you must dispose context only once at the end of request processing (when you are sure that no code will use the context).

我爱人 2024-10-28 00:42:00

您没有指定 EFAccountRepository 绑定的范围,因此它默认为 .InTransientScope()。这意味着每次解析 IAccountRepository 时都会创建该对象的一个​​新实例 [请参阅 https ://github.com/ninject/ninject/wiki/Object-Scopes]。

瞬态范围对象

  1. 此外,只要没有对
  2. 的引用,它们就会自动被垃圾收集[Ninject 不会缓存它们],任何人都不会自动处置它们。

相比之下,您将 MyObjectContext 绑定到 IObjectContext .InRequestScope()。这意味着当您处于相同的 HTTP 请求处理操作中时,它将被重用。

此外,在 http 请求完成之前,请求范围对象

  1. 不会被垃圾收集
  2. ,如果它是 IDisposable,则可能会在 HTTP 请求完成后自动处置。 [不确定确切的时间,但从我看到的其他问题来看,我怀疑这取决于 Ninject 的版本]

现在,ObjectContext 是 IDisposable,因此可以合理地得出结论:

  • 存在对 IObjectContext 的对象引用,并且您正在使用 IObjectContext在创建它的 HTTP 请求之外。Ninject
  • 已自动处理它,因为 HTTP 请求已完成。

为了解决这个问题,您需要弄清楚为什么您的对象上下文对象引用能够存活这么长时间,并考虑消除长寿命......或删除其对短寿命(请求范围)对象的依赖。

[清楚地注意这个问题已经有一个公认的答案,但我认为公认的答案有点难以理解。]

You didn't specify a scope for your EFAccountRepository binding so it defaults to .InTransientScope(). This means a new instance of the object will be created each time you resolve the IAccountRepository [refer to https://github.com/ninject/ninject/wiki/Object-Scopes ].

Also, transient scope objects

  1. are automatically garbage collected as soon as there are no references to them [Ninject doesn't cache them]
  2. are not automatically disposed by anyone

In contrast, you bound MyObjectContext to IObjectContext .InRequestScope(). This means it will be reused when you are in the same HTTP request handling operation.

Also, a request scope object

  1. won't be garbage collected until your http request is done
  2. might be automatically disposed once the HTTP request is done, if it's IDisposable. [Not sure precisely when, but from other questions I have seen I suspect it depends on the version of Ninject]

Now, ObjectContext is IDisposable, so it seems reasonable to conclude that

  • an object reference to the IObjectContext exists, and you are using the IObjectContext outside of the HTTP request which it was created in.
  • Ninject has automatically disposed of it, since the HTTP request has completed.

In order to solve the issue, you need to figure out why your object context object reference is surviving so long, and consider either eliminating the long-livedness... or removing its dependency on short-lived (request-scoped) objects.

[note clearly the question already has an accepted answer, but I think the accepted answer was kind of hard to understand.]

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文