No parameterless constructor defined for this object in asp.netcore migrations - asp.net-core

I am new to ASP.NET Core. learning new version of .NET Core 2.0 using VS Code. I got stuck while doing creating database using migration. First, it gives an exception of implementation of IDesignTimeDbContextFactory. After solving this, it still gives an exception of
No parameterless constructor defined for this object
Here's my code for DbContextClass:
public VegaDbContext CreateDbContext(string[] args)
{
IConfigurationRoot configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json")
.Build();
var builder = new DbContextOptionsBuilder<VegaDbContext>();
var connectionString =
configuration.GetConnectionString("DefaultConnection");
builder.UseSqlServer(connectionString);
return new VegaDbContext(builder.Options);
}

I had tried a couple of ways when I was experimenting with ef core. I faced similar issues too. Finally I found services working great. First you will need to create your DBContext with the following override constructor:
public VegaDbContext(DbContextOptions<VegaDbContext> options) : base(options)
{
}
In your start up, you can add your context as a service like this:
services.AddDbContext<ApplicationDBContext>(config => {
config.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
});
You can read in full detail about how dependency injection works here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection
This part should help you with the migration. You can perform your migrations using the dotnet ef commands https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet.
When using your db context, do ensure that you are using dependency injection so you make full use of the AddDbContext function and keep it DRY.

https://learn.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro
If I were your in your shoes, I look at this document.
Here is the simple DbContext that you can find on this webSite
namespace ContosoUniversity.Data
{
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
{
}
public DbSet<Course> Courses { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Student> Students { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Course>().ToTable("Course");
modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
modelBuilder.Entity<Student>().ToTable("Student");
}
}
}

I just got the same error. If you are careful the error description is actually giving you the solution of the problem.
  DesignTimeFactoryObject's constructor function should not take parameters.
public class ExampleDesignTimeFactory : IDesignTimeDbContextFactory<YourDBContext>{
public ExampleDesignTimeFactory(){ no constructor or no parameter constructor }
}

I use ASP.NET CORE 3.1 to create the project and it solved

Related

AddPooledDbContextFactory with DbContext that uses custom DbConnection: service not registered

I have a custom DbContext SnowflakeDbContext that I need to initialize with a SnowflakeDbConnection for it to work:
public class SnowflakeDbContext : DbContext
{
private readonly string connectionString = "";
public SnowflakeDbContext(DbContextOptions<SnowflakeDbContext> options) : base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
var dbConnection = new SnowflakeDbConnection()
{
ConnectionString = this.connectionString
};
optionsBuilder.UseSqlServer(dbConnection);
optionsBuilder.AddInterceptors(new SnowflakeCommandInterceptor());
}
public DbSet<Opportunity> Opportunities { get; set; } = default!;
public DbSet<Account> Accounts { get; set; } = default!;
}
This works well with EF Core 5, were in Startup.cs (I am using an ASP.NET Core 5 web application) I use
.AddDbContext<SnowflakeDbContext>(ServiceLifetime.Singleton)
I want to use the SnowflakeDbContext with HotChocolate where it is recommended that I use AddPooledDbContextFactory<> in order to support pooling of connections and allowing the system to make simultaneous calls (described here).
I have modified Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services
.AddPooledDbContextFactory<SnowflakeDbContext>(options =>
{
var dbConnection = new SnowflakeDbConnection()
{
ConnectionString = this.connectionString
};
options.UseSqlServer(dbConnection);
options.AddInterceptors(new SnowflakeCommandInterceptor());
})
.AddGraphQLServer()
.AddQueryType<Query>();
}
Using the following GraphQL query (which uses parallel queries):
query GetAccountsInParallel {
a: accounts {
id, name
}
b: accounts {
id, name
}
c: accounts {
id, name
}
}
I get the following error:
"No service for type 'SnowflakeGraphQL.Snowflake.SnowflakeDbContext' has been registered.",
I can add
.AddDbContext<SnowflakeDbContext>()
in Startup.cs after the call to .AddPooledDbContextFactory<>. Now I get a different error:
"A second operation was started on this context instance before a previous operation completed. This is usually caused by different threads concurrently using the same instance of DbContext."
All of the examples I have seen on the web use .UseSqlServer(connectionString) where as I need to use the .UseSqlServer(dbConnection) version in order to be able to access our Snowflake database.
How do I configure my application in Startup.cs to use .AddPooledDbContextFactory()?
Update: Starting with the graphql-workshop code and replacing Sqlite with first SqlServer and then SqlServer using my SnowflakeDbContext I get it to work, so there must be a subtle difference somewhere in my code as described above that results in a failure in my case.
When retrieving the accounts records, we need to use the [ScopedService] rather than the [Service] like this:
[UseApplicationDbContext]
public async Task<List<Account>> GetAccounts([ScopedService] SnowflakeDbContext context) => await context.Accounts.ToListAsync();

