Search code examples
asp.net-core-mvcasp.net-mvc-scaffolding

Why does controller scaffolding requires a project that has individual user accounts


I am trying to understand how ASP.NET Core works by following this tutorial. It correctly specifies that, if I want to be able to harness the power of controller scaffolding, I have to create a project and specify Authentication as Individual user accounts.

When doing this, besides other things, it will generate this class: ApplicationDbContext : IdentityDbContext<ApplicationUser>. After several levels of inheritance, it inherits DbContext.

If I want to use a DbContext, why am I forced to inherit from IdentityDbContext and cannot simply inherit DbContext?

Is it possible to use my own authentication structures and still be able to work with controller scaffolding?


Solution

  • I just gave it a try and you can scaffold the controller but you will need to manually hook a few things first. The intro to EF Core might come handy in understanding how things have to be setup.

    • Start with a new MVC project and select No Authentication so it doesn't create the IdentityContext.
    • Then add to your project.json the dependencies needed for both EF Core and scaffolding:

      "dependencies": {
        ...
        //EF Core
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.EntityFrameworkCore.Tools": {
          "version": "1.0.0-preview2-final",
          "type": "build"
        },
        //Scaffolding
        "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
          "version": "1.0.0-preview2-final",
          "type": "build"
        },
        "Microsoft.VisualStudio.Web.CodeGenerators.Mvc": {
          "version": "1.0.0-preview2-final",
          "type": "build"
        }
      },
      
      "tools": {
        ...
        // EF Core
        "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
        //Scaffolding
        "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
          "version": "1.0.0-preview2-final",
          "imports": [
            "portable-net45+win8"
          ]
        }
      },
      
    • Create the model class that you want to use, for example:

      public class Customer
      {
          public int CustomerId { get; set; }
          [Required]
          public string Email { get; set; }        
          public string FirstName { get; set; }
          public string LastName { get; set; }        
      }
      
    • Now create a new empty DBContext class, for example:

      public class FooContext: DbContext
      {
          public FooContext(DbContextOptions<FooContext> options) : base(options)
          {
          }
      }
      
    • Then update Startup.ConfigureServices with your context class:

      services.AddDbContext<FooContext>(options =>
              options.UseSqlServer(Configuration["Data:FooContext:ConnectionString"]));
      
    • You also need a connection string in your appsettings.json. If starting a new project, you can add one using localdb:

        "Data": {
          "FooContext": {
            "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=FooContext-d69c2d45-f845-4069-92ed-2486567146cb;Trusted_Connection=True;MultipleActiveResultSets=true"
          }
        }
      
    • When using localdb, you can create the database by adding an initial migration and updating the db. Run these commands from the project root:

      dotnet ef migrations add initial
      dotnet ef database update
      

    Make sure you rebuild your project after these steps before using the scaffolding options.

    • You will then be able to right click the Controllers folder, select Add -> Controller and use the "MVC Controller with Views using Entity Framework" option. After you select your model and context classes, scaffolding will generate everything for you.
    • You can also avoid manually creating the DBContext class and let scaffolding generate it for you. Just select new DBContext class in the same scaffolding dialog and it will create the context class, add the connection string to appsettings.json and update Startup.ConfigureServices. (You will still need to create the db, for example adding and running an initial migration)

    If you run the project, you will see you can navigate to the generated index page, like /customers and see an empty list. There is one more thing though!

    • The scaffolded edit/create views rely on a partial named _ValidationScriptsPartial for adding the unobtrusive validation scripts, and as it doesn't exist in a new project, the edit/create view will throw an error.
    • You will need to manually create a new partial view ~/Views/Shared/_ValidationScriptsPartial.cshtml with the following contents:

      <environment names="Development">
          <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
          <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
      </environment>
      <environment names="Staging,Production">
          <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.14.0/jquery.validate.min.js"
                  asp-fallback-src="~/lib/jquery-validation/dist/jquery.validate.min.js"
                  asp-fallback-test="window.jQuery && window.jQuery.validator">
          </script>
          <script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.6/jquery.validate.unobtrusive.min.js"
                  asp-fallback-src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"
                  asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive">
          </script>
      </environment>