Entity Framework Core Error: No parameterless constructor defined for this object - asp.net-mvc

At the point of creating a new MVC Controller:
after I click Add button, I get the following Error:
Here is my simple Context class:
public class MainDbContext : DbContext
{
public MainDbContext(DbContextOptions<MainDbContext> options) : base(options)
{
}
public DbSet<Todo> Todo { get; set; }
}
and my simple model:
public partial class Todo
{
public int Id { get; set; }
public string TaskName { get; set; }
}
I have made some search on this issue, most of the posts point to a dropdown list or a SelectList method using MVC, but for my case it is a Controller creation fail, so it seems to be an Entity Framework Core issue
Any help ?

Thanks to #poke comment above, and to this link: "Use Code First with connection by convention", by modifying the context class as follows C# will call base class parameterless constructor by default
public class MainDbContext : DbContext
{
public MainDbContext()
// C# will call base class parameterless constructor by default
{
}
}

It's a tooling error. Most likely, you're running Visual Studio 2015, which doesn't have full .NET Core support. Basically, in previous versions of EF, DbContext had a parameterless constructor, and this version of the scaffold generator is depending on that. In EF Core, DbContext does not have a parameterless constructor, so the generator is choking on that.
If you're using VS2015, upgrade to 2017. It's time. Aside from that, you don't need this anyways, and it's only leading you down a bad path. All the scaffold does is create a new class under Controller, named {Name}Controller that inherits from Controller. Then it creates a folder named {Name} in Views and adds some basic HTML for doing CRUD. You'll end up replacing most of this HTML anyways. Additionally, the scaffold requires you to work with an actual entity class, which is the last thing you should ever be doing. You should always accept user input via a view model and then map that posted data onto your entity class before finally saving the entity. Look at the scaffold being broken as an excellent opportunity to start learning how to create good code.

Here's the solution from Microsoft. It suggest to create a design-time class that instantiates the connection to a database.

