Add identity into an ASP.NET Core 2.1 MVC project and maintain full control of the Identity UI

To maintain full control over the Identity UI in an ASP.NET Core 2.1 MVC project, scaffold the identity using the Windows version of Visual Studio 2017.

Scaffold the Identity

  1. Right click the web application project and select Add, New Scaffolded Item
  2. On the left side of the Add Scaffold dialog select Identity, and click the Add button
  3. Select your existing Layout page, so the scaffolding will not overwrite it
  4. Select the Identity functions (files) you want to override, and click the down arrow to select your existing data context class
  5. The MY_SOLUTION\MY_WEBAPP\ScaffoldingReadme.txt file contains tasks to do to set up the Identity UI. Based on that
    1. Add the following lines to the Configure method of the Startup.cs file in this order. If a line is already in the file, make sure the order is correct.
      app.UseStaticFiles()
      app.UseAuthentication()
      app.UseMvc()
    2. Add to the ConfigureServices method of the Startup.cs file, if the line is not there.
      services.AddMvc()
  6. The Aeras, Identity, Pages, Account folder contains the .cshtml files you can modify.
  7. The code is in the .cshtml.cs file

Use your own SMTP server

To configure Identity to use you own SMTP server to send the Forgot my password and email verification emails, register a custom email sender.

  1. Add to the ConfigureServices method of the Startup.cs file
    // using Microsoft.AspNetCore.Identity.UI.Services;
    services.AddSingleton<IEmailSender, EmailSender>();
  2. Create the EmailSender class in the web application project
    // using Microsoft.AspNetCore.Identity.UI.Services;
    // using System.Threading.Tasks;
    public class EmailSender : IEmailSender
    {
        public Task SendEmailAsync(string sTo, string sSubject, string sMessage)
        {
            MyMessagingClass messaging = new MyMessagingClass();
    
            // Send an email message with SMTP
            messaging.MySendEmailMethod(sTo, sSubject, sMessage);
            
            return Task.CompletedTask;
        }
    }

For more information see https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.1&tabs=visual-studio#scaffold-identity-into-a-razor-project-with-authorization

 

 

Add jQuery DataTables grid to an ASP.NET Core MVC web application

ASP.NET does not provide sortable, searchable tables. jQuery DataTables is a popular way to display user-friendly data in an ASP.NET Core MVC web application.

Set up the environment

  1. Add the System.Linq.Dynamic.Core NuGet package to the web application
  2. Add the JsonOptions to the Startup.cs file
     using Newtonsoft.Json.Serialization;
  3. Add the AddJsonOptions to the services.AddMvc() section in the ConfigureServices() method of the Startup.cs file
     .AddJsonOptions(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());

Add the jQuery DataTables grid to the view

  1. Add the script and css references to the bottom of the view
    @section Scripts {
    	<!-- For the DataTables grid -->
    	<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.19/css/jquery.dataTables.css">
    	<script type="text/javascript" src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
    
    	<!-- Page-specific script -->
    	<script src="~/js/MY-CONTROLLER_MY-PAGE.js" asp-append-version="true"></script>
    }
  2. Add to the page-specific MY-CONTROLLER_MY-PAGE.js file to the wwwroot\js directory
    $(document).ready(function () {
    
      // Set up the DataTable grid
      $('#serverTable').DataTable();
    
    });
  3. Create a table with the same id referenced in the script
    @if (null != Model.ServerList) {
      <table id="serverTable" class="table table-striped table-bordered dt-responsive nowrap" width="100%">
        <thead>
          <tr>
            <th></th>
            <th>Name</th>
            ...
          </tr>
        </thead>
        <tbody>
          @foreach (ServerInstance instance in Model.ServerList) {
            <tr>
              <td><input type="checkbox" asp-for="@instance.Selected" /></td>
              <td>@instance.NameTag</td>
              ...
            </tr>
          }
        </tbody>
      </table>
    }

 

Error unprotecting the session cookie in an ASP.NET Core MVC application.

The new ASP.NET Core MVC framework automatically displays a message for the user to accept the application’s privacy policy. The default message is “Use this space to summarize your privacy and cookie use policy.” No cookies are saved in the user’s browser until they click the Accept button.

Even after accepting the terms, if the browser contains old, stale cookies the application may not be able to save cookies. The log contains

warn: Microsoft.AspNetCore.Session.SessionMiddleware[7]
Error unprotecting the session cookie.
System.Security.Cryptography.CryptographicException: The key … was not found in the key ring.

If the web application works in a new incognito window, clear the old cookies in your browser.

In Google Chrome

  1. In the Chrome menu select Clear Browsing Data
  2. On the Clear browsing data page select All time, and Cookies and other site data

 

 

Set the environment for an ASP.NET Core MVC web application

When the ASP.NET Core MVC web application starts, reads the name of the environment for an environment variable of the host computer. The compiled application contains the configuration for all supported environments, making possible to build and deploy the same artifact in every environment.

If the ASPNETCORE_ENVIRONMENT environment variable is not defined, the Production environment settings are loaded.

In Visual Studio the web application project sets the value on the Debug tab.

To set the environment on the server

Windows

To set the value globally that is preserved after restart

Command prompt

  1. Open the command prompt window and execute
    setx ASPNETCORE_ENVIRONMENT Development /M

PowerShell

  1. Open a PowerShell window and execute
    [Environment]::SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "Development", "Machine")

macOS

  1. Add to the .bashrc or .bash_profile file
    export ASPNETCORE_ENVIRONMENT=Development

 

Configure the ASP.NET Core MVC web application

Create the environment-specific appsettings.json files

  1. In the web application project click the arrow next to the appsettings.json file to reveal the Development configuration file
  2. Right-click the appsettings.Development.json file and select Copy

  3. Right click the web application project and select Paste

  4. Rename the appsettings – Copy.Development.json file to appsettings.Production.json

  5. The file will automatically move under the appsettings.json file

Edit the configuration files

  1. Open the appsettings.Production.json file and add the connection string
    {
        "ConnectionStrings": {
            "DefaultConnection": "Server=MY_DATABASE_URL;Database=MY_DATABASE_NAME;Username=MY_USERNAME;Password=MY_PASSWORD"
        }
    }
    
    

 

Return values to the controller in the model from the ASP.NET MVC view

When we create an ASP.NET MVC web application, the model (an object) is the easiest way to return values from the view to the controller.

For the view to be able to return the values in the model, make sure the model contains properties, not fields, for every value with { get; set; }

public class MyViewModel
{
    public string ID { get; set; }
}

Add the model to the view at the top of the .cshtml file

IMPORTANT!!! To return values for properties that do not have controls on the page, like IDs that are not displayed, add a hidden field to the view.

@model MyViewModel
<form  asp-action="Index" asp-controller="My">
    <input asp-for=@Model.ID type="hidden" >
</form>

Send the data in the model to the view from the get method in the controller

public class MyController : Controller
{
    public IActionResult Index()
    {
         MyViewModel model = new MyViewModel();
         model.ID = "MY_ID";
         return View(model);
    }
}

Read the value from the model in the post method of the controller and send the model back

public class MyController : Controller
{
    [HttpPost, ValidateAntiForgeryToken]
    public IActionResult Index(MyViewModel model)
    {
        string ID = model.ID;
...
        return View(model);
    }
}

 

The .NET MVC model has to have a parameterless constructor

When you create a class to be used as the model in a .NET MVC application, the class has to have a parameterless constructor. It is called during the POST when the user clicks the submit button of the form. If the class does not have a parameterless constructor, we will get the following generic error message. None of the breakpoints can help you to find the cause, and there is no entry in the event log.

The website cannot display the page
HTTP 500

Most likely causes:
•The website is under maintenance.
•The website has a programming error.

What you can try:
Refresh the page.
Go back to the previous page.
More information

There is already an open DataReader associated with this Command which must be closed first

When your MVC 5 web application page tries to read the database using the Entity Framework in a loop you may get the following error message:

InnerException: System.InvalidOperationException
HResult=-2146233079
Message=There is already an open DataReader associated with this Command which must be closed first.
Source=System.Data

This usually happens when a cshtml page receives an IEnumerable<> model from the database and makes repeated calls to retrieve the rows one-by-one in a foreach loop.

If your page does not display paged data, read the rows into a List  with the ToList() method and send the list to the cshtml page to iterate through it. This forces the application to read all appropriate rows with one call from the database.

Sometimes you can also eliminate the problem if you add the following to the connection string in the web.config file:

;multipleactiveresultsets=True