I've read a couple of articles about creating a generic repository in Entity Framework. In every article the ObjectContext is passed as an argument to the constructor like this:
public Repository(ObjectContext context)
{
_context = context;
}
In a web application the preferred way to handle ObjectContext lifestyle is per web request. This means that these repositories must also have lifestyle per web request, if used in in a web context. This spreads to services using repositories and further on if we stick to constructor injection...
I think the ObjectContext life cycle should be handled outside the repositories, for example in a HttpModule. I would also like to handle repositories as singletons instead, and then ObjectContext can't be injected in the constructor. Another mechanism for getting the ObjectContext into the repository must be used, like an ObjectContextFactory.
Whats the downside of handling the repositories with a singleton lifestyle?
One issue with repositories being singletons, as with any other objects, is that determining what dependencies the repository has becomes more difficult. When you require that a context is passed in the constructor that is a clear declaration of a dependency on the ObjectContext class. If you were to use a static factory to get a reference to an object context then it would be necessary to see the implementation of the repository to know how it uses the factory.
A common way to achieve what you're looking for, namely the ability to manage the scope of the ObjectContext class outside of the repository is by using a dependency injection library, such as Autofac. You can register the ObjectContext class such that a new instance is created for every HTTP request. Then if you also register the repository class, when a repository is requested the dependency injection container will attempt to get a reference to the ObjectContext dependency. Since only one instance of ObjectContext will be created per HTTP request multiple repositories within that scope will receive the same instance. The Autofac page has example of integrating with ASP.NET that you can look at.
Related
Some of you may be familiar with the DbContextScope library, which allows you to nest scopes within your code, and allow those scopes to share a common DbContext. The idea is that the DbContext gets managed for you by the scope library, and instead of calling SaveChanges() on the context, you call SaveChanges() on the scope. The magic happens because the scope will only save all the changes on the context at it's outer-most call of SaveChanges(), so all the nested operations performed on the DbContext get saved in a single transaction at the outer scope-level.
Now that DI is a first-class citizen in .NET Core, it appears that scopes have also become an important part of the .NET Core ecosystem, and the EF Core team, knowing this, has implemented scoping based on allowing DbContexts being injected by the DI system, and (I assume) allowing change saving to happen at scope-levels and not directly on the DbContexts in some way.
So my question are these:
What is the appropriate way to share a DbContext via a scope, allowing the SaveChanges() be managed at the scope level and not the code-level that typically calls SaveChanges() on the DbContext?
Are there new mechanisms in EF Core that manage this for you, just like DbContextScope did this for you as a 3rd party library?
Save me the drama, and spare me the lectures on why you think UOW needs to be implemented in addition to EF. K thnxs bye.
UPDATE: As of 6/2020 there are several forks of DbContextScope that work with EF Core 3.
UPDATE: Forks of this project can be viewed here: https://github.com/mehdime/DbContextScope/network
There are several EF Core 3 versions... I haven't tried any yet, but there you go.
Since Entity Framework 5.0.0, there is IDbContextFactory<TDbContext> that lets you control the creation and disposal (!!) of your DbContexts.
Instead of registering your DbContext with AddDbContext or AddDbContextPool, you can now use AddDbContextFactory or AddPooledDbContextFactory, respectively.
Note that this feature takes care of one of the problems that DbContextScope solves, not all of them. As for what the other problems and solutions are, refer to Mehdi's original post. It is long but excellent.
DbContext sharing is built-in to the Dependency Injection design for EF.
The DI container will generate a scoped DbContext instance for each web request. You can share the DbContext instance from any component that has a dependency on it, and call SaveChanges(), or manage transactions in your outer controller.
I'm working on an ASP.net Web API application with Autofac and Entity Framework.
I've been breaking apart different my service classes into smaller classes in order to make my code more testable and to make my code more SOLID.
I'm using Autofac to inject Entity Framework DbContext into my various helper classes. This becomes problematic because if I use entities queried from DbContext in two different helper classes, I get an error when Entity Framework tries to produce a query.
The error says that Entity Framework cannot produce a query with entities from two different instances of DbContext.
Clearly, the solution is that I need to configure Autofac so that the same instance of DbContext is injected into each of the helper classes, but I'm afraid that if I try to do this, I may get concurrency issues when this application gets deployed to a production environment and many people use it at once.
How do I configure Autofac so that when a request hits my application, my API helper classes all get the same instance of DbContext, but I don't have concurrency issues across multiple requests?
An alternative to the action filter recommended by the Autofac documentation (https://autofaccn.readthedocs.io/en/latest/faq/per-request-scope.html#no-per-request-filter-dependencies-in-web-api) see: "No Per-Request Filter Dependencies in Web API" and manually going to the DependencyResolver for others:
You could have a look at the Medhime DbContextScope unit of work provider. (https://www.nuget.org/packages/EntityFramework.DbContextScope/) compiled for both EF6 and EF Core.
The injected dependencies for your classes becomes a DbContextScopeFactory for the top level, and an AmbientDbContextLocator for your services. These don't "break" with Web API's limitation on the request lifetime scope. The ContextScopeFactory would be initialized once and supply the DbContext, while the locators will be fed that single instance.
It may be worth having a look at if managing context references across services and an API action prove clunky.
My layout
project.web (.net core 2.1 web api)
Some binding models (for post/put requests) and resource models for GET requests
Controllers.
I only call interfaces from (x.api) which are resolved to x.core services.
No validation or anything. This happens inside the core layer
I've setup a few things like automapper and swagger, that are not relevant for my question.
project.api (class lib)
only contains interfaces for .core and .store projects (services, repositories and domain models)
project.core (class lib)
two kinds of services
1) Services which call the repository services (interfaces). But validate the data before calling the repo service.
2) Services that will have to execute long term stuff (IE: scanning folders, handling file information, ...). I actually created HostedServices for these as a folder could easily contain thousands of files.
project.store (class lib)
Wrapper services for my storage (Only contains helper methods so I don't have to write the same queries a hundred times.)
Problem / question
At this time I have registered all of my services and repositories as singletons in public void ConfigureServices(IServiceCollection services)
because I was using a different storage (nosql, litedb) before refactoring code to EF (sqllite)
Now the problem is that I want to register my DbContext as scoped (by default)
But my repositories (singleton) depend on dbcontext. Which means I will have to make these scoped as well. I'm ok with this, as these are only wrapper services, so I don't have to write the same queries all the time.
But some other services, that will need access to my data are singletons, and I cannot register these as scoped. Contains some data that needs to be the same for every request, and some collections and long running jobs.
I can think of two solutions
The first solution is to make a dependency to IServiceScopeFactory in my repository and use something like using (var scope = ServiceScopeFactory.CreateScope()) { scope.ServiceProvider.GetService(typeof(MyDbContext))... }
this way I can remove the dependency from my repository wrapper, but this doesn't sound clean to me.
The other solution is to register all of my services that only handle database stuff as scoped. (IE customerSservice in core only does validations and calls customerRepository) I remove dependencies from my remaining singleton services.
In those singletons, instead of depending on the customersService, I could use a rest call with restsharp or something similar
Just like how I would consume them from my windows client applications and web client apps.
I don't actually like either. But perheps someone can give me some advice or thoughts?
Well, the two options you laid out are in fact your only two options. The first is the service locator antipattern, which as the name implies, is something you should avoid. However, when you are dealing with singleton-scoped objects needing access to objects in other scopes, there is no other way.
The only other option is to reduce the scope of your services from singletons, such that you can then inject the context directly. Not everything necessarily needs to be a singleton. Generally, if you need to utilize something like DbContext, there's a strong argument to be made that your object should not be singleton-scope in the first place. If you need it to be singleton-scoped, that's most likely an indication that the class is either doing too much or is otherwise brittle.
Every once in a while, I'm encountering the following exception in my ASP.NET/MVC5/WebAPI2/EF6/MSSQL application:
System.InvalidOperationException: The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.
I've traced this to my authorization code, which is a derivative of AuthorizeAttribute and instantiating its own DbContext to verify that my Web API consumer's API key is valid (the error occurs when trying to access the database).
The AuthorizeAttribute in turn decorates controllers which are derivatives of my BaseController, which also instantiates a DbContext for controller work.
After trying to troubleshoot this for days and reading this and this I suspect that creating the two DbContext instances per request is the problem. However, I'm not quite sure how I can use only a single instance for this work. My controller code currently nicely instantiates the DbContext upon its own creation and disposes of it transparently when the controller itself disposes. The AuthorizeAttribute is completely independent from all this and creates the context on demand for its own purposes.
Any patterns/ideas how to preserve/reuse the same DbContext for both units of work?
I had exactly the same issue when starting out with a base application using Entity Framework 6 for the first time.
The best solution for me was to ensure only one DbContext instance during the request life cycle using Autofac (with MVC integration) and Autofac's InstancePerRequest lifetime scope.
If you're interested in going down the dependency injection route (which I'd strongly advise) I would recommend familiarizing yourself with Autofac - and for more information on your particular issue check out davidbitton's answer here - it will get you on the right track.
I'm using strongly typed views and autofac for Dependency Injection under ASP.NET MVC2 and I'm trying to get a common dynamic header via dependency injection. I.e. i want this to happen without the view having to be away of this content even existing and i was hoping to avoid static discovery of the container and manual resolution, but I can't find a way to easily inject the master or a partial view included in the master via either ctor or property injection.
I can't imagine this is an uncommon task, but all I can find in terms of methods is Controller subclassing to stuff data into untyped ViewData, subclassing ViewModels to stuff master data into the model, or static resolution, all of which I'd prefer not to use. What am I overlooking?
EDIT: As has been pointed out DI into master pages is fighting the framework. So my question is badly framed: I don't really care about DI into master pages, but I have a dynamic element in the chrome of the site, i.e. the master page. Providing it with a model shouldn't be the responsibility of each controller using that master, as it is request context, not controller context specific. I fully admit that injection directly into master pages is inappropriate. If i could register a separate master controller to be invoked in addition, that would be even better. Is that possible? Given this task of providing the master with a model independent of the controller, what is the framework appropriate approach? Or does shared content in MVC require that each Controller has to know about that content?
You could use child actions.
Controller:
public class MyHeaderController: Controller
{
private readony IRepository _repository;
public MyHeaderController(IRepository repository)
{
_repository = repository;
}
[ChildActionOnly]
public ActionResult Index()
{
var model = _repository.GetSomeModel();
return PartialView(model);
}
}
And somewhere in your master page include it:
<div><%= Html.Action("Index", "MyHeader") %></div>
Your problems stem from confusing the term Dependency Injection, and fighting how the ASP.NET MVC framework works.
Also, you are using the term Dependency Injection in the wrong context. You are trying to use a hammer as a chisel.
MasterPages and views in ASP.NET MVC are intended to be used as templates. As stated in the other answer, child actions will solve your problem.
For future reference:
Dependency Injection refers to a means to configure what parameters to inject into class constructors, and have this done for you automatically, overriding some of the frameworks defaults. The purpose for this is to decouple components, so that they become more reusable, more testable, more unitary, amongst other good things.
DI refers to, and solves, a code issue, not a UI issue.
What you are trying to do is simply not possible. Ie, inject via constructors and properties a "dependency" into a masterpage. Again, MasterPages are intended by ASP.NET MVC to be used as just templates. They have no code behind class to instantiate via a constructor that would allow dependencies to be injected into it.
In other words, you are fighting the framework, which means you don't understand it.
If this sounds like nitpicking, I think this has to be highlighted as otherwise, you are confusing yourself and others who read this thread in the future.