Is it bad to have a captive dependency on DbContext instance? - c#

Maybe this question has some explanation around but could not find the best solution to this:
I was reading this blog post from Mark Seemann about the captive dependencies and as far as I understand at the end of the post he comes to conclusion never use or at least try to avoid the captive dependencies otherwise there will be troubles (so far is OK). Here is another post from Autofac documentation.
They suggest using captive dependencies only by purpose (when you know what you are doing!). This made me think about a situation I have on my website. I have like 10 services, all of them rely on DbContext for database operations. I think they could easily be registered as InstancePerLifetimeScope if I fix the problem for DbContext not to hold it forever in memory attached to my services. (I am using Autofac in my case). So, I thought a good starting point would be to create all of these as per lifetime instances and the DbContext as instance per request. Then in my services, I would use something like that:
public class MyService
{
private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();
private MyModel GetMyModel() => Mapper.Map<MyModel>(_dbContext.MyTable.FirstOrDefault());
}
And then in my startup class I have:
builder.RegisterType<ApplicationDbContext>().As<IDbContext>().InstancePerRequest();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Does this pattern work correctly, I mean not keeping the dbContext forever attached to any service, so it will be disposed at the end of the request and if it works, is there any performance issue from this line:
private readonly IDbContext _dbContext = DependencyResolver.Current.GetService<IDbContext>();
compared to constructor injection(There are many invocations from dbContext to database so I am afraid to get IDbContext every time I want to use it because it might be resource consuming) ?
The reason I want dbContext to be instance per request and not instance per dependency is that I have implemented the unit of work pattern on top of the dbContext object.
A normal method in my controller would look like:
public ActionResult DoSth()
{
using(var unitOfWork = UnitOfWorkManager.NewUnitOfWork())
{
//do stuff
try
{
unitOfWork.Commit();
return View();
}
catch(Exception e)
{
unitOfWork.RollBack();
LoggerService.Log(e);
return View();
}
}
}
If this works fine then there is another issue I am concerned of. So, if I can make my services as instances per lifetime (except DbContext), is there any issue to apply async-await on every method inside of the services to make them non-blocking methods. I am asking this if there is any issue using async-await for the dbContext instance, so, for example, I would have something like this:
public async MyModel GetMyModel()
{
var result = //await on a new task which will use dbcontext instance here
return Mapper.Map<MyModel>(result);
}
Any advice or suggestion is much appreciated!

I'd approach the issue from a distance.
There are some architectural choices which can make your life easier. In web development it's practical to design your application to have stateless service layer (all the state is persisted in DB) and to fit the one HTTP request, one business operation principle (in other words one service method for one controller action).
I don't know how your architecture looks (there's not enough info in your post to determine) but chances are it meets the criteria I described above.
In this case it's easy to decide which component lifetime to choose: DbContext and service classes can be transient (InstancePerDependency in terminology of Autofac) or per request (InstancePerRequest) - it doesn't really matter. The point is that they have the same lifetime so the problem of captive dependencies doesn't arise at all.
Further implications of the above:
You can just use ctor injection in your service classes without worries. (Anyway, service locator pattern would be the last option after investigating lifetime control possibilities like lifetime scopes and IOwned<T>.)
EF itself implements the unit of work pattern via SaveChanges which is suitable most of the cases. Practically, you only need to implement an UoW over EF if its transaction handling doesn't meet your needs for some reason. These are rather special cases.
[...] is there any issue to apply async-await on every method inside of the
services to make them non-blocking methods.
If you apply the async-await pattern consistently (I mean all async operations are awaited) straight up to your controller actions (returning Task<ActionResult> instead of ActionResult), there'll be no issues. (However, keep in mind that in ASP.NET MVC 5 async support is not complete - async child actions are not supported.)

The answer, as always, is it depends... This configuration can work if:
Your scopes are created within the request boundary. Is your unit of work creating a scope?
You don't resolve any of your InstancePerLifetimeScope services before creating your scope. Otherwise they potentially live longer than they should if you create multiple scopes within the request.
I personally would just recommend making anything that depends on DbContext (either directly or indirectly) InstancePerRequest. Transient would work as well. You definitely want everything within one unit of work to be using the same DbContext. Otherwise, with Entity Framework's first level cache, you may have different services retrieving the same database record, but operating on different in-memory copies if they're not using the same DbContext. Last update would win in that case.
I would not reference your container in MyService, just constructor inject it. Container references in your domain or business logic should be used sparingly and only as a last resort.

