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.
Related
I have a project created from the ASP.NET Core Web Application template in VS. When run, the project creates a database to support the Identity package.
The Identity package is a Razor Class Library. I have scaffolded it and the models can be seen. The models are sub-classed from Microsoft.AspNetCore.Mvc.RazorPages.PageModel.
I am tracing the code to try and get a better understanding of how it all works. I am trying to find the path from the models to the physical database.
In the file appsettings.json, I see the connection string DefaultConnection pointing to the physical database.
In startup.cs, I see a reference to the connection string DefaultConnection:
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
After this, I lost the trail. I can't find the link from a model in code to a table in the database. What is the code needed to perform a query like select * from AspNetUsers?
As #Daniel Schmid suggested , you should firstly learn the Dependency injection in ASP.NET Core.
ASP.NET Core has an excellent Dependency Injection feature through which this framework provides you with an object of any class that you want. So you don’t have to manually create the class object in your code.
EF Core supports using DbContext with a dependency injection container. Your DbContext type can be added to the service container by using the AddDbContext<TContext> method.
Then you can use the instance like :
public class MyController
{
private readonly ApplicationDbContext _context;
public MyController(ApplicationDbContext context)
{
_context = context;
}
...
}
or using ServiceProvider directly, less common :
using (var context = serviceProvider.GetService<ApplicationDbContext>())
{
// do stuff
}
var options = serviceProvider.GetService<DbContextOptions<ApplicationDbContext>>();
And get users by directly querying the database :
var users = _context.Users.ToList();
Please also read this article .
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;
}
}
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 have existing .net 4 application which is based on object context.
Now I'm adding DbContext in to existing application by inheriting DbContext and call constructor method and pass the existing object context. i.e.
public class DemoModelEntitiesDbContext : DbContext
{
public DemoModelEntitiesDbContext():base(new DemoModelEntities(), dbContextOwnsObjectContext:true)
{
}
public DbSet<ELMAH_Error> ELMAH_Error { get; set; }
}
Than When I call,
using (DemoModelEntitiesDbContext context = new DemoModelEntitiesDbContext())
{
foreach (ELMAH_Error entity in context.ELMAH_Error.ToList())
{
Console.WriteLine(entity.ID);
}
}
I am getting following error message,
"The type 'ObjectContextDemo.ELMAH_Error' was not mapped. Check that the type has not been explicitly excluded by using the Ignore method or NotMappedAttribute data annotation. Verify that the type was defined as a class, is not primitive, nested or generic, and does not inherit from EntityObject."
I checked my existing entities are inheriting from EntityObject.
How to add DbContext in to existing application and not changing existing code?
You could cast to object context but then you gain nothing from DbContext if you 100% stick with existing code. but Ive done that with POCOs, not EntityObjects and can't confirm that it would work with entityobjects.
Otherwise it's not possible to do that without changes. DbContext does not support EntityObject. DbContext is designed for POCOs. Plus there are other code differences between DbContext and ObjectContext. You'd have to change even if you were already using POCOs. If you are using the EF designer, you'd have to start by using a different code gen template (ef5 DbContext template). But that will result in very different classes and plenty of changes to your EF calls in your app.
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();
}
}