Entity Framework Core DbContext and Dependency Injection - entity-framework

I'm building a service application using Web API, .Net Core and EntityFramework Core.
For configuring options in my DbContext I'm using these lines in "ConfigureServices" method in Startup.cs
var connection = #"Server=ISSQLDEV;Database=EventManagement;Trusted_Connection=True;";
services.AddDbContext<EMContext>(options => options.UseSqlServer(connection));
I know that if I add the context as a constructor parameter in the controller .Net will inject the context in the constructor.
But this is not the behavior I want. I don't want my web api to know anything about the dbcontext. I have a DataAccess Project with a repository class that handles all CRUD operations.
This means that I just want to say Repository.AddEvent(evt) in my controller and then repository knows how to handle that.
On the other hand, repository uses a simple dependency resolver to get the right "IDataAdapter" implementation. One of those implementations is SQLDataAdapter. This is the point I need my context.
How can I pass my context all the way to this point?

You can solve this by adding your dbcontext via constructor injection to your classes from your data access layer.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(o => o.UseSqlServer(myConnStr));
services.AddScoped<Repository>(); // 'scoped' in ASP.NET means "per HTTP request"
}
}
public class MvcController
{
private Repository repo;
public MvcController(Repository repo)
{
this.repo = repo;
}
[HttpPost]
public void SomeEndpoint()
{
this.repo.AddFoo(new Foo());
}
}
public class Repository
{
private DbContext db;
public Repository(ApplicationDbContext db)
{
this.db = db;
}
public void AddFoo(Foo obj)
{
this.db.Set<Foo>().Add(obj);
this.db.SaveChanges();
}
}
If you want to further customize how your DbContext is injected into your DI container, I suggest you look at what .AddDbContext is actually doing. See https://github.com/aspnet/EntityFramework/blob/1.0.0/src/Microsoft.EntityFrameworkCore/EntityFrameworkServiceCollectionExtensions.cs#L142-L158

Related

Can i Pass DbContext as interface or delegate

I am having two dbcontext so want to pass it though some function so I can switch between the two dbcontext or I have to change in all the api controller
public class AccountClassesController : ControllerBase
{
private readonly ApplicationDbContext _context;
public AccountClassesController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/AccountClasses
[HttpGet]
public async Task<ActionResult<IEnumerable<AccountClass>>> GetAccountClass()
{
return await _context.AccountClass.ToListAsync();
}
don't want to call the ApplicationDbContext from controller call it through some function or something
I have implemented database connection for postgresql and sqlserver now for them each one creates a different type of migration in code first, so had to create two dbcontext, now I want to be able to switch between dbcontext when I using postgresql or sql server
Yes, you can create interfaces and modify your ApplicationDbContext to implement.
interface
public interface IAccountClass {
Task<IEnumerable<AccountClass>> GetAccountClass();
}
public class AppDbContext: DbContext, IAccount {
/* implementing interface
*/
public Task<IEnumerable<AccountClass>> GetAccountClass() {
return this.AccountClass.ToListAsync();
}
}
Inject DbContext instance casting as interface in your controller:
public AccountClassesController(IAccountClass accountClass)
{
_accountClass = accountClass;
}
// GET: api/AccountClasses
[HttpGet]
public async Task<ActionResult<IEnumerable<AccountClass>>> GetAccountClass()
{
return await this._accountClass.GetAccountClass();
}
You must configure you dependency injection framework to inject a new ApplicationDbContext as IAccountClass.
You can check this answer here is it a good practice to pass an EF DbContext as delegate in services to attach all changes on it.
But if you application don't have any performance issues is fine even if you instance new context due EF is incredible fast managing and building it up.

Disposal and injecting DbContexts with .NET Core

I know that one way to use a context is via the using statement.
I use it like so within my controllers
[ApiController]
public class MyController : ControllerBase
{
[HttpPost]
public ActionResult PostActionHere(ActionRequestClass request)
{
using (var context = new MyEntityFrameworkContext())
{
....
// use context here
context.SaveChanges()
....
}
}
}
I would like to start injecting it into my controller. Mainly because I think it is easier to read and is more uniform with .NET Core dependency injection.
[ApiController]
public class MyController : ControllerBase
{
private MyEntityFrameworkContext _myDb;
public MyController(MyEntityFrameworkContext myDb)
{
_myDb = myDb;
}
[HttpPost]
public ActionResult PostActionHere(ActionRequestClass request)
{
....
// use context here
_myDb.SaveChanges()
....
}
}
Within my startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyEntityFrameworkContext >(options =>
options.UseSqlServer(Configuration.GetConnectionString("MyEntityFrameworkDatabase")));
}
What I am worried about is that injecting it I lose the disposal properties that come with the using statement. Is that true? Feel free to suggest alternate approaches.
injecting it I lose the disposal properties that come with the using statement. Is that true?
No:
The AddDbContext extension method registers DbContext types with a
scoped lifetime by default.
Configuring a DbContext
And when the scope (here the HttpRequest) ends, the Scoped Lifetime object will be Disposed.

How do I register DbContext EF Core in ServiceStack Core?