A solution
Because DbContext constructor is expecting DbContextOptions, AddDbContext must be set within the Startup Configuration method.
public class MainDbContext : DbContext
{
public MainDbContext(DbContextOptions<MainDbContext> options) : base(options)
{
}
public DbSet<Todo> Todo { get; set; }
}
Within projects startup.cs set AddDbContext
services.AddDbContext<MainDbContext>(o => o.UseSqlServer(#"Data Source=SOURCE;Initial
Catalog=DBCatalog;User ID=ZX;Password=******;Connect
Timeout=30;Encrypt=False;TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
ConfigureServices method:
Set database:
UseSqlServer,
UseInMemeoryDatabase,
UseSqlite,
etc...
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<MainDbContext>(o => o.UseSqlServer(#"Data Source=SOURCE;Initial
Catalog=DBCatalog;User ID=ZX;Password=******;Connect
Timeout=30;Encrypt=False;TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False"));
}

Make sure your project builds and runs without errors before scaffolding.
In Visual Studio 2019, I received this error while attempting to scaffold a new controller because I had a missing comma in my JSON in appsettings.json file.
Eventually I built and tried to run and got a System.FormatException, "Could not parse the JSON file" during runtime.
Since appsettings.json was the only JSON file I was editing recently I knew it had to be appsettings.json.
Scaffolding, code generators, and EF migrations invoke runtime code, this means even if your code compiles, if it throws runtime errors those could cause a problem for such actions.
FYI -
As of EF Core 2.1 parameterized constructors are allowed.
See this Microsoft article for more information.
https://learn.microsoft.com/en-us/ef/core/modeling/constructors

the solution is check the file Startup.cs if you have in the void ConfigureServices the DataContext, for example in SQLServer my Startup.cs is
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourDataContext>(options => options.UseSqlServer(Configuration.GetConnectionString("YourConnectionStrings")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});
}
}
if you not have this services the error is
no parameterless constructor defined for type YourDataContextName

I had the same problem and I add this line to Startup.cs on the ConfigureServices method.
It worked fine for me:
services.AddControllersWithViews();

Just add an empty constructor to your dbcontext and this solves the problem.

Related

HttpContext is null when injected into a singleton dependency

I'm looking to create a global class in my Blazor application that contains a function that gets the user's Department through the user's username which I get from Windows authentication but I can't seem to access the HttpContextAccessor through my global class. It acts like it has access to HttpContext when I inject it but when it runs, I get the error
System.NullReferenceException: 'Object reference not set to an instance of an object.'
and the accessor is null when you look at it in the local variables.
I've done a lot of googling but couldn't find anything that melded well with what I'm doing and my current knowledge of how these things work.
Here's my global class:
public class Global
{
[Inject]
IHttpContextAccessor HttpContextAccessor { get; set; }
public string Identity;
public string Department;
public Global()
{
Identity = HttpContextAccessor.HttpContext.User.Identity.Name;
CalculateDepartment(Identity)
}
private void CalculateDepartment (string identity) {
//Calculate what department the person is in based on user ID
Department = CalculatedDepartment;
}
}
Here is my startup:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor(o => o.DetailedErrors = true);
services.AddTelerikBlazor();
services.AddHttpContextAccessor();
services.AddSingleton<Global>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.ApplicationServices.GetRequiredService<Global>();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
Google said to use services.AddScoped<Global> but I found that this didn't work with my CalculateDepartment function and when I used services.AddSingleton<Global> it worked so I kept it that way.
It appears to be doing this to anything I try to inject in this way into this file. I can inject things into any other page but not this class apparently. There were a few people simply saying to inject it into the constructor but that didn't help me much as I'm fairly new to this and I couldn't get the examples that I found of that to work. That could be the solution though, maybe I just need to do it in a way that would work. There could just be a better way of making a global class too.
Based on what I've surmised from your question - your looking to get access to the the HttpContext in Blazor Server. If so, then this code - credit to Robin Sue - gets the context for you:
// Server Side Blazor doesn't register HttpClient by default
// Thanks to Robin Sue - Suchiman https://github.com/Suchiman/BlazorDualMode
if (!services.Any(x => x.ServiceType == typeof(HttpClient)))
{
// Setup HttpClient for server side in a client side compatible fashion
services.AddScoped<HttpClient>(s =>
{
// Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
var uriHelper = s.GetRequiredService<NavigationManager>();
return new HttpClient
{
BaseAddress = new Uri(uriHelper.BaseUri)
};
});
}
If not then ignore the answer!
It turns out that I was unable to access anything that was injected through my constructor so I did some research and according to this website:
https://blazor-university.com/dependency-injection/injecting-dependencies-into-blazor-components/
Dependencies are injected after the Blazor component instance has been created and before the OnInitialized or OnInitializedAsync lifecycle events are executed. This means we cannot override our component’s constructor and use those dependencies from there, but we can use them in the OnInitialized* methods.
So basically I just can't use injected dependencies at all in my constructor. I've got to find another way to do this then! I'll update this when I find another way to do it if I don't just give up and move on.
Edit:
I ended up using a (imo) not great work around where I created a method in Global.cs that set the username string to whatever was put into it. Then I used the fact that my shared layouts are used at all times and can access the username through the use of <AuthorizeView> so I just set the username using the method that I created in one of my layouts like this:
<AuthorizeView>
<Authorized>
#{
Global.SetUserName(context.User.Identity.Name);
}
</Authorized>
</AuthorizeView>
So yeah, not ideal but it works and for now that's my goal.

DI parameters to class library without controller

