How am I supposed to inject my MyDbContext
into my database service layer MyService
?
Startup.cs
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"])); services.AddMvc(); }
MyDbContext.cs
public partial class MyDbContext : DbContext { public virtual DbSet<User> User { get; set; } public MyDbContext(DbContextOptions<MyDbContext> options) :base(options) { } }
appsettings.json
{ "Logging": { "IncludeScopes": false, "LogLevel": { "Default": "Debug", "System": "Information", "Microsoft": "Information" } }, "ConnectionStrings": { "DefaultConnection": "Server=MyServer;Database=MyDatabase;user id=MyUser;password=MyPassword;" } }
MyService.cs
public class MyService { public User GetUser(string username) { // Should i remove this call and get the reference from the injection somehow? MyDbContext db_context = new MyDbContext(optionsBuilder.Options); using (db_context) { var users = from u in db_context.User where u.WindowsLogin == username select u; if (users.Count() == 1) { return users.First(); } return null; } } }
In my GetUser
method, I know I am supposed to be using my injected MyDbContext
here but I am not quite sure how to fetch it. Which piece of the puzzle am I missing?
You can define a RepositoryConnection class in App. Data that acts as a wrapper to the Context and removes the need to reference EF in App. Web . If you are using an IoC Container you can control the lifetime of the RepositoryConnection class to ensure that all instances of Repository get the same Context.
The AddDbContext extension method registers DbContext types with a scoped lifetime by default.
EF and EF Core DbContext types implement IDisposable . As such, best practice programming suggests that you should wrap them in a using() block (or new C# 8 using statement). Unfortunately, doing this, at least in web apps, is generally a bad idea.
You don't have to include the dbcontext yourself, ASP.NET core dependency injection service will do this for you. You have just to declare your services and your database context in your startup class, and put the dbcontext you need in your service's constructor :
Create the DBContext class: Set up dependency injection by adding options.UseSqlServer () to ConfigureServices () in Startup.cs: Make DBContext accessible from within each controller by adding it to the controller class and setting it through the constructor:
Microsoft recommends using the Repository pattern to further abstract the database access layer, in which case we would use the interface IProductsDb in the Dependency Injection instead of the concrete class ProductsDb.
Make DBContext accessible from within each controller by adding it to the controller class and setting it through the constructor:
You don't have to include the dbcontext yourself, ASP.NET core dependency injection service will do this for you.
You have just to declare your services and your database context in your startup class, and put the dbcontext you need in your service's constructor :
Startup.cs (your have to choose the service lifetime you want, here it's a scoped service, once per request):
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<MyDbContext>(options => options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"])); services.AddMvc(); services.AddScoped<IMyService, MyService>(); }
Your service class:
public class MyService : IMyService { private readonly MyDbContext _context; public MyService(MyDbContext ctx){ _context = ctx; } public User GetUser(string username) { var users = from u in _context.User where u.WindowsLogin == username select u; if (users.Count() == 1) { return users.First(); } return null; } } public interface IMyService { User GetUser(string username); }
In your controller, you have to declare the services (or the database context) you need to use in the same way :
public class TestController : Controller { private readonly IMyService _myService; public TestController(IMyService serv) { _myService = serv; } public IActionResult Test() { return _myService.MyMethod(); // No need to instanciate your service here } }
Note about the controller : you don't have to add them in your startup class like you do with your database context or your services. Just implement their constructor.
If you need more information about the .NET Core depencency injection, the official documentation is clear and very complete : https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
NB: In the startup.cs, the AddScoped line is an option. Your can choose the lifetime you want for your service. There is the different lifetimes you can choose :
Transient
Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.
Scoped
Scoped lifetime services are created once per request.
Singleton
Singleton lifetime services are created the first time they are requested (or when ConfigureServices is run if you specify an instance there) and then every subsequent request will use the same instance.
Above taken from: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
Note: It's not the question here but your GetUser data query looks like a little strange to me. If your count()==1 goal is to check the unicity of the user, the good way is to add a unicity constraint in your database. If count()==1 goal is to check you have data to avoid a object null reference exception, you can use .FirstOrDefault(), it will manage this for you. You can simplify this method :
public User GetUser(string username) => (from u in _context.User where u.WindowsLogin == username select u).FirstOrDefault();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With