Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

If Program.Main calls extension methods, dotnet aspnet-codegenerator -dc fails with "Could not get the reflection type for DbContext" #2623

Closed
dylanbeattie opened this issue Jan 17, 2024 · 4 comments · Fixed by #2641

Comments

@dylanbeattie
Copy link

The bug occurs when trying to run dotnet aspnet-codegenerator and specify a DbContext:

dotnet aspnet-codegenerator controller -name ArtistsController -m Artist -dc MyDbContext

If the application's Program.Main method calls any extension methods, the tool fails with:

Could not get the reflection type for DbContext : MyDbContext
  at Microsoft.VisualStudio.Web.CodeGeneration.ActionInvoker.<BuildCommandLine>b__6_0()
  at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.Execute(String[] args)
  at Microsoft.VisualStudio.Web.CodeGeneration.ActionInvoker.Execute(String[] args)
  at Microsoft.VisualStudio.Web.CodeGeneration.CodeGenCommand.Execute(String[] args)

This happens with projects that reference Microsoft.VisualStudio.Web.CodeGeneration.Design v8.0.0. The same code works fine with Microsoft.VisualStudio.Web.CodeGeneration.Design v7.0.1, running under both .NET 7 and under .NET 8.

  • Verified on .NET 8.0.101 Windows 10 Pro 10.0.19045
  • Verified on .NET 8.0.101 on Linux (Ubuntu 20.04 on Windows WSL2)

Code is below, and there are .NET 7 and .NET 8 projects demonstrating the problem available at github.com/dylanbeattie/dotnet8-aspnet-codegenerator-bug.

using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

/* The codegen command that reproduces the problem:

 dotnet aspnet-codegenerator controller -name ArtistsController -m Artist -dc MyDbContext

If you uncomment the call to builder.DoNothing(), this command fails with:
  Could not get the reflection type for DbContext : MyDbContext
    at Microsoft.VisualStudio.Web.CodeGeneration.ActionInvoker.<BuildCommandLine>b__6_0()
    at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.Execute(String[] args)
    at Microsoft.VisualStudio.Web.CodeGeneration.ActionInvoker.Execute(String[] args)
    at Microsoft.VisualStudio.Web.CodeGeneration.CodeGenCommand.Execute(String[] args)
*/

// builder.DoNothing();

builder.Services.AddControllersWithViews();
var sqliteConnection = new SqliteConnection("Data Source=:memory:");
sqliteConnection.Open();
builder.Services.AddDbContext<MyDbContext>(options => options.UseSqlite(sqliteConnection));
var app = builder.Build();


using (var scope = app.Services.CreateScope()) {
	var db = scope.ServiceProvider.GetService<MyDbContext>()!;
	db.Database.EnsureCreated();
}

app.UseStaticFiles();
app.UseRouting();
app.MapGet("/", (MyDbContext db) => db.Artists.ToList());
app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
app.Run();

public static class ExtensionMethods {
	public static bool DoNothing(this WebApplicationBuilder builder) => true;
}

public class Artist {
	public Guid Id { get; set; }
	public string Name { get; set; } = String.Empty;
}

public class MyDbContext : DbContext {
	public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }

	public DbSet<Artist> Artists { get; set; } = default!;
	protected override void OnModelCreating(ModelBuilder modelBuilder) 	{
		base.OnModelCreating(modelBuilder);
		modelBuilder.Entity<Artist>().HasData(
			new Artist { Id = Guid.NewGuid(), Name = "Artist A" },
			new Artist { Id = Guid.NewGuid(), Name = "Artist B" },
			new Artist { Id = Guid.NewGuid(), Name = "Artist C" }
		);
	}
}
@dylanbeattie
Copy link
Author

I'm guessing this is related to some other issues folks have reported with aspnet-codegenerator when specifying a DbContext:

@deepchoudhery
Copy link
Member

Haven't gotten to fixing this bug, thanks a lot for finding this info, will have this fixed for servicing early next month.

@dylanbeattie
Copy link
Author

I'm also seeing the same behaviour if I call any extension methods from within the DbContext.

Given this utility class:

public static class NodaTimeConverters {

	public static ModelConfigurationBuilder AddNodaTimeConverters(this ModelConfigurationBuilder builder) {
		builder.Properties<Instant>().HaveConversion<InstantToDateTimeOffsetConverter>();
		return builder;
	}

	private class InstantToDateTimeOffsetConverter()
		: ValueConverter<Instant, DateTimeOffset>(i => i.ToDateTimeOffset(),
			dto => Instant.FromDateTimeOffset(dto));
}

If I call the AddNodaTimeConverters as an extension method:

	protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) {
		base.ConfigureConventions(configurationBuilder);
		configurationBuilder.AddNodaTimeConverters();
	}

I get the same error "Could not get the reflection type for DbContext", but if I call the same code as a static method:

	protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder) {
		base.ConfigureConventions(configurationBuilder);
		NodaTimeConverters.AddNodaTimeConverters(configurationBuilder);
	}

it works.

@Grizzlly
Copy link

@deepchoudhery any updates?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants