I decided to use this AddDbContext method to add and setup my context for my Entity Framework Core project.
services.AddDbContext<ExampleContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ExampleConnection")));
// https://stackoverflow.com/a/51970589/196526
I suppose this AddDbContext allow us to add a global context and it is possible to retrieve it later when required in my controller or service class. How can I use it?
Well, dotnet core has got dependency injection inbuilt now. The way you use it in your controllers, service or repository classes is as simple as through a constructor injection.
Example -
public class AccountRepository : IAccountRepository{
private readonly DbContext _exampleContext;
public AccountRepository(ExampleContext context){
_exampleContext = context;
}
}
Related
I'm trying to inject TenantProvider into DbContext
public class AppDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, long>
{
public int? _tenantId;
public ITenantProvider _tenantProvider;
public AppDbContext(
DbContextOptions<AppDbContext> options,
ITenantProvider tenantProvider
)
: base(options)
{
_tenantProvider = tenantProvider;
}
but I don't understand how to register it correctly - if I put the breakpoint in the constructor - tenantProvider is null.
The bit from Startup.cs
services.AddDbContext<AppDbContext>(options => AppDbContextOptionsBuilder.Get());
the next line is required to inject the DbContext into a controller or a service (if I add ServiceLifetime.Scoped as a second parameter to the method above - AddDbContext - the feature doesn't work):
services.AddScoped(p => new AppDbContext(AppDbContextOptionsBuilder.Get(), p.GetService<ITenantProvider>()));
(Entity Framework is a separate project in my solution)
When using .AddScoped method - we can pass TenantProvider into constructor by resolving it using .GetService method.
Does anyone have an idea of how to resolve TenantProvider in .AddDbContext method?
Additional info:
I was trying to replace ITenantProvider in the constructor of DbContext with IHttpContextAccessor - the latter is registered as singleton. But the acessor parameter is still null.
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
I don’t really understand what your AddScoped call is supposed to do. AddDbContext will already register the database context properly with the service collection. So when you resolve the context through dependency injection, additional dependencies will be automatically resolved.
So it should be enough to do this:
services.AddDbContext<AppDbContext>(options => …);
services.AddSingleton<ITenantProvider, TenantProvider>();
And then, you can depend on your AppDbContext using constructor injection, e.g. in your controllers.
Two notes though:
When configuring options, you should modify the passed options object. So you should not just return AppDbContextOptionsBuilder.Get() but instead use the passed options object and edit that.
You should really think about whether your database context having a dependency on your tenant provider is the right thing to do. As per SRP, your database should only do a single thing and that is provide database access.
Depending on how your tenant provider affects your database access, it might make more sense to move this dependency up one level into some service that uses both the database context and the tenant provider to query data in the right way.
I'm trying to get dependencies set up correctly in my Workflow application. It seems the best way to do this is using the Service Locator pattern that is provided by Workflow's WorkflowExtensions.
My workflow uses two repositories: IAssetRepository and ISenderRepository. Both have implementations using Entity Framework: EFAssetRepository, and EFSenderRepository, but I'd like both to use the same DbContext.
I'm having trouble getting both to use the same DbContext. I'm used to using IoC for dependency injection, so I thought I'd have to inject the DbContext into the EF repositories via their constructor, but this seems like it would be mixing the service locator and IoC pattern, and I couldn't find an easy way to achieve it, so I don't think this is the way forward.
I guess I need to chain the service locator calls? So that the constructor of my EF repositories do something like this:
public class EFAssetRepository
{
private MyEntities entities;
public EFAssetRepository()
{
this.entities = ActivityContext.GetExtension<MyEntities>();
}
}
Obviously the above won't work because the reference to ActivityContext is made up.
How can I achieve some form of dependency chain using the service locator pattern provided for WF?
Thanks,
Nick
EDIT
I've posted a workaround for my issue below, but I'm still not happy with it. I want the code activity to be able to call metadata.Require<>(), because it should be ignorant of how extensions are loaded, it should just expect that they are. As it is, my metadata.Require<> call will stop the workflow because the extension appears to not be loaded.
It seems one way to do this is by implementing IWorkflowInstanceExtension on an extension class, to turn it into a sort of composite extension. Using this method, I can solve my problem thus:
public class UnitOfWorkExtension : IWorkflowInstanceExtension, IUnitOfWork
{
private MyEntities entities = new MyEntities();
IEnumerable<object> IWorkflowInstanceExtension.GetAdditionalExtensions()
{
return new object[] { new EFAssetRepository(this.entities), new EFSenderRepository(this.entities) };
}
void IWorkflowInstanceExtension.SetInstance(WorkflowInstanceProxy instance) { }
public void SaveChanges()
{
this.entities.SaveChanges();
}
}
The biggest downside to doing it this way is that you can't call metadata.RequireExtension<IAssetRepository>() or metadata.RequireExtension<ISenderRepository>() in the CacheMetadata method of a CodeActivity, which is common practice. Instead, you must call metadata.RequireExtension<IUnitOfWork>(), but it is still fine to do context.GetExtension<IAssetRepository>() in the Execute() method of the CodeActivity. I imagine this is because the CacheMetadata method is called before any workflow instances are created, and if no workflow instances are created, the extension factory won't have been called, and therefore the additional extensions won't have been loaded into the WorkflowInstanceExtensionManager, so essentially, it won't know about the additional extensions until a workflow instance is created.
I've run into a bit of a problem with EF looking for the best practice for this problem:
public void TestEntityFramework_UOWImplementation()
{
using (UnitOfWorkInventory uow = new UnitOfWorkInventory())
{
IMaterialRepository repos = new MaterialRepository(uow);
Material mat = GetMaterial("Mikes Material", 1);
mat.CostPrice = 20;
repos.InsertOrUpdate(mat);
uow.Commit();
}
}
private Material GetMaterial(string sku, int clientId)
{
IMaterialRepository repos = new MaterialRepository(new UnitOfWorkInventory();
return repos.Find(sku, clientId);
}
In the TestEntityFramework_UOWImplementation() method, its fine, i call create a scope for my unit of work.. and create a repository inside it.
But when i want to getMaterials() as below.. I have no access to the unit of work or the repository, unless i actually pass it as a parameter! This is clearly not particularly nice.
How do people get around this problem??
Thanks in advance!
Neil
In your implementation you wont have access to the Unit of Work like that. What I do is use an IoC container and Dependency Injection to handle it. I have a WCF service that uses Unit of Work with a repository pattern against EF5.
You can read more about repository pattern, unit of work, and EF here but basically what I do is in the constructor of my service class I inject the Unit of Work like so:
private readonly IUnitOfWork uow;
public LoanService(IUnitOfWork unitOfWork)
{
uow = unitOfWork;
}
Then I can use uow.WhateverMethod in my repos anywhere in the service. I use Ninject to handle the injection of IUnitOfWork. Hope it helps you.
If anyone was looking for a way around this, I done something a bit different.
I used a Dependency Injection framework (StructureMap) to handle all DI, so everytime i instantiate a repository it will retrieve the DBContext from the Service Locator of StructureMap. I also make the dbcontext scope to be for the duration of the request from the webserver.
The advantage here being that everytime i retrieve or inject a DBContext, it will retrieve the same context for the duration of the request meaning i can use this across multiple methods and class! I pass the interface type as a generic param to the constructor, meaning that i can point the repo as different contexts. Helpful in applications where there are lots of dbcontexts.
Repo Constructor Eg:
public class PurchaseOrderRepository<TDbContext> : GenericRepository<PurchaseOrder>, IPurchaseOrderRepository<TDbContext> where TDbContext : DbContext
{
public PurchaseOrderRepository()
: base((TDbContext)ObjectFactory.GetInstance<TDbContext>())
{
}
}
Usage:
//resolves the request scope InventoryContext...
var pRepos = new PurchaseOrderRepository<IInventoryContext>();
and the structure map dependency looks like:
For<IInventoryContext>().HttpContextScoped().Use<InventoryContext>();
I made a small test function for creating an Entity Framework Code-First DbContext instance directly connected to a SQL CE 4.0 file but I really don't like the global state approach. Isn't there a better way to do this, without using DbDatabase static properties?
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Database;
using System.Data.SqlServerCe;
public class SqlCeDb
{
public static T Instance<T>() where T: DbContext, new()
{
DbDatabase.DefaultConnectionFactory = new SqlCeConnectionFactory("System.Data.SqlServerCe.4.0");
DbDatabase.SetInitializer<T>(new DropCreateDatabaseAlways<T>());
return new T();
}
}
Dependency Injection is what a lot of people are doing. You write a class that has a dependency on DbContext (i.e. it's a constructor argument or a property decorated as a dependency), and the IoC (Inversion of Control) container will give you an instance of it when the class is created. Every IoC container I've worked with has a way of registering a single instance (instead of creating a new instance every time).
Popular IoC Containers:
StructureMap
Unity
Ninject
There are others, but these are the ones I see used most often.
I have an ASP.Net MVC application and I am using StructureMap within MVC to glue the whole application together. There are some model classes that have heavyweight dependencies that are not used in all public methods, so I pass in an IContainer to the model constructor and use that to create the heavyweight dependencies on demand.
My question is where does the IContainer come from that is injected? Is it a reference to the one held centrally by MVC (it's logical parent) or is it a brand new one created and configured solely for this class?
The container injected into a constructor that has an IContainer parameter is the same container that is creating the instance of the class with the constructor.
Jeremy Miller has expressed this behaviour as "IContainer is injected into itself by default" in his blog post on NHibernate with StructureMap.
Couldn't you go with a factory model for creating those dependencies when needed in order to reduce your coupling to the container?
You could make your model take a Func as parameter and use SM's ability to autoinject those:
public class MyModel
{
Func<IHeavyDep> _heavyFactory;
public MyModel(Func<IHeavyDep> dependency)
{
_heavyFactory = dependency;
}
public void UsesHeavy()
{
var heavy = _heavyFactory();
heavy.DoMyStuff();
}
}