IHttpClientFactory using in ActionFilterAttribute [duplicate]

I am trying to inject a service into my action filter but I am not getting the required service injected in the constructor. Here is what I have:
public class EnsureUserLoggedIn : ActionFilterAttribute
{
private readonly ISessionService _sessionService;
public EnsureUserLoggedIn()
{
// I was unable able to remove the default ctor
// because of compilation error while using the
// attribute in my controller
}
public EnsureUserLoggedIn(ISessionService sessionService)
{
_sessionService = sessionService;
}
public override void OnActionExecuting(ActionExecutingContext context)
{
// Problem: _sessionService is null here
if (_sessionService.LoggedInUser == null)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Unauthorized");
}
}
}
And I am decorating my controller like so:
[Route("api/issues"), EnsureUserLoggedIn]
public class IssueController : Controller
{
}
Startup.cs
services.AddScoped<ISessionService, SessionService>();
Using these articles as reference:
ASP.NET Core Action Filters
Action filters, service filters and type filters in ASP.NET 5 and MVC 6
Using the filter as a ServiceFilter
Because the filter will be used as a ServiceType, it needs to be registered with the framework IoC. If the action filters were used directly, this would not be required.
Startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddMvc();
services.AddScoped<ISessionService, SessionService>();
services.AddScoped<EnsureUserLoggedIn>();
...
}
Custom filters are added to the MVC controller method and the controller class using the ServiceFilter attribute like so:
[ServiceFilter(typeof(EnsureUserLoggedIn))]
[Route("api/issues")]
public class IssueController : Controller {
// GET: api/issues
[HttpGet]
[ServiceFilter(typeof(EnsureUserLoggedIn))]
public IEnumerable<string> Get(){...}
}
There were other examples of
Using the filter as a global filter
Using the filter with base controllers
Using the filter with an order
Take a look, give them a try and see if that resolves your issue.
Hope this helps.
Global filters
You need to implement IFilterFactory:
public class AuthorizationFilterFactory : IFilterFactory
{
public bool IsReusable => false;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
// manually find and inject necessary dependencies.
var context = (IMyContext)serviceProvider.GetService(typeof(IMyContext));
return new AuthorizationFilter(context);
}
}
In Startup class instead of registering an actual filter you register your filter factory:
services.AddMvc(options =>
{
options.Filters.Add(new AuthorizationFilterFactory());
});
One more way for resolving this problem. You can get your service via Context as in the following code:
public override void OnActionExecuting(ActionExecutingContext context)
{
_sessionService = context.HttpContext.RequestServices.GetService<ISessionService>();
if (_sessionService.LoggedInUser == null)
{
context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Result = new JsonResult("Unauthorized");
}
}
Please note that you have to register this service in Startup.cs
services.AddTransient<ISessionService, SessionService>();
Example
private ILoginService _loginService;
public override void OnActionExecuting(ActionExecutingContext context)
{
_loginService = (ILoginService)context.HttpContext.RequestServices.GetService(typeof(ILoginService));
}
Hope it helps.
After reading this article ASP.NET Core - Real-World ASP.NET Core MVC Filters (Aug 2016) I implemented it like this:
In Starup.cs / ConfigureServices:
services.AddScoped<MyService>();
In MyFilterAttribute.cs:
public class MyFilterAttribute : TypeFilterAttribute
{
public MyFilterAttribute() : base(typeof (MyFilterAttributeImpl))
{
}
private class MyFilterAttributeImpl : IActionFilter
{
private readonly MyService _sv;
public MyFilterAttributeImpl(MyService sv)
{
_sv = sv;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_sv.MyServiceMethod1();
}
public void OnActionExecuted(ActionExecutedContext context)
{
_sv.MyServiceMethod2();
}
}
}
In MyFooController.cs :
[MyFilter]
public IActionResult MyAction()
{
}
Edit: Passing arguments like [MyFilter("Something")] can be done using the Arguments property of the TypeFilterAttribute class: How do I add a parameter to an action filter in asp.net? (rboe's code also shows how to inject things (the same way))
While the question implicitly refers to "filters via attributes", it is still worth highlighting that adding filters "globally by type" supports DI out-of-the-box:
[For global filters added by type] any constructor dependencies will be populated by dependency injection (DI). Adding a filter by type is equivalent to filters.Add(new TypeFilterAttribute(typeof(MyFilter))).
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection
With regards to attribute-based filters:
Filters that are implemented as attributes and added directly to controller classes or action methods cannot have constructor dependencies provided by dependency injection (DI). This is because attributes must have their constructor parameters supplied where they're applied. This is a limitation of how attributes work.
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#dependency-injection
However, as mentioned in the previous answers to the OP, there are ways of indirection that can be used to achieve DI. For the sake of completeness, here are the links to the official docs:
ServiceFilterAttribute
TypeFilterAttribute
IFilterFactory implemented on your attribute

NSubstitute for the EF's Core DbContext - how to use it?

I'm trying to create the unit test for a class which uses my EF Core DbContext:
public class MyContext : DbContext
{
public MyContext(DbContextOptions<MyContext> options) : base(options)
{
}
public DbSet<SomeTable> SomeTables { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
}
}
the class which is consuming that context is simple:
public class MyClass
{
public MyClass(MyContext db)
{
}
}
so, when I try to create
var fakeContext = Substitute.For<MyContext>();
which ends with the error:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException : Can not instantiate proxy of class: MyContext.
Could not find a parameterless constructor.
which is being raised by base(options) constructor. So, the net approach was to extend the code:
var dbContextOptions = Substitute.For<DbContextOptions<MyContext>>();
dbContextOptions.ContextType.Returns(typeof(MyContext));
var dbContextOptionsExtension = Substitute.For<IEnumerable<IDbContextOptionsExtension>>();
dbContextOptions.Extensions.Returns(dbContextOptionsExtension);
var myFakeContext = Substitute.For<MyContext>(dbContextOptions);
but it generates more and errors. So, how to fix it ?
You haven't elaborated on the additional errors so I can't provide a specific answer, however trying to mock a DbContext properly is difficult. IMO there are two options.
1) Use the Microsoft in-memory provider.
2) If you want to use a mocked DbContext using NSubstitute, use a pre-existing library that does the mocking for you. There are a few around such as EntityFrameworkCore.Testing.NSubstitute (disclaimer - I am the author).
The in-memory provider is not a complete implementation, it can't do relational operations and there are a swag of LINQ operations it doesn't support, so depending on your use cases the latter may be a better solution.
If you have a specific error/use case in mind pop it up and I may be able to provide a better answer.
Ok, I've used the InMemory provider:
var options = new DbContextOptionsBuilder<AgreementContext>()
.UseInMemoryDatabase("fakeDb")
.Options;
var agreementContext = Substitute.For<MyContext>(options);

