Inject DbContextOptions vs DbContext in a repository EF Core - asp.net-core

I have the StudentDbContext
public class StudentDbContext : DbContext
{
public StudentDbContext()
{
}
public StudentDbContext(DbContextOptions<StudentDbContext> options)
: base(options)
{
}
public virtual DbSet<Students> Students{ get; set; }
}
and then I have a repository and I try to understand what is the difference if I inject the StudentDbContext vs inject DbContextOptions
Inject the DbContextOptions
class StudentRepository : IStudentRepository
{
private readonly DbContextOptions<StudentDbContext> _context;
public StudentRepository(DbContextOptions<StudentDbContext> context)
{
_context = context;
}
}
Inject StudentDbContext
class StudentRepository : IStudentRepository
{
private readonly StudentDbContext _context;
public StudentRepository(StudentDbContext context)
{
_context = context;
}
}
Are there any advantages or disadvantages in each case?

DbContextOptions class is used to create the options to be used by a DbContext. It configures the database (and other options) to be used for the database context. DbContext class contains DbSet properties for each entity in the model.
If you try to use DbContextOptions in a repository you will have no access to any model since it doesn't have them.

DbContextOptions and DbContextOptions<TContext> have different use cases.
You need to inject DbContextOptions (generic or not) in subtypes of DbContext.
The DbContextOptions instance will contain the options that you have configured in the Startup class:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextFactory<ConcreateDbContext>(
options => options.UseSqlServer(#"Server=(localdb)\mssqllocaldb;Database=Test")
);
}
If your DbContext implementation is not supposed to be inherited from, you will inject in your ConcreateDbContext the generic version of options type DbContextOptions<ConcreateDbContext>, and this ensures that the correct options for the specific DbContext subtype are resolved from dependency injection. You can also, mark your ConcreateDbContext as sealed, as the class is not designed to be inherited from.
public sealed class ConcreateDbContext: DbContext
{
public ConcreateDbContext(DbContextOptions<ConcreateDbContext> contextOptions)
: base(contextOptions)
{
}
}
In case that you want to have a DbContext that is intended to be inherited from, you are supposed to expose a protected constructor which will take as a parameter the non-generic version of DbContextOptions.
public class BaseDbContext: DbContext
{
protected BaseDbContext(DbContextOptions contextOptions)
: base(contextOptions)
{
}
}
In case you want to have a DbContext that is intended to be both instantiated and inherited from, you will have two constructors, one taking the generic, and one the non-generic version of DbContextOptions.
And when you want to interact with the data in your database, you will inject the concrete DbContext implementation (in your case StudentDbContext).

Related

How can I get HttpContext inside an abstract class in ASPNETCore

I have the following Repository:
public class TestRepository : WebCaller<Data>, ITestRepository
{
string connString = this.GetConnectionString();
.... some code here
}
In my Repository I can do Dependency Injection to the constructor without a problem.
In my abstract class WebCaller I need to get access to HttpContext somehow, I was reading that you can Inject IHttpContextAccessor to get access to the context, but because this is an Abstract class, that also lives outside the Web project, I can't have a constructor.
I was trying to do this:
public abstract class WebCaller<T> : WebRequest, IDisposable
{
//[Inject]
public ITestRepository TestRepo
{
get
{
return this.HttpContext.RequestServices.GetRequiredService<ITestRepository >();
}
}
..... more code here
}
Was trying to use Inject attribute but was reading that is no longer available, so should be other way to pass HttContext to the abstract class.
You can have a constructor on your abstract class. Just inject IHttpContextAccessor to it. Then any derived class will also take IHttpContextAccessor and pass it to its base constructor (your abstract class constructor). You can make the abstract class constructor protected.
Like:
public abstract class WebCaller<T> : WebRequest, IDisposable
{
protected WebCaller(IHttpContextAccessor contextAccessor)
{
}
}
public class TestRepository : WebCaller<Data>, ITestRepository
{
public TestRepository(IHttpContextAccessor contextAccessor) : base(contextAccessor)
{
}
string connString = this.GetConnectionString();
.... some code here
}

How to simplify asp.net core dependency injection

