7

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 ;).

Matthijs Wessels
  • 6,530
  • 8
  • 60
  • 103
  • Just browsing questions and... What's this ObjectContext thing? – Tim Lovell-Smith Nov 20 '12 at 21:55
  • 1
    @TimLovell-Smith Conceptually similar as EF5's [DbContext](http://msdn.microsoft.com/en-us/library/system.data.entity.dbcontext(v=vs.103).aspx). "Represents a combination of the Unit-Of-Work and Repository patterns and enables you to query a database and group together changes that will then be written back to the store as a unit". For a more detailed explanation. I would suggest to search for articles on Entity Framework. – Matthijs Wessels Nov 21 '12 at 12:34

2 Answers2

3

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).

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • Yes, I know. I use let Ninject manage the life time of my context. I set it to `InRequestScope`. So Ninject will create and dispose the context per request. However, I think my MembershipProvider's lifetime spans multiple requests and responses. So I wonder what Ninject does with the lifetime the context it gives to the MembershipProvider. – Matthijs Wessels Mar 14 '11 at 08:42
  • Ninject does still the same - it disposes context at the end of the request so if you are right with behavior of MembershipProvider the next call in membership provider will throw the exception. – Ladislav Mrnka Mar 14 '11 at 08:46
  • Ah ok. I'll have to find a way to tell Ninject to keep a seperate context instance for the MembershipProvider or let it reinject the context for every request. Thanks for your answer(s). – Matthijs Wessels Mar 14 '11 at 08:58
  • i have a similar problem. in application_start i first setup my the dependency resolver with the ninject modules. (dbcontext with Bind().ToSelf().InRequestScope();) later in application_start i'm calling: IEmployeeService employeeService = DependencyResolver.Current.GetService(); EFZeiterfassungDataContextInitializer d = new EFZeiterfassungDataContextInitializer( Server.MapPath("~/Content/UserImages/"), employeeService); Database.SetInitializer(d); but then the first real (child) request won't work! how to solve? – toebens Jun 14 '11 at 07:55
  • @MatthijsWessels I'm having the same problem, found a solution? – ridermansb Dec 09 '11 at 15:49
  • @Riderman de Sousa Barbose, I don't remember my exact solution (cannot access the code anymore). However, as a result to this question, I asked this question: http://stackoverflow.com/questions/5298133/can-i-specify-the-scope-in-ninject-for-only-this-specific-situation. There I was pointed to some documentation which shows you how to specify more precisly when to inject what. That way you can let Ninject inject differently for different classes. – Matthijs Wessels Dec 12 '11 at 18:27
0

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.]

Tim Lovell-Smith
  • 15,310
  • 14
  • 76
  • 93