Creating a database context using the database first approach with entityframework core.

I want to be able to create a database context with entityframework core in my webapi project using the database first approach.
When I create like this it works very well
public class TestingContext : DbContext
{
public TestingContext(DbContextOptions<TestingContext> options)
: base(options)
{
}
public TestingContext()
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
I had to add the line services.AddDbContext to make it work.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddCors();
//using Dependency Injection
services.AddSingleton<Ixxx, xxx>();
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddDbContext<TestingContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// Register the Swagger generator, defining one or more Swagger documents
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "Articles API", Version = "v1" });
});
}
If I remove this method from my TestingContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
I get the error below.
No database provider has been configured for this DbContext.
A provider can be configured by overriding the DbContext.OnConfiguring method or
by using AddDbContext on the application service provider. If AddDbContext is used,
then also ensure that your DbContext type accepts a DbContextOptions object in its
constructor and passes it to the base constructor for DbContext.
Why do I need to pass my connection string to the database in two places before it can pull my data. Please assist. I am new to the core. The two places are configure services method and the context itself.
Option 1: Remove parameterized constructor and OnConfiguring. Result:
public class TestingContext : DbContext
{
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
Option 2: Remove parameterized constructor and options in ConfigureServices in AddDbContext
Result:
In Startup.cs
services.AddDbContext<TestingContext>();
In TestingDbContext.cs
public class TestingDdContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=xxxxxx;Initial Catalog=xxxxxx;Integrated Security=False;User Id=xxxxx;Password=xxxxx;MultipleActiveResultSets=True");
}
public DbSet<Information> Information { get; set; }
public DbSet<ArticleUser> ArticleUser { get; set; }
}
Option 3: A parametric constructor is needed to create factory. Example:
public class TestDdContext : DbContext
{
public TestDdContext(DbContextOptions options) : base(options)
{
}
//TODO: DbSets
}
public class TestDbContextFactory : IDbContextFactory<TestDdContext>
{
public TestDdContext Create(DbContextFactoryOptions options)
{
var contextOptions = new DbContextOptionsBuilder();
contextOptions.UseSqlServer("...");
return new TestDdContext(contextOptions.Options);
}
}
If you are creating tests, do you need a backing Sql database? Would the In-memory provider not serve you better?
options.UseInMemoryDatabase("database-name");
For this reason, I'd ditch using the OnConfiguring method, and rely on passing the DbContextOptions to your constructor
Side note, you have to consider what you are testing - are you testing your code that is dependent on your DbContext, or are you testing your DbContext itself - if there is no custom logic and you are merely extending the DbContext, there may not be enough value in writing tests for it - and you're not responsible for testing EFCore itself.

