InvalidOperationException: MVC - asp.net-mvc

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

Related

Registering a MediatR pipeline constrained PostProcessor using ASP.NET Core DI

Previously, we had the following pipeline setup working for auditlogging purposes
public class AuditLogPostProcessor<TRequest, TResponse> :
IRequestPostProcessor<TRequest, TResponse>
where TRequest : IAuditLogRequest<TResponse>
Where IAuditLogRequest implements IRequest
public interface IAuditLogRequest<TResponse> : IRequest<TResponse>
All and only the Commands that implement the IAuditLogRequest reached the AuditLogPostProcessor.
Registration using SimpleInjector was as follows
_container.RegisterCollection(typeof(IRequestPostProcessor<,>),
new[] { typeof(GenericRequestPostProcessor<,>),typeof(AuditLogPostProcessor<,>) });
Currently, we use the ASP.NET Core DI for our Dependence Injection with the following registration.
services.AddScoped(typeof(IRequestPostProcessor<,>), typeof(GenericRequestPostProcessor<,>));
services.AddScoped(typeof(IRequestPostProcessor<,>), typeof(AuditLogPostProcessor<,>));
When a Command implements the IRequest, we get the error
TypeLoadException: GenericArguments[0], 'Command',
on 'AuditLogPostProcessor`2[TRequest,TResponse]' violates
the constraint of type parameter 'TRequest'.
So it seems the DI is not honoring the constraint. Can I get the desired behavior with the ASP.NET Core DI?
I was looking to do exactly the same thing. Apparently ASP.net core DI does not support this feature.
SRC: Support constrained open generic types
You need to use another container such as Autofac or StructureMap.
Example: Autofac for ASP.NET core
It's very simple and it does not require much changes
We have a similar setup.
If your handler implements IRequestPostProcessor, all you need to do is add this to your DI :
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(RequestPostProcessorBehavior<,>));

ASP.net Core EF DataContext not Scoped as per Documentation?

In my Startup.cs file, I have set up a data context to participate in DI.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer("Connection String");
});
}
According to Dependency Injection Doc, the above code automatically puts the data context as Scoped in the IoC container. I am under the impression that an instance of MyDbContext is created for every request. A subsequent request would then have a new MyDbContext instance throughout its lifetime.
I have a controller set up and I'm passing MyDbContext via constructor DI. I make a simple GET request, and I get the data I want. I make a change to that very entity in SQL Management Studio, like change the value of one property/column. I make that same GET request. I don't get the new value that I set in SQL Management Studio.
This makes me think that ASP.net Core holds on to the same instance of MyDbContext across the lifetime of my application. If I stopped and restarted the application, that GET request will return the value I expected.
How do I refresh this data context for each request if I set it up with DI?
Am I missing something? I might post more code if needed.

asp.net 5 dependency injection in multiple projects