With EF Core, DbContext is registered as Scoped by EF service extension. This is desirable because DbContext is not thread-safe and therefore it should be created per request.
ServiceStack IOC treats any Scoped registration in Startup as singleton, which contradicts with the point above.
One possible solution is to not use EF Core's service extension, but that seems to bring a lot of boilerplate code and reduce maintainability. Is there any better way?
--
UPDATE
I'd like to provide sample code for clarity
I added a private Guid to the DbContext class so that I can tell whether we have the new instance.
public class BloggingContext : DbContext
{
private readonly Guid _instance;
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{
_instance = Guid.NewGuid();
}
public DbSet<Blog> Blogs { get; set; }
}
With .NET Core MVC, the controller code looks like
public class BlogsController : Controller
{
private readonly BloggingContext _context;
public BlogsController(BloggingContext context)
{
_context = context;
}
// skip for readability
}
For each request hitting the controller, the _instance inside BloggingContext returns an unique value. However, when using within a ServiceStack service, _instance always returns the same value.
public class BlogService : ServiceStack.Service
{
private readonly BloggingContext _context;
public BlogService(BloggingContext context)
{
_context = context;
}
// skip for readability
}
This behaviour is consistent with ServiceStack documentation about .NET Core Container Adapter that scoped dependencies registered in .NET Core Startup is singleton within ServiceStack. However, it is not desirable because we want DbContext to be created per request.
My solution is that I move the DbContext registration into AppHost code as below
public override void Configure(Container container)
{
container.AddScoped(c =>
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);
return new BloggingContext(optionsBuilder.Options);
});
}
This code works as I expect. Every instance of BloggingContext injected into my BlogService is now unique. However, I find myself unable to use any service collection extension which is very handy in .Net Core Startup anymore. For example, I want to use Entity Framework Unit Of Work and I couldn't call
services
.AddUnitOfWork<BloggingContext>();
Instead, I have to wire up all dependencies of that library myself like
public override void Configure(Container container)
{
container.AddScoped(c =>
{
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlServer(connection);
return new BloggingContext(optionsBuilder.Options);
});
container.AddScoped<IRepositoryFactory, UnitOfWork<BloggingContext>>();
container.AddScoped<IUnitOfWork, UnitOfWork<BloggingContext>>();
container.AddScoped<IUnitOfWork<BloggingContext>, UnitOfWork<BloggingContext>>();
}
You should be able to register it in .NET Core's IOC like any .NET Core App:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BloggingContext>(options =>
options.UseSqlite("Data Source=blog.db"));
}
Then reference like a normal dependency in your ServiceStack Services:
public class MyServices : Service
{
public BloggingContext BloggingContext { get; set; }
}
Which uses ServiceStack's .NET Core Container Adapter to resolve any dependencies not in ServiceStack's IOC, in .NET Core's IOC.

Dbcontext object transient in dotnet core

I'm creating an webapi application in dotnet core with entity framework. When I gone through documentation. I can use DI to inject the dbcontext object in dotnet core. But when I'm doing this the whole application using one dbcontext object. How do I make the dbcontext as transient? If any example is there it will really help me.
Please find my existing code below.
This is the code I wrote in ConfigureService
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataAccess.XXXXContext>(options => options.UseMySQL(Configuration["ConnectionStrings:DefaultConnection"]),ServiceLifetime.Transient);
}
This is the code i wrote in DBcontext class
public partial class XXXXContext : DbContext
{
private readonly Logger logger = LogManager.GetCurrentClassLogger();
public XXXXContext(DbContextOptions<XXXXContext> options) :base(options)
{
logger.Debug("XXXXContext created");
}
}
If you see i have written already Transient in the AddDbContext method.So everytime if it create object. My constructor should call. But i'm getting call only once.
I`ve already done this using a separated statement.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataAccess.XXXXContext>(options => options.UseMySQL(Configuration["ConnectionStrings:DefaultConnection"]));
services.AddTransient<DataAccess.XXXXContext>();
}

Generic Repository session management asp.net-mvc fluent nhibernate

I have gotten into a problem with my project. I am using a generic repository with structure map together with Fluent NHibernate. Everything works rather well, but when it comes to transactions and session management I have really no clue what to do. I have looked around for answers but I cant really find anything that fit my needs.
What I do in my application is that I let structure map instantiate a repository class when it gets a request for it, like so:
internal class RepositoryRegistry : Registry
{
public RepositoryRegistry()
{
For<IRepository<User>>().Use<Repository<User>>();
For<IRepository<Tasks>>().Use<Repository<Tasks>>();
}
}
internal class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
For<ISessionFactory>()
.Singleton()
.Use(() => new NHibernateSessionFactory().GetSessionFactory());
For<ISession>()
.Singleton()
.Use(x => x.GetInstance<ISessionFactory>().OpenSession());
}
}
public interface IRepository<T>
{
T GetById(int id);
void SaveOrUpdate(T entity);
IList<T> GetAll();
IQueryable<T> Linq();
void Add(T entity);
}
Edit: I have concluded what I need. I wan't to use the unit of work pattern along with structure map, but I also want to have some kind of repository wrapper which can be accessed through a unit of work.
Thanks,
James Ford
I think that you are looking for the Unit Of Work pattern, where the transaction life time is controlled by a unit of work that you inject into the Repostories/Services.
See this answer for a sample implementation of a UoW with NHibernate and StructureMap.
Edit:
Provided you have implemented a Unit of Work and a generic repository you would basically use them by:
1) Mapping them in structure map:
c.For(typeof(IRepository<>)).Use(typeof(Repository<>));
c.For<IUnitOfWork>().Use<UnitOfWork>();
2) Having the Controller accept a Repository(or a Service encapsulating the repository; this approach is often preferred) and the UnitOfWork:
public class MyController
{
public MyController(IRepository<MyEntity> repository, IUnitOfWork uow)
{
_repository = repository;
_unitOfWork = uow;
}
}
This of course also requires that you have created a custom ControllerFactory.
3) Using the Unit of Work and Repository in the controller action:
public ViewResult MyAction(MyEntity entity)
{
_repository.Save(entity);
_unitOfWork.Commit();
return View();
}