Related

ASP.NET Core - Repository dependency injection fails on Singleton injection

I am using SoapCore to create a web service for my ASP.NET Core MVC application.
I am using Entity Framework Core and a simple Repository pattern to get my DB data.
I am injecting my repository classes via .AddSingleton() in my Startup.cs:
services.AddSingleton<IImportRepository, ImportRepository>();
services.AddSingleton<IWebService, WebService>();
Since the EF DbContext is scoped I get an error when calling my web service:
Cannot consume scoped service 'App.Data.ApplicationDbContext' from
singleton 'App._Repository.IImportRepository'.
When I use .AddScoped() instead, it works fine.
I've read injecting scoped dependencies via a controllers/classes constructor is bad practice, since it "falls back" to be a singleton or behaves like one.
I wonder if there is another way to make it work with singletons or if this has some major draw backs in the long term (about 100-200 users will use the site) when using scoped injections in my controllers via the ctor?
Simply put, your go-to lifetime should be "scoped". You should only use a singleton or transient lifetime if you have a good reason to do so. For a singleton, that's stuff like managing locks or holding data that needs to persist for the lifetime of the application, neither of which applies to the concept of a repository. Repositories should be entirely disposable. The point is to persist to the database or to some other store, so they should not contain any data in their own right that needs to be persisted.
Long and short, your best bet here is to simply make your repo(s) scoped, so you can directly inject the context. As far as constructor injection goes, I'm not sure where you got the idea that that's a bad practice. It's in fact how dependency injection works in most cases, so you can't really have one without the other.
If you absolutely need to have a singleton, then your only option is the service locator antipattern. For that, you will inject IServiceProvider:
public class MyRepo
{
private readonly IServiceProvider _serviceProvider;
public MyRepo(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
...
}
Then, each time you need the context (that's important), you'll need to do:
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<MyContext>();
// do something with context
}
Scoped objects cannot be injected in to singleton objects. Its simple as this, singletons are created only once when the app is starting and used by all the subsequent requests. Scoped objected are created during each request and disposed at the end of the request. So there is no way for the previously created single object to know about the scoped objects creating during each request. So using scoped objects is not possible in singletons. But the the other way around is possible.
injecting scoped dependencies via a controllers/classes constructor
I don't think its a bad practice at all. If not how are you planing to do unit testing?
Also its not right to make DB context singleton. You will face cashing issues/data anomalies in parallel and subsequent requests. In my opinion DB context has to be scoped and all the objects that uses the db-context has to be scoped all the way up.
So in you case, make all the objects ImportRepository, WebService and DB Context all scoped.
Cheers,

In MVC Controller, wanting async for returning EntityFramework CodeFirst data

I'm wanting to use the async/await pattern in my ASP.NET MVC controller. I'm getting the error
The ObjectContext instance has been disposed and can no longer be used
Ultimately, I'm wanting to cache my result but for now I think the first step is to just figure out how to work with EF and return with async/await
public class SpeakerController : Controller
{
public async Task<ActionResult> Index()
{
using (var context = new MultiTenantContext())
{
var speakersAll = await context.Speakers.ToListAsync();
return View("Index", speakersAll);
}
}
Solution Found:
private MultiTenantContext context = new MultiTenantContext();
public async Task<ActionResult> Index()
{
var speakersAll = await context.Speakers.ToListAsync();
return View("Index", speakersAll);
}
As I said in the comment below, pulling context out of the using causes it not to be disposed when the ToListAsync() actually executes.
You should avoid using Lazy Loading within web applications, because the goal is to minimize the response time of the HTTP request, and this is best achieved with fewer database requests. Especially with MVC and/or Web API, where you have very granular action methods, it should be possible in most cases to determine exactly what your data requirements are and include these in one or very few requests/queries. This puts less load on your database server and results in better performance for your web requests.
As for using statements and dbcontexts, you shouldn't be instantiating dbcontexts in your controller if you can help it. It's much better to inject them, and let your container determine how to manage their lifetime. Typically you will want to have exactly one dbcontext instance per request, which will be available for all (however few these may be) queries you need EF to make during the life of the request. If you're using StructureMap (my preference), you would achieve this with:
For<DbContext>.HybridHttpOrThreadLocalScoped().Use<MyContext>();
(Note that this syntax is updated with StructureMap 4)
If you're not sure whether you trust my recommendation, consider that EF7 is taking this recommendation further and making it difficult to work with EF7 and MVC 6 without using dependency injection, in an effort to drive developers toward doing the right thing (falling into "the pit of success" as it were). See this EF7/MVC6 tutorial in the official asp.net docs for an example (http://docs.asp.net/projects/mvc/en/latest/tutorials/mvc-with-entity-framework.html).
Excerpt:
Notice that we don’t set any value for Logger and BookContext. The
dependency injection (DI) subsystem automatically sets these
properties at runtime. DI also handles the object lifetimes, so you
don’t need to call Dispose. For more information, see Dependency
Injection.
If you're lazy-loading Speaker.Sessions, your Context is long gone by the time it's used, hence the issue.
Try this instead:
await context.Speakers.Include(x => x.Sessions).ToListAsync();
to ensure Sessions is loaded before your Context goes out of scope.
You can use a different pattern; e.g. allowing the Context to live longer, but personally I think very-short-lived Contexts within using() blocks, as you've done, is best, if you don't need some sort of Unit of Work pattern.
While this isn't the issue here - you also shouldn't mix lazy-loading with async-await in EF: Why Does Await Not Appear to Prevent Second Operation on EF Context

Entity Framework Unit of Work lifetime

I am trying to learn entity framework and related patterns. While searching I came across the site: http://www.asp.net/mvc...
I checked the patterns, but I could not understand one point. According to my investigations, dbcontex lifetime should be very little because it has in-memory object model and these changes should be persisted to database as fast as possible. If not, there will be conflicts in multi-user scenarios.
When I look at the above tutorial, I see that for every controller there is only one uow defined. I wonder if this means as long as I am on a one page of the site doing CRUD operations I am using the same dbcontext. But shouldn't its lifetime shorter? For example for every action one uow could be defined.
Could somebody please explain the lifetime of uow?
Defining a DbContext as a private class variable vs. defining it as a local variable shouldn't make any difference.
Every time an HTTP request is created, the controller is initialized (as well as any of it's class variables) and the action is called. Instances of ontrollers will not persist between different requests, nor will any instances of DbContext.
Check out this article about why you don't have to worry about the lifetime of a DbContext.
EDIT
I realized a caveat to this answer a few days after I posted it, and I would have felt guilty had I not updated it.
The above statement is true if every action uses your DbContext. If only a few of your actions use it, however, you might be better off using a locally-scoped DbContext instead. This will prevent unnecessary creation of a DbContext class variable any time you call an action that doesn't require usage of it. Will this make your code more efficient? Yes - but insignificantly so - and you'll have to instantiate a DbContext every time you want to use it, which will result in slightly messier code than just having one class-variable at the top.
Each action being called is a new instance of the controller. Just set a breakpoint in your controller constructor and you will see that it is called everytime you make a request to any action on the controller.
Generally a DBContext is scoped per web request in a web application. So if you inject a DBContext into your controller that generally will give you what you need.
In the example given, the controller is taking the responsibility of creating the instance of the DbContext and doing the dispose. A better practice is to let IoC container to take the responsibility of the lifetime control for the instance of DbContext, and implement constructor injection to inject the DbContext into the MVC/WebApi controller.
As for WCF service, my preference is to indicate the below attribute
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
for the service, and also specify the lifetime of the DbContext so that only one DbContext instance would be create per call.
you may need to have some lifetime management if DI will be implemented for WCF service or MVC/WebApi.
Ref: https://msdn.microsoft.com/en-us/library/dn178463(v=pandp.30).aspx#_Lifetime_Management
This post is also highly recommended for your question.
One DbContext per web request... why?

Singleton in Asp.NET application

In my app, I create a dbcontext for every call and dependency inject it through Ninject.
I've been thinking of creating a singleton class (ContextManager - BaseController would set the context on every request) to make the context available from everywhere, thus allowing all the services to share the same context. This would furthermore make it easy to, for example, disable proxy creating etc. seeing as the context is managed from one place only.
However, seeing as the object is a singleton object the context would be overwritten per each request which won't work for me (I don't want multiple requests sharing a single context).
What would be the best way to do this (how to preferably a single context ONLY in request scope)?
What you're describing is not a Singleton, but a Request-Scoped object. ASP.NET MVC has strong support for dependency injection, and you should allow your DI bindings to determine where the context comes from, rather than instantiating it yourself. Ninject has binding syntax to support this. I think it goes:
Bind<DataContext>().ToSelf().InRequestScope();
As long as you are using good Dependency-Injection patterns consistently, this should cause the same DataContext instance to be passed to every dependency you have within the same request.
The advantage to relying on Dependency Injection for construction of your context is that if you want to change details like disabling change tracking on the context, you can simply change your DI binding to use a custom method or factory, and the rest of your code doesn't have to change at all.
Singleton is not the right approach here, but this is not too hard to implement, by simply instantiating your data context in your controller and injecting it into your service classes, e.g.:
public class SomeController {
private DataContext _context;
private SomeService _service;
public SomeController() {
_context = ...InstantiateContext();
_service = new SomeService(_context);
}
}
This also allows makes it relatively simple to inject your context into your controller if you wish to unit test that. You can also relatively simply dispose of your context by coding this into the dispose method of the controller class (as noted above, a base controller class may be useful).
A singleton carries some persistent state - this is anathema to unit testing and will ultimately give you difficulties in your code.

Lazy Dependency Injection

I have a project where the Ninject is used as IoC container. My concern is that a lot of classes have such kind of constructors:
[Inject]
public HomeController(
UserManager userManager, RoleManager roleManager, BlahblahManager blahblahManager) {
_userManager = userManager;
_roleManager = roleManager;
_blahblahManager = blahblahManager;
}
What if I don't want to have all instances of these classes at once?
The way, when all this classes are wrapped by Lazy<T> and passed to constructor is not exactly what I need. The T instances are not created yet, but Lazy<T> instances are already stored in memory.
My colleague is suggesting me to use Factory pattern to have control over all instantiations, but I'm not sure that IoC have such great design bug.
Is there a workaround for this situation or IoC really have such big defect in it's design? Maybe I should use another IoC container?
Any suggestions?
Seems to me that you are doing premature optimization: don't do it.
The constructors of your services should do nothing more than storing the dependencies that it takes in private fields. In that case the creation of such an object is really light weight. Don't forget that object creation in .NET is really fast. In most cases, from a performance perspective, it just doesn't matter whether those dependencies get injected or not. Especially when comparing to the amount of objects the rest of your application (and the frameworks you use) are spitting out. The real costs is when you start using web services, databases or the file system (or I/O in general), because they cause a much bigger delay.
If the creation is really expensive, you should normally hide the creation behind a Virtual Proxy instead of injecting a Lazy<T> in every consumer, since this allows common application code to stay oblivious to the fact that there is a mechanism to delay the creation (both your application code and test code are becoming more complex when you do this).
Chapter 8 of Dependency Injection: Principle, Practices, Patterns contains a more detailed discussion about lazy and Virtual Proxies.
However, a Lazy<T> just consumes 20 bytes of memory (and another 24 bytes for its wrapped Func<T>, assuming a 32bit process), and the creation of a Lazy<T> instance is practically free. So there is no need to worry about this, except when you’re in an environment with really tight memory constraints.
And if memory consumption is a problem, try registering services with a lifetime that is bigger than transient. You could do a per request, per web request, or singleton. I would even say that when you're in an environment where creating new objects is a problem, you should probably only use singleton services (but it's unlikely that you're working on such an environment, since you're building a web app).
Do note that Ninject is one of the slower DI libraries for .NET. If that's troubling you, switch to a faster container. Some containers have performance that is near newing up object graphs by hand.
but by all means, do profile this, many developers switch DI libraries for the wrong reasons.
Do note that the use of Lazy<T> as dependency is a leaky abstraction (a violation of the Dependency Inversion Principle). Please read this answer for more information.
Steven is correct in saying that this looks like premature optimization. The construction of these object is very fast and is usually never the bottleneck.
However using Lazy to express a dependency you don't need right away is a common pattern in Dependency Injection frameworks. Actofac is one such container that has built in support for various wrapping types. I'm sure there is also an extension for Ninject as well, maybe take a look at this one, Ninject Lazy.
You can also inject into an action method with the syntax below. (I'm not sure exactly what version this was introduced).
Constructor is best practice, but I had to do this once deliberately when I had a service that was doing some expensive initialization - accidentally in fact - but it wasn't discovered for a while and it was just easiest to move it to the one method that did need it.
This can make for cleaner code if you only need to access a service from one action method - but bear in mind if you inject it to the method you'll have to pass it around everywhere because it will no longer be on this. Definitely don't go assigning to this.service in an action method - that's horrible.
public IActionResult About([FromServices] IDateTime dateTime)
{
ViewData["Message"] = "Currently on the server the time is " + dateTime.Now;
return View();
}
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection?view=aspnetcore-2.2#action-injection-with-fromservices

Categories