Since asp.net core DI provides only constructor injection and method injection.
If there's a lot of services to inject.
Instead of writing a lot inside constructor and change constructors frequently.
Can I just use some kind of provider so that I can get the services everywhere inside controller?
Instead of :
public class HomeController : BaseController
{
public HomeController(
IEmailService emailService,
ISMSService smsService,
ILogService logService,
IProductRepository _productRepository)
:base(emailService,smsService,logService)
{
}
public IActionResult()
{
_emailService.SendSomething();
}
...
}
public class BaseController : Controller
{
protected readonly IEmailService _emailService;
protected readonly ISMSService _smsService;
protected readonly ILogService _logService;
public BaseController(
IEmailService emailService,
ISMSService smsService,
ILogService logService)
{
_emailService = emailService;
_smsService = smsService;
_logService = logService;
}
}
With some kind of provider like:
public class HomeController : BaseController
{
public HomeController(IDIServiceProvider provider)
:base(provider)
{
}
public IActionResult()
{
_provider.GetScopedService<IEmailService>().SendSomething();
}
...
}
public class BaseController : Controller
{
protected readonly IDIServiceProvider _provider;
public BaseController(IDIServiceProvider provider)
{
_provider = provider;
}
}
So that I don't have to change all controller's constructors every time when BaseController's constructor changes and simplify all controller's constructors.
You can inject IServiceProvider to your controller and get your dependencies from that but it's not DI anymore and it's called Service Locator pattern.
public class HomeController
{
private readonly ITestService _testService;
public HomeController(IServiceProvider serviceProvider)
{
_testService = serviceProvider.GetRequiredService<ITestService>();
}
}
It's recommended to not use Service Locator because :
1- Your controller dependencies are not obvious with the first look.
2- It's harder to write unit tests for that.
3- Your service now needs one more dependency (IServiceProvider).
Use Service Locator pattern only when it needed like injecting your dependencies to FilterAttributes or ValidationAttributes. ( You can use ServiceFilter for this situations too. )

How to resolve EF7 current database context in ASP NET 5 out of the controller?

I want to get one context per request in ASP NET 5/EF 7 app for use it in some methods (not in controller).
Unfortunately I did not find the answer in the documentation
ASP.NET vNext template and examples aspnet/MusicStore
You may use some methods for achieving this purpose.
Using .AddDbContext<ApplicationDbContext>(); method for registering ApplicationDbContext in Dependency Injection system (in ConfigureServices() method), leads to the fact that it registered as Scoped dependence(or in another words "per request"). Thereby you only need get it from Dependency Injection system.
Add your dbContext as parameter of constructor method your class (in which you will use dbContext). Then you have to get this class using Dependency Injection system, e.g added it as parameter of controller's constructor.
public class HabitsController : Controller
{
public HabitsController(HabitService habitService)
{
}
}
public class HabitService
{
private GetHabitsContext _dbContext;
public HabitService(GetHabitsContext dbContext)
{
_dbContext = dbContext;
}
}
But if you don't want to use constructor injection for getting context, you can get necessary dependenses using GetService() method (but you need in ServiceProvider instance for that, in example below, i'am getting it through constructor injection too).
using Microsoft.Framework.DependencyInjection; // for beta 6 and below
using Microsoft.Extensions.DependencyInjection; // for beta 7 and above
public class HabitService
{
private IServiceProvider _serviceProvider;
public HabitService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public GetHabit()
{
var dbcontext = _serviceProvider.GetService<ApplicationDbContext>();
}
}
In first method, we can get HabitService through GetService() method too (not through the constructor injection).
using Microsoft.Framework.DependencyInjection; // for beta 6 and below
using Microsoft.Extensions.DependencyInjection; // for beta 7 and above
public class HabitsController : Controller
{
public HabitsController(IServiceProvider serviceProvider)
{
var habitService= serviceProvider.GetService<HabitService>();
}
}
public class HabitService
{
private GetHabitsContext _dbContext;
public HabitService(GetHabitsContext dbContext)
{
_dbContext = dbContext;
}
}
Thanks Tseng for remark:
I should be noted, that it's a pretty bad practice to inject the container into your objects. The container should only be referenced from the composition root and certain type of factories (which are implemented on application level, and not in the domain/business layer)
dbContext in HabitsController and _dbContext in HabitService are different contexts!
I checked, this is the same context.

Injecting my UnitOfWork into my Repository Constructor