So I'm not sure if I'm just missing something, but basically every example of DI I see with asp.net core shows passing of parameters from the appSettings.json file through a constructor in the controller and then to anything else.
Can I bypass the Controller and just inject directly a Class Library?
For an example of what I'm trying to do, let's say I have appSettings.json with
"EmailSettings":{"smtpServer":"mail.example.com", "port":123, "sendErrorsTo":"errors#example.com"}
Then a Class Library for EmailServices
EmailSettings.cs
public class EmailSettings{
public string smtpServer {get;set;}
public int port {get;set;}
public string sendErrorsTo {get;set;}
}
IEmailService.cs
public interface IEmailService
{
void SendErrorEmail(string method, Exception ex);
}
and EmailService.cs
public class EmailService :IEmailService
{
private readonly EmailSettings _emailSettings;
public EmailService(EmailSettings emailSettings)
{
_emailSettings = emailSettings;
}
public void SendErrorEmail(string method, Exception ex)
{
....
}
}
Startup.cs in the main asp.net core application
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddScoped<IEmailService, EmailService>(p => {
return new EmailService(p.GetService<EmailSettings>());
});
...
}
Without loading the EmailServices or the appsetting.json parameters through the controller and then into the BusinessLayer class library, I want to be able to call the SendErrorEmail from BusinessLayer (or any other place).
DoWork.cs
public MakeItWork()
{
try
{...}
catch (exception ex)
{
IEmailService.SendErrorEmail("BAL - MakeItWork",ex)
}
}
But it just fails with a null exception. The DI in the startup doesn't create the EmailService in place of the IEmailService, and I'm going to guess the parameters are not there either.
Thanks for any help you can give.
----EDIT----
I ended up just switching to using AutoFac for DI. It's able to accomplish what I was looking for. Accepted the answer below to give Phantom the points for trying to assist.
A couple of things:
In your MakeItWork() method, you have code that "calls" a method using the interface name - not even sure how that will compile. You need to use an object of a class that implements that interface to actually make method calls at runtime. For example, in your DoWork class, you could have a constructor requesting for an instance of a class that implements the IEmailService interface and store it for future use in other methods.
Second, in the Services collection, you are adding a "Scoped" dependency (in the ConfigureServices method). A "scoped" dependency is only created upon a (http)Request, typically via calls to controllers. From your code and your explanation, it looks like you are wanting to add a Singleton object for your IEmailService interface. So, instead of adding a Scoped dependency use AddSingleton - as you have done, you can also create the specific object in the call to AddSingleton - that means this object will be provided every time you request it (through class constructors, for example). If you are using it as a singleton, you should also make sure that it is thread safe. Alternatively, you can also add the dependency using AddTransient - if you use this, a new object will be created every time you request it.
Update:
Sample Code
Modify your ConfigureServices to make the EmailService as Transient (this means a new object every time this service is requested):
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<EmailSettings>(Configuration.GetSection("EmailSettings"));
services.AddTransient<IEmailService, EmailService>();
...
}
Your "DoWork" class should request the EMail Service in the constructor:
public class DoWork()
{
private IEmailService _emailService;
//Dependency should be injected here
public DoWork(IEmailService emailService)
{
_emailService = emailService;
}
public MakeItWork()
{
try
{...}
catch (exception ex)
{
//Use the saved email service object to do your work
_emailService.SendErrorEmail("BAL - MakeItWork", ex)
}
}
}
It doesn't end here. The question remains as to how you are going to create an Object of the DoWork class. For this, one idea is to create an interface for the DoWork class itself and then setup the container for that interface as well. Then wherever you would want to use the DoWork implementation you can "request" the interface for DoWork. Or use the container directly to create an instance.

Entity Framework 7 Migration Scaffolding in Class Library with Configuration

