I have an existing WebAPI project that resolves the database connection string to use and then uses Unity for dependency injection of a repository into APIControllers. I would like to pass an instance of my DBContext to EFContextProvider instead of it creating another (1 per request).
What would be the ramifications if we added a public contructor that took a DBContext as assigned it to _context in the EFContextProvider class?
Related
Trying to teach myself MVC. I am using database first in the MVC pattern.
I have scaffolded the controller and views. Yet when I run it I get this error?
I am not sure what to do since this was generated via automatically.
InvalidOperationException: Unable to resolve service for type 'OPPS_APP11_7_2020.Models.ENT_PLANNERContext' while attempting to activate 'OPPS_APP11_7_2020.Controllers.ProductsController'.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, bool isDefaultParameterRequired)
It seems like there is Database Context in the ProductController constructor, while it is not registered using Dependency inject (DI) in startup.cs in configureServices.
If you are not familiar with Dependency inject in ASP.Net core, I suggest you have a read about it, check MS Docs
If you are using Entity framework (EF) there are special way to add their context in DI. check this Configuring a DbContext in EF Core, Ms Docs
After using the Scaffold-DbContext command to generate the relate models and the dbcontext based on your existing database, you have to register the DbContext to dependency injection in the Startup's ConfigureServices method.
Try to add the following code:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
//register the dbcontext.
services.AddDbContext<ENT_PLANNERContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
You could add the connection string in the appsetting.json file:
"ConnectionStrings": {
"DefaultConnection": "{your database connection string}"
}
Reference:
https://www.entityframeworktutorial.net/efcore/create-model-for-existing-database-in-ef-core.aspx
I have a HomeController and a Referrence of a type-class.If I create a new object of the class it works fine for me. But I dont want to create new object in the Controller instead I want to pass a referrence of the class through the HomwController's Constructor.Here is my code. I need to implement DI here.
//private readonly UnitOfWork<Student> _unitOfWork = new UnitOfWork<Student>();
private readonly UnitOfWork<Student> _unitOfWork;
//TODO ??
public HomeController(UnitOfWork<Student> unitOfWork)
{
_unitOfWork = unitOfWork;
}
public ActionResult Index()
{
return View(_unitOfWork.GenericRepository.GetAll());
}
Any help?
First, if you want to use dependency injection, you'll have to go through a third party dependency injection container - NInject or Unity for example among many others (or building your own if you are looking for some challenge).
Second, your HomeController should take an abstract unit of work type (interface or abstract class) as a parameter. You are actually using a concrete type in your HomeController constructor which is not how things should work in a dependency injection world (when using "Constructor Injection", your dependency container is in charge of providing the concrete implementation for the abstraction, based on container configuration).
Third your UnitOfWork<Student> does not make a lot of sense. A Repository<Student> would make some sense, but a Unit Of Work is not working on a single "Type" but rather on a "collection" of different data sets (a unit of work is potentially working on a collection of repositories). What would make sense here is to specify a parameter IUnitOfWork unitOfWork in your HomeController constructor, and configure your depency container to pass in a concrete UnitOfWork object on which you can get your Repository<Student> do operations on it in your action method (and potentially on other repositories accessed from the UnitOfWork object) and then Commit all modifcations by calling the associated method on the UnitOfWork object.
You should make some searches arround NInject use with ASP.NET MVC3 and also take a look at EntityFramework if you are dealing with UnitOfWork and Repository patterns (and if data is backed by a DB).
EDIT
In reaction to your comment dealing with (IUnitOfWork<Student> and IUnitOfWork<Course>).
As I said before, it does not make a lot of sense :
A UnitOfWork can be grossly seen as a "container" of repositories, giving access to these repositories and coordinating actions (like commiting all the changes) on these repositories. You should rather have an abstract non generic type IUnitOfWork, providing access to generic repositories such as IRepository<Student> or IRepository<Course>, and also containing a Commit method which would commit to DB (or file, or memory or whatever the unitofwork/repository implementation is targeting to persist data).
This way instead of injecting an IRepository<Student> and/or IRepository<Course> in your controller constructor (or if your controller needs to work on 10 different repositories, well, pass 10 parameters :S), you just accept a single parameter of abstract type IUnitOfWork (the concrete instance being injected by the DI container), and then any action method can work on any set of repository by getting them from the UnitOfWork, and once it has done all the changes, it can call Commit on the unitOfWork which will take care of comming all the modifications that have been done in the repository.
That's the theory and the general idea.
Now more specifically about DI in ASP.NET MVC, the more common way (there are other ways) of "plumbing" the DI container is to create a class inheriting from IDependencyResolver making use of the DI container to resolve types, and in Application_Start call DependencyResolver.SetResolver whith an instance of this class.
This way, when ASP.NET MVC is asked to create a controller (end user request), it will go through this depency resolver to ask for an instance of the controller, and this dependency resolver will turn to the DI container to create an instance of the controller by taking care of all needed injection.
You should take a look on the website / forums of your specific DI container as they all show ways to plumb it with ASP.NET MVC.
This is just a very high overview, there are a lot of tricky details, but that's the gross idea.
EDIT2
Just posted an article (my first one) on my blog to explain how to correctly use the Repository and UnitOfWork patterns in an ASP.NET MVC project.
http://codefizzle.wordpress.com/2012/07/26/correct-use-of-repository-and-unit-of-work-patterns-in-asp-net-mvc/
Are you talking ASP.NET MVC ?
I have been working with Ninject for some time now, and am very happy with it! Take a look at the sample app in this repository to get an idea on how to use it in ASP.NET MVC 3:
https://github.com/ninject/ninject.web.mvc/tree/master/mvc3
To expand a bit on the reply, here's a code snippet from where I set up the Ninject bindings
kernel.Bind(typeof(IUnitOfWork<>).To(typeof(UnitOfWork<>));
And my controller:
public class MyController : Controller {
private readonly IUnitOfWork<Student> uowStudent;
public MyController(IUnitOfWork<Student> uowStudent) {
this.uowStudent = uowStudent;
}
}
Then all you need to do, is make sure any arguments in the constructor for the UnitOfWork class are also bound in the kernel.
We are building a multi-tenant database application utilizing ASP.NET MVC, the Entity Framework Code First, and the soon to be released SQL Azure Federations. Our repository accepts a DbContext as a constructor argument that is injected using Ninject. The problem is that the DbContext has an int constructor argument to specify the account id that will be used for the requests made with that context. Something like this:
public class DatabaseContext : DbContext
{
public DatabaseContext(int accountId)
{
// Code here to ensure we only work with data associated with
// the account identified by accountId
}
}
The value for the account id will be stored in a Session variable. The question is how do we get Ninject to inject a value from Session into the constructor when it creates a new instance of DatabaseContext?
Or is there another way I should go about injecting the account id into the DbContext?
There are a few ways. I like using the .ToMethod approach.
Bind<DatabaseContext>().ToMethod(
c => new DatabaseContext((int)HttpContext.Current.Session["Acct"]);
Though to solve this particular problem, I've found it better to create an ISessionManager service that has session-based data on it. Anything that wants, e.g., an accountId would have this service injected into the constructor, and access its AccountId property when it needs an account ID.
I'm running into issues with multiple contexts and the main solution that comes up is to share the context between repositories however I haven't found a good example on how to do this.
For reference, I'm using an MVC Web App to connect to my data layer. I'd like to have one context per user request (assuming this is correct).
Thanks,
Edit -
This is my solution with the help of BrokenGlass's links and the following SO Question:
I essentially implemented the Unit Of Work pattern and Dependency Injection. I should have mentioned in addition to using MVC, I'm also using Ninject.
In a given repository constructor (see the link below for Unit Of Work pattern details):
public class PersonRepository : IPersonRepository
{
private readonly MyContext _context;
public PersonRepository(IUnitOfWork unitOfWork)
{
if (unitOfWork == null)
throw new ArgumentNullException("unitOfWork");
_context = unitOfWork as MyContext;
}
//...
}
In my MVC App in the NinjectMVC3 class (the key being the InRequestScope() method):
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IUnitOfWork>().To<MyContext>().InRequestScope();
kernel.Bind<IPersonRepository>().To<PersonRepository>();
//...
}
Your repository layer should provide a unit of work that represents a single request and uses a context object that is then used on all individual repositories that are needed to fulfill the request.
For HTTP / web apps specifically you can cache the db context in the HttpContext.Current.Items which stores shared data for each HTTP request. Also check out this similar SO thread for details: attaching linq to sql datacontext to httpcontext in business layer
My answer to C#/EF and the Repository Pattern: Where to put the ObjectContext in a solution with multiple repositories? provides an implementation of a RepositoryProvider that works with a single instance of an ObjectContext. You could use the code the same way, with a LINQ-to-SQL DataContext instead of an EF ObjectContext. The benefit of the RepositoryProvider over Ninject, is that the RepositoryProvider implementation is not bound to a specific DI framework, and can itself be configured in any DI framework.
In addition, you can manage creation and scoping of the DataContext to either a Thread or a WebRequest (such as in #BrokenGlass's answer with HttpContext.Current.Items) by using the DataContextFactory class from here.
I'm trying to inject a repository to a custom membership provider with ninject in MVC 3.
In MembershipProvider I have tried the following:
[Inject]
public ICustomerRepository _customerRepository{ get; set; }
And
[Inject]
public TUMembershipProvider(ICustomerRepository customerRepository)
{
_customerRepository = customerRepository;
}
In my ninject module i tried the following:
Bind<MembershipProvider>().ToConstant(Membership.Provider);
None of the above works.
When i use(in global.asa)
kernel.Inject(Membership.Provider);
together with
[Inject]
public ICustomerRepository _customerRepository{ get; set; }
it works, but i have no life cycle management and this will cause a "ISession is open" error from NHibernate, because the ISession is InRequestScope and the repository is not.
You could use the approach #Remo Gloor outlines in his blog post on provider injection. It involves 3 steps:
Add [Inject]s to any properties on your provider you need injected (although the pattern he shows -- creating a very simple class whose only function is to be a receptable for property injection and forwards any requests to a real class implemented using constructor injection -- is well worth following)
public class MyMembershipProvider : SqlMembershipProvider
{
[Inject]
public SpecialUserProvider SpecialUserProvider { get;set;}
...
Create an initializer wrapper that implements IHttpModule which pulls the provider in, triggering its creation:-
public class ProviderInitializationHttpModule : IHttpModule
{
public ProviderInitializationHttpModule(MembershipProvider membershipProvider)
{
}
...
Register the IHttpModule in your RegisterServices :-
kernel.Bind<IHttpModule>().To<ProviderInitializationHttpModule>();
there is no 4; Ninject does the rest - bootstrapping all registered IHttpModules including the one you added) during the startup sequence.
(Don't forget to read the comments on the blog post re lifetimes etc.)
Finally, if you're looking for something completely braindead direct that solves it neatly, try this #Remo Gloor answer instead
PS a great writeup on the whole mess is Provider is not a Pattern by #Mark Seemann. (and the oboligatory plug for his excellent book:- Dependency injection in .NET which will have you figuring this stuff out comfortably from first principles)
i had this problem
a custom membership, role and profile provider in another project from MVC using repository, when ever i call the provider the injected repository was null.
tried to call kernel.Inject(Membership.Provider); in the NinjectWebCommon method registerServices(IKernel kernel) but got the exception
The result is always null, because asp.net has it's own static property for membership.which is membership.provider. and this instance is not part of instance ninject management.
so use on PostApplicationStartMethod
here is the soloution by cipto add to NinjectWebCommon the attrbute and method :
[assembly: WebActivator.PreApplicationStartMethod(typeof(WebApp.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivator.PostApplicationStartMethod(typeof(WebApp.App_Start.NinjectWebCommon), "RegisterMembership")]
[assembly: WebActivator.ApplicationShutdownMethodAttribute(typeof(WebApp.App_Start.NinjectWebCommon), "Stop")]
public static void RegisterMembership()
{
bootstrapper.Kernel.Inject(Membership.Provider);
}
The problem is that the whole Membership infrastructure is a "native" .NET code (System.Web.Security) that does not know about MVC and about the DI container used by MVC.
The static call to Membership.Provider returns the membership provider based on the configuration, however, the specified provider type is instantiated with a simple Activator.CreateInstance call. Hence, the dependency injection has no chance to kick in and set your repository dependency on the result. If you explicitly setup the returned instance with Ninject it can work, because you explicitly gave Ninject the object to set the dependencies. Even in this case it can only work with property injection and not with constructor injection, because the instance is created by the membership configuration previously.
To summarize: you cannot easily inject dependencies into the membership provider because it is not resolved from a dependency injection container.
I think you have 2 possibilities:
You create a repository in the custom membership provider directly or you access it by some other means on demand (where the web context is already present).
You go one level higher and check the components that would use your membership provider and you try change there (to use a membership provider resolved from your DI container instead of the uninitialized Memership.Provider). If this "higher component" is the forms authentication, then this article might be of help (using dependency injection with IFormsAuthentication and IMembershipService): http://weblogs.asp.net/shijuvarghese/archive/2009/03/12/applying-dependency-injection-in-asp-net-mvc-nerddinner-com-application.aspx
Did you try resolving your repository "manually", like in this answer:
Ninject : Resolving an object by type _and_ registration name/identifier
?