I've got an ASP.NET 5 dnxcore solution with some projects to separate my logic:
API
Core (with services for business logic)
DAL (repository interfaces)
Entity Framework (the repositories implementations)
Now I use DI to call my services in the constructors of my API controllers:
private readonly IMyService _myService;
public Controller(IMyService myservice){ _myService = myService; }
The services in my core get the repository thru constructor injection too:
private readonly IMyRepository _myRepo;
public MyService(IMyRepository myRepo){ _myRepo = myRepo; }
Currently I need to define my DI container in the startup class of my API to make it work.
My question is, how can I put the 'building' of the DI container of the repositories in my services in my Core-project. This way, my API is loosely coupled of the fact that my services use Entity Framework, so I can change to, for example, mongodb without changing my API project.
My question is, how can I put the 'building' of the DI container of the repositories in my services in my Core-project. This way, my API is loosely coupled of the fact that my services use Entity Framework, so I can change to, for example, mongodb without changing my API project.
You could, but you shouldn't do that.
Dependency Injection is the practice of making loosely-coupled classes throughout the libraries that can be plugged together (often in many ways).
However, each application should have a composition root, which is the one place in the application where we put the coupling code. Our first instinct as developers is to try to farm the coupling code off into its own library, but that is an urge that you should resist. See composition root reuse.
Mark Seeman's illustration sums it up well. Avoiding transitive dependencies is what is desired when using DI in order to flatten the dependency graph. This ensures assemblies can be used/tested in isolation without dragging along unnecessary dependencies, which in turn makes maintenance easier.
That said, many DI containers have a way to organize the configuration of certain parts of the application by using modules. In Autofac, the documentation for modules is here.
You can easily add an extension method of IServiceCollection into your services layer and use it to register its own dependencies.
Then in the startup you just call the method on the service layer without having any reference to EntityFramework in your web app.
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace your.service.layer
{
public static class MyServiceCollectionExtensions
{
public static IServiceCollection AddMyServiceDependencies(this IServiceCollection services)
{
services.AddScoped<My.Data.Tier.DbContext, My.Data.Tier.DbContext>();
}
}
}
Startup:
using your.service.layer;
public void ConfigureServices(IServiceCollection services)
{
services.AddMyServiceDependencies();
}
Now your web app only needs a reference to your service layer and it is not directly dependent on EntityFramework.
As NightOwl888 have said, you should have a CompositionRoot in your application, the place where all your dependencies are set.
What I did is this:
1. Create a Core Class Library named CompositionRoot.
2. Add a class to handle your dependencies:
public class DependencyMapper
{
public static void SetDependencies(IServiceCollection serviceCollection, IConfigurationRoot configuration)
{
serviceCollection.AddEntityFramework()
.AddDbContext<SonoPeopleContext>(options =>
options.UseSqlServer(configuration["Data:DefaultConnection:ConnectionString"])
);
MapperConfiguration mapperConfiguration = new MapperConfiguration(cfg =>
{
cfg.AddProfile(new AutoMapperProfileConfiguration());
});
serviceCollection.AddSingleton<IMapper>(sp => mapperConfiguration.CreateMapper());
serviceCollection.AddScoped<IUserService, UserService>();
}
}
Then you reference your CompositionRoot in your MVC project and in your Startup.cs you just do
DependencyMapper.SetDependencies(services, Configuration);
That's all.
See this question, I have the same problem because my application is DB agnostic and base on the request will need to switch between a document oriented database (noSQL) and transaccional database (SQL).

Automatically updating database with multiple DbContexts

I'm using EF6 in ASP.NET 5 project. Where I'm using ASP.NET Identity as the authentication mechanism. As anyone would do, I have modeled my domain objects in a separate dll project and for data access logic I have a separate project. This data project contains EF migrations, DbContext for domain models, repositories and Unit of work.
And I have a service layer which is contacted by ASP.NET controllers and this service layer will communicate with data layer and do required operations.
In the main ASP.NET web project I have the default DbContext which is related to Identity and it's migrations.
Having two DbContexts somehow prevents me from updating database automatically. If I had only one DbContext after I create migrations for model changes, it will automatically run on the first time I try to access the website. This doesn't happen anymore, always I have to run the "update-database" command manually.
One solution I have right now is to add a reference to "Microsoft.AspNet.Identity.EntityFramework" in my data project and use Identity context contain my domain tables. But adding an ASP.NET reference in my data project is something I don't want to do unless I have no other options. Because data layer is not even communicating directly with web layer.
Even though this video by Scott Allen discuss about this issue, a solution is not proposed.
You can kick in migrations explicitly by using database initializer and using MigrateDatabaseToLatestVersion. This initializer allows you explicitly state the context and configuration you want to use. Something like:
SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>());
You can also call all the logic manually, effectively doing the same as Update-Database cmdlet, when you want during app start. Look at DbMigrator class.
You can run migration inside each DbContext constructor separately.
public class DataContext: DbContext
{
static DaraContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
}
}
public class ApplicationDbContext : IndetityDbContext
{
static ApplicationDbContext()
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());
}
}

Inject repository to custom membership provider with Ninject

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
?

Resources