Im very new but on a quest to learn nhibernate and DI with structuremap so am making an app to test everything out.
I am having some problems injecting my unitofwork into my base repository. I create a unitofwork on every request then either commit or rollback at the end. But when tryin to inject into my base repository its always null when i go to use it in my methods. More specifically i get this error: "Object reference not set to an instance of an object". Any ideas what im doing wrong and if this is the correct route i should be going?
Many thanks in advance.
Base Repository:
public abstract class Repository<T> : IRepository<T>
{
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
UnitOfWork = _unitOfWork;
}
public Repository() {}
public void Save(T obj)
{
_unitOfWork.CurrentSession.Save(obj);
}
}
StructureMap registry thats set in my application_start:
public class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<UnitOfWork>();
For<ISession>().HybridHttpOrThreadLocalScoped().Use(context => context.GetInstance<ISessionFactory>().OpenSession());
For<ISessionFactory>().Singleton().Use(NHibernateSessionFactory.GetSessionFactory());
}
}
Update:
The baserepository is inherited by specific repositorys ie ArticleRepository then im injecting that into my aspx pages on application_start. Then my aspx page inherits a basepage where the buildUp takes place. And i access the repository like this:
public IArticleRepository ArticleRepo { get; set; }
public void SaveThing()
{
ArticleRepo.Save(object);
}
This gets called on application_start:
public class Bootstrapper
{
public static void BootStrap()
{
ObjectFactory.Configure(x =>
{
x.AddRegistry<NHibernateRegistry>();
x.AddRegistry<WebRegistry>();
});
}
}
And in the webregistry:
For<IArticleRepository>().Use<ArticleRepository>();
There is a good chance your ArticleRepository doesn't have a constructor that takes an IUnitOfWork as a parameter make sure you have the following
public class ArticleRepository : Repository<Article>
{
public ArticleRepository(IUnitOfWork unitOfWork) : base(unitOfWork)
{
}
...
}
Remember Strcuture map uses the greediest constructor on the class that it instantiates. Since your abstract repository class will never be instantiated it will not use its constructors. I would also suggest not having any default constructors if your classes need to have their dependencies injected that way. Less chance for errors that way.
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
UnitOfWork = _unitOfWork;
}
I think you mean to write
public readonly IUnitOfWork _unitOfWork;
public Repository(IUnitOfWork UnitOfWork)
{
_unitOfWork = UnitOfWork;
}
You were assigning the local variable to the parameter instead of the parameter to the local variable.
Edit: Also you should write your parameter with a lowercase U 'unitOfWork' instead of 'UnitOfWork'

Entity framework DbContext in wcf per call instance mode

I have a repository like this
public abstract class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected DbContext _dbContext;
public BaseRepository(DbContext dbContext)
{
_dbContext = dbContext;
}
public TEntity GetByKey(object keyValue)
{
// todo
}
}
and a concrete repository like this
public CustomerRepository : BaseRepository<Customer> , ICustomerRepository
{
public CustomerRepository(DbContext context) : base (context) { }
public Customer FindCustomerByKey(string key)
{
_dbContext.Set<Customer>().Find(key);
}
}
I have wcf service like this
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class CustomerSatisfactionService : ICustomerSatisfactionService
{
private ICustomerRepository _customerRepository;
private IHelpDeskRepository _helpdeskRepository;
public AccountService(ICustomerRepository customerRepository,IHelpdeskRepository helpdeskRepository)
{
_customerRepository = customerRepository;
_helpdeskRepository = helpdeskRepository;
}
public void DoSomethingUsingBothRepositories()
{
// start unit of work
// _customerRepository.DoSomething();
// _helpdeskRepository.DoSomething();
// commit unit of work
}
}
and I am using StructureMap for injecting DbContext instances like this
For<DbContext>().Use(() => new MyApplicationContext());
My problem is when a client calls the service, a new CustomerSatisfactionService instance is created, hence new instances of CustomerRepository and HelpdeskRepository are created but with different DbContexts.
I want to implement the unit of work pattern, but in the DoSomethingWithBothRepositories method, the two repositories have different DbContexts.
Is there any way to tell structure map to spin up a DbContext instance on a per call basis?
You must specify lifecycle for your DbContext so that only one instance is created per call. StructureMap doesn't contain build-in lifecycle management for per call WCF but you can find one implementation on this blog.
You need to implement UnitOfWork pattern so that same context is shared amongst entities. Take a look at http://blogs.msdn.com/b/adonet/archive/2009/06/16/using-repository-and-unit-of-work-patterns-with-entity-framework-4-0.aspx for a way to implement it.
I don't know if you need/want StructureMap to control the instantiation of dbcontext, have a look at this reply, UoW and UoW Factory setup dbcontext for the calls that need to be made in the repository.
EF ObjectContext, Service and Repository - Managing context lifetime.