Trying to add migrations to an EF7 Model that lives in an ASP.NET 5 class library. When running dnx . ef migration add mymigration fails with different results depending on which project I run it on.
If I run it in the folder of the main project, it cannot locate a DbContext, this makes sense because the DbContext is in the shared project and ef commands likely don't care about dependencies.
If I run it in the folder of the shared project, it does not have access to the connection string specified in the startup.cs. I have gleaned from questions like this that it does work from the shared project if you specify the connection string in the OnConfiguring method of the DbContext but I really would like to keep this code separate from the configuration.
I came across some issue logs in the EF7 repository that mention they implemented command line options for specifying a project and a context but there are no examples and I couldn't figure out how to use it from looking at the source code in the commit history.
Here is an approach that might work for you.
If I run it in the folder of the shared project, it does not have access to the connection string specified in the startup.cs.
Startup.cs
I'm assuming that in your Startup.cs, you're specifying the connection string by accessing Configuration rather than by hard coding it. Further, I'm assuming that in your Startup.cs file's constructor, you're setting up configuration from a few sources. In other words, your Startup.cs might look something like this:
public class Startup
{
public IConfiguration Config { get; set; }
public Startup(IHostingEnvironment env)
{
var config = new Configuration()
.AddJsonFile("config.json")
.AddUserSecrets()
.AddEnvironmentVariables();
Config = config;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options =>
{
options.UseSqlServer(Config["ConnectionStrings:MyDbContext"]);
});
}
public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider)
{
var db = serviceProvider.GetRequiredService<MyDbContext>();
db.Database.AsSqlServer().EnsureCreated();
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
});
}
}
config.json
Further, I'm assuming that you're adding the connection string to a config.json in the root of your project (or that you adding it via user secrets or environmental variables.) Your config.json might look something like this:
{
"ConnectionStrings": {
"MyDbContext": "Some-Connection-String"
}
}
If you're not doing it that way, it might be worth trying it.
I have gleaned from questions like this that it does work from the shared project if you specify the connection string in the OnConfiguring method of the DbContext but I really would like to keep this code separate from the configuration.
DbContext
If my assumptions above are correct, then you can access the connection string in the DbContext by using the same pattern that you used in the Startup class. That is, in the DbContext constructor, setup the IConfiguration. Then, in OnConfiguring, access the connection string. It might look something like this:
public class MyDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder builder)
{
builder.Entity<SomeModel>().Key(e => e.Id);
base.OnModelCreating(builder);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var connString = Config["ConnectionStrings:MyDbContext"];
optionsBuilder.UseSqlServer(connString);
}
public IConfiguration Config { get; set; }
public MyDbContext()
{
var config = new Configuration()
.AddJsonFile("config.json")
.AddEnvironmentVariables();
Config = config;
}
}
Project Structure
You'll of course need to have a config.json file in the root of your shared projects folder too. So, your projects' structure could look something like this:
SharedDataContext
Migrations
config.json
project.json
WebApp
config.json
project.json
Startup.cs
In the above, both config.json files contain a connection string setting for the DbContext.
Some Thoughts
If you don't like duplicating the config.json connection string stuff, then you can use environmental variables or user secrets instead.

Accessing Methods/Properties from a class in a separate project without adding reference to the project containing the class (Same solution)

I'm not sure if the title correctly describes my problem. If someone could better describe my problem by reading the following description, please help me by editing the title to something more meaningful.
I'm trying to learn asp.net MVC with Entity Framework and Ninject.
I was having a look at NuGet Gallery application on GitHub and tried to implement a few parts in my project.
I followed the answer provided in this question [How do architect an ASP.Net MVC app with EF?] and designed my project with the following layered structure.
MyDemoApp
MyDemoApp.Domain (Contains POCO Classes)
MyDomain.Service (Contains references to Domain,EF. It contains only Interfaces)
MyDemoApp.Data (Contains references to EF, Domain, Service. It contains classes dealing with Entity Context and Repository)
MyDemoApp.Web (Contains references to ApplicationModel,Data,Domain,Service,Ninject)
MyDemoApp.ApplicationModel (Contains references to Data, Domain, Serivce. It implements the classes from Service project)
MyDemoApp.Web has no business logic and is acting like Humble Object, as mentioned in this answer
I have a Interface IConfiguration in MyDemoApp.Service project which is being implemented by Configuration class located in MyDemoApp.Web where I'm trying to read the connection string. I need to pass this connection string to the object of EntityContext being created in EntityContextFactory located in MydemoApp.Data
If I add a project reference of MyDemoApp.web to MyDemoApp.Data then Visual Studio Prompts me saying that it would cause a circular reference
In the following code return new EntitiesContext(""); How should I pass a parameter over here that would get the connection string that my bindings.cs gets ?
namespace MyDemoApp.Data
{
public class EntitiesContextFactory : IDbContextFactory<EntitiesContext>
{
public EntitiesContext Create()
{
//TO-DO : Get the Connnectionstring
return new EntitiesContext(""); //Need to pass connection string by calling property from Configuration class in MyDemoApp.Web project
}
}
public class EntitiesContext:DbContext,IEntitiesContext
{
public EntitiesContext(string connectionString) : base(connectionString)
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Provide mapping like foreign key
}
}
}
}
Configuration.cs:
namespace MydemoApp.Web
{
public class Configuration : IConfiguration
{
public string ConnectionString
{
get
{
return ConfigurationManager.ConnectionStrings['dev'].ConnectionString;
}
}
}
}
Bindings.cs:
namespace MydemoApp.Web.Bindings
{
public class MyModule : NinjectModule
{
public override void Load()
{
Bind<IConfiguration>().To<Configuration>();
var configuration = new Configuration(); //Gives me Connectionstring
Bind<IEntitiesContext>().ToMethod(context => new EntitiesContext(configuration.ConnectionString)); // This part would help me pass the connection string to the constructor
}
}
}
I don't quite get what problem you are facing. I assume that you need to access a class in Web assembly from Data assembly, but Data assembly already referencing Web assembly.
Can you just inject the configuration interface to your factory constructor, and use that to get the connection string?
public class EntitiesContextFactory : IDbContextFactory<EntitiesContext>
{
public EntitiesContextFactory(IConfiguration configuration){
this.configuration = configuration;
}
IConfiguration configuration;
public EntitiesContext Create()
{
return new EntitiesContext(configuration.ConnectionString);
}
}
I may misunderstand your question though.
Personally, I think you should leverage the ConfigurationManager in your EntitiesContextFactory.
This would look like:
return new EntitiesContext(System.Configuration.ConfigurationManager.ConnectionStrings["{connectionstringname}"].ConnectionString)
This class is agnostic of whether it is an app.config or web.config that is providing the configuration.
All it stipulates is that application that is hosting the dlls for running, must be configured with an (app/web).config that contains that connection string. your app can test for this at startup since it knows it has a dependency on a database connection for it to work.

