14

Hey I just recently learnt how to use extension methods and pretty excited to implement it in my current project.

My objective: I want to check whether an entry exists in my table in a helper class, since I'm going to use it in multiple controllers to be able to determine which navigation links to show in my navbar:enter image description here

My Issue: I don't know how to access my dbcontext in my static helper class. My dbcontext controller takes an argument I don't know how to pass in my static class. I think creating a new dbcontext would solve my scope issue explained below but I don't see how I can pass the optional argument to my constructor.

enter image description here

It is currently configured in the Startup.cs class. enter image description here

What I tried: Passing the ApplicationDbContext as an argument. This works for a single method call in my controller, but when calling multiple extension methods (To check which game accounts the user has) I get a ObjectDisposedException.

ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'ApplicationDbContext'.

From what I understand it is a scope issue where the first method call disposes the context when it's done and I'm trying to use the same context in the next call? What can I do to work around that?

I tried reading this link Cannot access a disposed of object in ASP.NET Core when injecting DbContext but it didn't help me since it requires the ApplicationBuilder which is in the Startup.cs class.

enter image description here

Solution Update I disposed the dbcontext after every method call because I put it into a variable. Instead, I call it directly on the passed context and it works:

enter image description here

5
  • 1
    How are you calling HasDota2Account()? Are you passing it a disposed DbContext? Where does _context come from? The error seems to indicate that it is, indeed, disposed before you call UpdateNavLinks(). So it would seem that you either shouldn't dispose it, or should be using a locally instantiated context in that method. Trying to share data context objects often leads to exactly this problem. Commented Sep 26, 2017 at 17:01
  • Also, in HasDota2Account db is the same object as context; when db is Disposed so will context be. If you try to use context after a call to HasDota2Account it give the same exception. Commented Sep 26, 2017 at 17:08
  • I am calling it from a controller like in my first image. context is a field on my controller, getting instantiated in the constructor. I don't know if it is disposed. I dont think I understand how to instantiate a local dbcontext _ since it takes the options argument I can't pass outside _of startup.cs Commented Sep 26, 2017 at 17:09
  • @simonatrcl Ah you are right. That was the issue and it works now. I'm gonna update my question with the answer, if you want to get credit you can write it in an answer and i will vote it :) Thanks David too! Commented Sep 26, 2017 at 17:13
  • 1
    @J.Kirk.: Excellent! Thanks, but not that worried about points, and those reading the question can see the comments easily enough. Cheers! Commented Sep 26, 2017 at 17:17

2 Answers 2

16

Yeah, so, although the extensions are new and shiny to you, that doesn't mean you should use them for everything. First, extensions should have a logical connection to the type they're operating on. For example, if you have a string, something like ToUpper() makes sense as an extension because it modifies and returns a string. Something like what you're trying to do: just using the value of the reference to return a completely foreign type is a violation of the extension pattern.

Second, an extension should not interact with something like a database. In particular here, the static nature of an extension is completely incompatible with the concept of a EF context object. The only way you could even get it to work is to actually new up a context each time the extension is called, inside the extension. That's both a great way to screw up the EF object tracking stuff and a great way to leak memory.

Long and short, don't do this.

If you're just trying to factor out this code, you have better options. For example, you can actually just add methods directly to your context.

public class ApplicationDbContext : DbContext
{
    ...

    public bool HasDota2Account(string id)
    {
        return Dota2Accounts.Any(m => m.ApplicationUserId == id);
    }
}

Then, in your controller, you can simply do:

var hasDota2Account = context.HasDota2Account(User.Identity.GetUserId());
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your explanation. Learning something new every day.
4

Never declare DbContext as static, it will cause all sorts of trouble, and not refresh the data, so you will be getting old data from a query. An option is to instantiate it inside the static method every time you use it, like this:

public static MyClass Example
{
        public static bool MyStaticMethod(long id)
        {
            MyDBContext db = new MyDBContext();
            //use db context now....
        }
}

2 Comments

Even better way is to instantiate the Context in a disposed scope, with the using statement: using var db = new MyDBContext();
how is this possible, this will throw an exception.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.