Controller scaffolding using EF fails when project contains middleware configured using secrets #305

Closed
DaniJG opened this Issue Oct 4, 2016 · 2 comments

Projects

None yet

2 participants

@DaniJG
DaniJG commented Oct 4, 2016

It seems EntityFrameworkServices.GetModelMetadata will fail at the step Attempting to figure out the EntityFramework metadata for the model and DbContext when building the application services in EntityFrameworkServices.TryCreateContextUsingAppCode, if the Startup class adds some middleware with required options being populated from the secret manager.

I have created a new ASP.Net Core 1.0.0 project using the default Web Application template adding individual accounts authentication.
Then I have added the google authentication middleware:

    "Microsoft.AspNetCore.Authentication.Google": "1.0.0"

I have updated my startup class with the Google middleware, where the ClientId and Secret are read from the SecretManager tool:

app.UseGoogleAuthentication(new GoogleOptions
{
    ClientId = Configuration["GoogleClientId"],
    ClientSecret = Configuration["GoogleClientSecret"]             
});

If I then:

  1. Create a new model class
  2. Either add a dbSet to the default ApplicationDbContext or create a new dbContext class
  3. Run the MVC Controller with Views, using Entity Framework scaffolding selecting that model class and context

I get the following error:

C:\Program Files\dotnet\dotnet.exe aspnet-codegenerator --project "C:\Users\Daniel.Garcia\Documents\Github\WebApplication3\src\WebApplication3" controller --force --controllerName ArticlesController --model WebApplication3.Models.Article --dataContext WebApplication3.Data.ApplicationDbContext --relativeFolderPath Controllers --controllerNamespace WebApplication3.Controllers --referenceScriptLibraries --useDefaultLayout
Finding the generator 'controller'...
Running the generator 'controller'...
Attempting to compile the application in memory
Attempting to figure out the EntityFramework metadata for the model and DbContext: Article
info: Microsoft.Extensions.DependencyInjection.DataProtectionServices[0]
      User profile is available. Using 'C:\Users\Daniel.Garcia\AppData\Local\ASP.NET\DataProtection-Keys' as key repository and Windows DPAPI to encrypt keys at rest.
The 'ClientId' option must be provided. StackTrace:There was an error creating the DbContext instance to get the model. No parameterless constructor defined for this object.

   at Microsoft.AspNetCore.Authentication.OAuth.OAuthMiddleware`1..ctor(RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, UrlEncoder encoder, IOptions`1 sharedOptions, IOptions`1 options)
No parameterless constructor defined for this object.   at Microsoft.AspNetCore.Authentication.Google.GoogleMiddleware..ctor(RequestDelegate next, IDataProtectionProvider dataProtectionProvider, ILoggerFactory loggerFactory, UrlEncoder encoder, IOptions`1 sharedOptions, IOptions`1 options)

--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.Extensions.Internal.ActivatorUtilities.ConstructorMatcher.CreateInstance(IServiceProvider provider)
   at Microsoft.Extensions.Internal.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, Object[] parameters)
   at Microsoft.VisualStudio.Web.CodeGeneration.ActionInvoker.<BuildCommandLine>b__6_0()   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass3_0.<UseMiddleware>b__0(RequestDelegate next)

   at Microsoft.Extensions.CommandLineUtils.CommandLineApplication.Execute(String[] args)   at Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.Build()

   at Microsoft.VisualStudio.Web.CodeGeneration.CodeGenCommand.Execute(String[] args)   at Microsoft.AspNetCore.Hosting.Internal.WebHost.BuildApplication()

   at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
   at Microsoft.VisualStudio.Web.CodeGeneration.EntityFrameworkCore.EntityFrameworkServices.TryCreateContextUsingAppCode(Type dbContextType, ModelType startupType)
RunTime 00:00:07.10

It seems to me the environment isn't set as Development when building the app in EntityFrameworkServices.TryCreateContextUsingAppCode. If I update my Startup constructor to always call builder.AddUserSecrets(); regardless of whether the environment is Development or not, then the scaffolding works fine.

//if (env.IsDevelopment())
//{
//    builder.AddUserSecrets();
//}
builder.AddUserSecrets();
@DaniJG
DaniJG commented Oct 9, 2016 edited

Another quick workaround would be setting things up so there are some dummy non-null values that will be overwritten in the dev environment with the values from the user secrets.

Just adding some dummy values to appsettings.json or registering the options like this:

    app.UseGoogleAuthentication(new GoogleOptions
    {
        ClientId = Configuration["GoogleClientId"] ?? "MissingClientId",
        ClientSecret = Configuration["GoogleClientSecret"] ?? "MissingClientSecret",
    });
@prafullbhosale
Contributor

This is fixed in 1.0.0-msbuild2-final and later

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