Windsor webservice inject properties

I have a MVC application and inject my repositories to my controller what works properly.
Additionally I have a Webservice in my solution which uses exactly the same repositories but when my Webservice is called my repository properties are null.
I register my repositories the following way:
container.Register(Classes.FromAssembly(Assembly.GetAssembly(typeof(HdtRepository))).InSameNamespaceAs<HdtRepository>().WithService.DefaultInterfaces().LifestyleTransient());
my repository properties look like:
public IUserRepository _userRepo { get; set; }
public IHdtRepository _hdtRepo { get; set; }
public ITimeRecordRepository _timeRepo { get; set; }
Can someone tell me why the repositories are not injected to my webservice?
For now I added the following to the constructor of my webservice:
public MyWebservice()
{
_userRepo = MvcApplication.container.Resolve<IUserRepository>();
_hdtRepo = MvcApplication.container.Resolve<IHdtRepository>();
_timeRepo = MvcApplication.container.Resolve<ITimeRecordRepository>();
_locationRepo = MvcApplication.container.Resolve<ILocationRepository>();
_wayRepo = MvcApplication.container.Resolve<IWayPointRepository>();
_wayDataRepo = MvcApplication.container.Resolve<IWayDataRepository>();
}
but as far as I know this is actually a antipattern.
I'm new to all that IoC stuff so could someone please tell me where the problem is.
Cheers,
Stefan
First lets get your project setup with some Windsor installers. They look like this for the most part.
public class ServiceInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Component.For<IEncryptionService().ImplementedBy<EncryptionService>());
}
}
in your App_Start folder add a class called ContainerConfig.cs that could look something like this.
public class ContainerConfig
{
private static IWindsorContainer _container;
public static IWindsorContainer ConfigureContainer()
{
_container = new WindsorContainer();
_container.Install(FromAssembly.This()).Install(FromAssembly.Named("Project.Dependency"));
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
_container.AddFacility<TypedFactoryFacility>();
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
return _container;
}
}
Please note that I have a separate project for my Dependency Injection hence the _container.Install(FromAssembly.This()).Install(FromAssembly.Named("Project.Dependency")); line... You can remove the latter .Install(FromAssembly) part.
In your Global.asax you can do something like this:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ContainerConfig.ConfigureContainer();
}
Now in your controllers you can do this:
public class TempController : Controller
{
private readonly IEncryptionService _encryptionService;
public TempController(IEncryptionService encryptionService )
{
_encryptionService = encryptionService;
}
public ActionResult Index()
{
// Example of calling a method on the encryption service.
string hash, salt;
_encryptionService.GethashAndSaltString("I Need Some Loving", out hash, out salt);
return View();
}
}
Please let me know if you get something working with constructor injection. Solving that issue will be a great help going forward and you won't be using property injection. Once we get all of that sorted out we can look at your webervice issues.
I guess this is not possible as far as I've read some other posts.
The problem is that you can't create a custom factory for a Webservice like "WindsorControllerFactory" for the controller.
I'm going to switch to WCF Service.
Resolve a System.Web.Services.WebService instance with Castle (for AOP purposes)