ASP.NET MVC, MVCContrib, Structuremap, getting it working as the controllerfactory?

I'm trying to get structuremap to correctly create my controllers, I'm using DI to inject an INewsService into a NewsController and thats the only constructor I have.
public class NewsController : Controller
{
private readonly INewsService newsService;
public NewsController(INewsService newsService)
{
this.newsService = newsService;
}
public ActionResult List()
{
var newsArticles = newsService.GetNews();
return View(newsArticles);
}
}
and I'm using this code to start the app
public class Application : HttpApplication
{
protected void Application_Start()
{
RegisterIoC();
RegisterViewEngine(ViewEngines.Engines);
RegisterRoutes(RouteTable.Routes);
}
public static void RegisterIoC()
{
ObjectFactory.Initialize(config => {
config.UseDefaultStructureMapConfigFile = false;
config.AddRegistry<PersistenceRegistry>();
config.AddRegistry<DomainRegistry>();
config.AddRegistry<ControllerRegistry>();
});
DependencyResolver.InitializeWith(new StructureMapDependencyResolver());
ControllerBuilder.Current.SetControllerFactory(typeof(IoCControllerFactory));
}
}
But Structuremap doesn't seem to want to inject the INewsService and I get the error
No parameterless constructor defined for this object.
What have I missed?
I use the "Default Conventions" mechanism that StructureMap provides to avoid needing to individually configure each interface. Below is the code I use to make that work:
My Global.asax has this line in Application_Start (which uses the StructureMap factory from MvcContrib):
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ObjectFactory.Initialize(x =>
{
x.AddRegistry(new RepositoryRegistry());
});
ControllerBuilder.Current.SetControllerFactory(typeof(StructureMapControllerFactory));
}
And the RepositoryRegistry class looks like this:
public class RepositoryRegistry : Registry
{
public RepositoryRegistry()
{
Scan(x =>
{
x.Assembly("MyAssemblyName");
x.With<DefaultConventionScanner>();
});
}
}
The DefaultConventionScanner looks for pairs of Interfaces/Classes that follow the nameing convention of ISomethingOrOther and SomethingOrOther and automatically associates the latter as a concrete type for the former interface.
If you didn't want to use that default convention mechanism, then you would add code in the Registry class to explicity map each of your interfaces to the concrete types with this syntax:
ForRequestedType<ISomethingOrOther>().TheDefaultIsConcreteType<SomethingOrOther>();
Unless I'm missing something, you are not telling StructureMap what concrete type to use for INewsService. You need to add something like:
TheConcreteTypeOf<INewsService>.Is<MyConcreteNewsService>();
I don't know the exact syntax off the top of my head, but that's what you're missing. Once you specify that then it will know what instance of the INewsService to inject into the controller.
ASP.NET MVC currently instantiates controllers using the default parameterless constructor, which precludes any constructor-based dependency injection. To do that, you really need to use the MvcContrib project, which has built-in support for StructureMap (and Castle/Spring.NET/Unity), although the current documentation is non-existent (literally, you get a stub wiki page, not a good sign). Erv Walter's code sample in this thread shows how to set up the StructureMap integration.

Resources