Tag Archives: App Service

Middleware in ASP .NET Core 3.1

By Shahed C on March 30, 2020

This is the thirteenth of a new series of posts on ASP .NET Core 3.1 for 2020. In this series, we’ll cover 26 topics over a span of 26 weeks from January through June 2020, titled ASP .NET Core A-Z! To differentiate from the 2019 series, the 2020 series will mostly focus on a growing single codebase (NetLearner!) instead of new unrelated code snippets week.

Previous post:

NetLearner on GitHub:

In this Article:

M is for Middleware in ASP .NET Core

If you’ve been following my blog series (or if you’ve done any work with ASP .NET Core at all), you’ve already worked with the Middleware pipeline. When you create a new project using one of the built-in templates, your project is already supplied with a few calls to add/configure middleware services and then use them. This is accomplished by adding the calls to the Startup.cs configuration methods.

ASP .NET Core 3.1  Middleware Pipeline
ASP .NET Core 3.1 Middleware Pipeline

The above diagram illustrates the typical order of middleware layers in an ASP .NET Core web application. The order is very important, so it is necessary to understand the placement of each request delegate in the pipeline.

  • Exception Handling
  • HTTPS Redirection
  • Static Files
  • Cookie Policy
  • Routing
  • Authentication
  • Authorization
  • Session
  • Endpoint Routing

How It Works

When an HTTP request comes in, the first request delegate handles that request. It can either pass the request down to the next in line or short-circuit the pipeline by preventing the request from propagating further. This is use very useful across multiple scenarios, e.g. serving static files without the need for authentication, handling exceptions before anything else, etc.

The returned response travels back in the reverse direction back through the pipeline. This allows each component to run code both times: when the request arrives and also when the response is on its way out.

Here’s what the Configure() method may look like, in a template-generated Startup.cs file:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy(); // manually added

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseSession(); // manually added

    app.UseEndpoints(endpoints =>
    {
        // map MVC routes, Razor Pages, Blazor Hub
    });
}

You may add calls to UseCookiePolicy() and UseSession()  manually, as these aren’t included in the template-generated project. The endpoint configuration will vary depending on the type of project template you start with: MVC, Razor Pages or Blazor, which you can mix and match. You may also enable authentication and HTTPS when creating the template.

Adding a new project in VS2019

In order to configure the use of the Session middleware, you may add the following code in your ConfigureServices() method:

public void ConfigureServices(IServiceCollection services)
{
...
    services.AddDistributedMemoryCache();
    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromSeconds(10);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    });
...
}

The calls to AddDistributedMemoryCache() and AddSession() ensure that we have enabled a (memory cache) backing store for the session and then prepared the Session middleware for use.

Built-In Middleware

The information below explains how the built-in middleware works, and why the order is important. The UseXYZ() methods are merely extension methods that are prefixed with the word “Use” as a useful convention, making it easy to discover Middleware components when typing code. Keep this in mind mind when developing custom middleware.

Exception Handling:

  • UseDeveloperExceptionPage() & UseDatabaseErrorPage(): used in development to catch run-time exceptions
  • UseExceptionHandler(): used in production for run-time exceptions

Calling these methods first ensures that exceptions are caught in any of the middleware components that follow. For more information, check out the detailed post on Handling Errors in ASP .NET Core, earlier in this series.

HSTS & HTTPS Redirection:

  • UseHsts(): used in production to enable HSTS (HTTP Strict Transport Security Protocol) and enforce HTTPS.
  • UseHttpsRedirection(): forces HTTP calls to automatically redirect to equivalent HTTPS addresses.

Calling these methods next ensure that HTTPS can be enforced before resources are served from a web browser. For more information, check out the detailed post on Protocols in ASP .NET Core: HTTPS and HTTP/2.

Static Files:

  • UseStaticFiles(): used to enable static files, such as HTML, JavaScript, CSS and graphics files. Called early on to avoid the need for authentication, session or MVC middleware.

Calling this before authentication ensures that static files can be served quickly without unnecessarily triggering authentication middleware. For more information, check out the detailed post on JavaScript, CSS, HTML & Other Static Files in ASP .NET Core.

Cookie Policy:

  • UseCookiePolicy(): used to enforce cookie policy and display GDPR-friendly messaging

Calling this before the next set of middleware ensures that the calls that follow can make use of cookies if consented. For more information, check out the detailed post on Cookies and Consent in ASP .NET Core.

Authentication, Authorization & Sessions:

  • UseAuthentication(): used to enable authentication and then subsequently allow authorization.
  • UseSession(): manually added to the Startup file to enable the Session middleware.

Calling these after cookie authentication (but before the endpoint routing middleware) ensures that cookies can be issued as necessary and that the user can be authenticated before the endpoint routing kicks in. For more information, check out the detailed post on Authentication & Authorization in ASP .NET Core.

Endpoint Routing:

  • UseEndpoints(): usage varies based on project templates used for MVC, Razor Pages and Blazor.
  • endpoints.MapControllerRoute(): set the default route and any custom routes when using MVC.
  • endpoints.MapRazorPages(): sets up default Razor Pages routing behavior
  • endpoints.BlazorHub(): sets up Blazor Hub

To create your own custom middleware, check out the official docs at:

Branching out with Run, Map & Use

The so-called “request delegates” are made possible with the implementation of three types of extension methods:

  • Run: enables short-circuiting with a terminal middleware delegate
  • Map: allows branching of the pipeline path
  • Use: call the next desired middleware delegate

If you’ve tried out the absolute basic example of an ASP .NET Core application (generated from the Empty template), you may have seen the following syntax in your Startup.cs file.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    ...
    app.UseEndpoints(endpoints => 
    {
        endpoints.MapGet("/", async (context) =>
        {
            await context.Response.WriteAsync("Hello World!");
        });
     }); 
}

You can use an alternative approach to terminate the pipeline, by calling app.Use() and then triggering the next middleware component with a call to next(context) as shown below. If there is no call to next(), then it essentially short-circuits the middleware pipeline.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ...
    // Approach 1: terminal middleware
    app.Use(next => async context =>
    {
        if (context.Request.Path == "/")
        {
            await context.Response.WriteAsync("Hello and goodbye!");
            return;
        }
        await next(context);
    });
    app.UseRouting();
    app.UseEndpoints(...); // Approach 2: routing
}

Finally, there is the Map() method, which creates separate forked paths/branches for your middleware pipeline and multiple terminating ends. Check out the official documentation on mapped branches for more information:

In the Configure() method, each call to app.Map() establishes a separate branch that can be triggered with the appropriate relative path. Each handler method then contains its own terminating map.Run() method.

In the official sample:

  • accessing /map1 in an HTTP request will call HandleMapTest1()
  • accessing /map2 in an HTTP request will call HandleMapTest2()
  • accessing the / root of the web application will call the default terminating Run() method
  • specifying an invalid path will also call the default Run() method

References

Key Vault for ASP .NET Core 3.1 Web Apps

By Shahed C on March 16, 2020

This is the eleventh of a new series of posts on ASP .NET Core 3.1 for 2020. In this series, we’ll cover 26 topics over a span of 26 weeks from January through June 2020, titled ASP .NET Core A-Z! To differentiate from the 2019 series, the 2020 series will mostly focus on a growing single codebase (NetLearner!) instead of new unrelated code snippets week.

Previous post:

NetLearner on GitHub:

In this Article:

K is for Key Vault for ASP .NET Core 3.1 Web Apps

In my 2018 blog series, we covered the use of User Secrets for your ASP .NET Core web application projects. This is useful for storing secret values locally during development. However, we need a cloud-based scalable solution when deploying web apps to Azure. This article will cover Azure Key Vault as a way to store and retrieve sensitive information in Azure and access them in your web application.

You will need an Azure subscription to create and use your own Key Vault and App Service.

Using Key Vault from Azure for your Web Apps
Using Key Vault from Azure for your Web Apps

Setting up Key Vault in Azure

Before you can use Key Vault in the cloud, you will have to set it up in Azure for your use. This can be done in various ways:

  • Azure Portal: log in to the Azure Portal in a web browser.
  • Azure CLI: use Azure CLI commands on your development machine.
  • Visual Studio: use the VS IDE on your development machine.

To use the Azure Portal: create a new resource, search for Key Vault, click Create and then follow the onscreen instructions. Enter/select values for the following for the key vault:

  • Subscription: select the desired Azure subscription
  • Resource Group: select a resource group or create a new one
  • Name: alphanumeric, dashes allowed, cannot start with number
  • Region: select the desired region
  • Pricing Tier: select the appropriate pricing tier (Standard, Premium)
  • Soft Delete: enable/disable
  • Retention Period: enter retention period (in days)
  • Purge protection: enable/disable
Key Vault creation screen on Azure Portal
Key Vault creation screen on Azure Portal

If you need help with the Azure Portal, check out the official docs at:

To use the Azure CLI: authenticate yourself, run the appropriate commands to create a key vault, add keys/secrets/certificates and then authorize an application to use your keys/secrets.

To create a new key vault, run “az keyvault create” followed by a name, resource group and location, e.g.

az keyvault create --name "MyKeyVault" --resource-group "MyRG" --location "East US"

To add a new secret, run “az keyvault secret set“, followed by the vault name, a secret name and the secret’s value, e.g.

az keyvault secret set --vault-name "MyKeyVault" --name "MySecretName" --value "MySecretValue"

If you need help with the Azure CLI, check out the official docs at:

To use Visual Studio, right-click your project in Solution Explorer, click Add | Connected Service, select “Secure Secrets with Azure Key Vault” and follow the onscreen instructions.

If you need help with Visual Studio, check out the official docs at:

Add a Connected Service in Visual Studio
Add a Connected Service in Visual Studio

Once created, the Key Vault and its secret names (and values) can be browsed in the Azure Portal, as seen in the screenshots below:

Key Vault details
Key Vault creation in Azure Portal
Key Vault creation in Azure Portal
Creating a secret for Azure Key Vault
Creating a secret for Azure Key Vault

NOTE: If you create a secret named “Category1–MySecret”, this syntax specifies a category “Category1” that contains a secret “MySecret.”

Retrieving Key Vault Secrets

Before you deploy your application to Azure, you can still access the Key Vault using Visual Studio during development. This is accomplished by using your Visual Studio sign-in identity. Even if you have multiple levels of configuration to retrieve a secret value, the app will use the config sources in the following order:

  • first, check the Key Vault.
  • if Key Vault not found, check secrets.json file
  • finally, check the appsettings.json file.

There are a few areas in your code you need to update, in order to use your Key Vault:

  1. Install the nuget packages AppAuthentication, KeyVault and AzureKeyVault NuGet libraries.
    • Microsoft.Azure.Services.AppAuthentication
    • Microsoft.Azure.KeyVault
    • Microsoft.Extensions.Configuration.AzureKeyVault
  2. Update Program.cs to configure your application to use Key Vault
  3. Inject an IConfiguration object into your controller (MVC) or page model (Razor Pages, shown below)
  4. Access specific secrets using the IConfiguration object, e.g. _configuration[“MySecret”]

Below is an example of Program.cs using the WebHostBuilder’s ConfigureAppConfiguration() method to configure Key Vault. The keyVaultEndpoint is the fully-qualified domain name of your Key Vault that you created in Azure.

...
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureKeyVault;
...
public static IHostBuilder CreateHostBuilder(string[] args) =>
   Host.CreateDefaultBuilder(args)
      .ConfigureAppConfiguration((ctx, builder) =>
      {
         var keyVaultEndpoint = GetKeyVaultEndpoint();
         if (!string.IsNullOrEmpty(keyVaultEndpoint))
         {
            var azureServiceTokenProvider = new AzureServiceTokenProvider();
            var keyVaultClient = new KeyVaultClient(
               new KeyVaultClient.AuthenticationCallback(
                  azureServiceTokenProvider.KeyVaultTokenCallback));
               builder.AddAzureKeyVault(
                  keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
         }
      }
   ).ConfigureWebHostDefaults(webBuilder =>
   {
      webBuilder.UseStartup<Startup>();
   }); 

private static string GetKeyVaultEndpoint() => "https://<VAULT_NAME>.vault.azure.net/";

NOTEPlease note that usage of Web Host Builder in ASP .NET Core 2.x has been replaced by the Generic Host Builder in .NET Core 3.x.

Below is an example of of a Page Model for a Razor Page, e.g. SecretPage.cshtml.cs in the sample app

...
using Microsoft.Extensions.Configuration;
public class SecretPageModel : PageModel
{
   public IConfiguration _configuration { get; set; }
   public string Message1 { get; set; }
   public string Message2 { get; set; }
   public string Message3 { get; set; } 

   public SecretPageModel(IConfiguration configuration)
   {
      _configuration = configuration;
   }

   public void OnGet()
   {
      Message1 = "My 1st key val = " + _configuration["MyKeyVaultSecret"];
      Message2 = "My 2nd key val = " + _configuration["AnotherVaultSecret"];
      Message3 = "My 3nd key val ? " + _configuration["NonExistentSecret"];
   }
}

In the above code, the configuration object is injected into the Page Model’s SecretPageModel()The values are retrieved from the collection in the OnGet() method and assigned to string properties. In the code below, the string properties are accessed from the model class in the corresponding Razor Page, SecretPage.cshtml.

@page
@model KeyVaultSample.Pages.SecretPageModel
...
<p>
 @Model.Message1
</p> 

<p>
 @Model.Message2
</p> 

<p>
 @Model.Message3
</p>

Finally, viewing the page allows you to navigate to the Secret Page to view the secret values. Note that I’ve only created 2 secret values before deploying this instance, so the 3rd value remains blank (but without generating any errors).

 SecretPage showing secrets retrieved from Key Vault
SecretPage showing secrets retrieved from Key Vault

Managed Service Identity

There are multiple ways to deploy your ASP .NET Core web app to Azure, including Visual Studio, Azure CLI or a CI/CD pipeline integrated with your source control system. If you need help deploying to Azure App Service, check out the following article from this blog series:

You can set up your Managed Service Identity in various ways:

  • Azure Portal: log in to the Azure Portal and add your app
  • Azure CLI: use Azure CLI commands to set up MSI
  • Visual Studio: use the VS IDE while publishing

Once you’ve created your App Service (even before deploying your Web App to it), you can use the Azure Portal to add your app using Managed Service Identity. In the screenshots below, I’ve added my sample app in addition to my own user access.

  • In the Access Policies section of the Key Vault, you may add one or more access policies.
  • In the Identity section of the App Service, you may update the System-Assigned setting to “On” and make a note of the Object ID, which is defined as a “Unique identifier assigned to this resource, when it’s registered with Azure Active Directory
Key Vault Access Policies
Key Vault Access Policies
Key Vault App Service Identity
Key Vault App Service Identity

To use the Azure CLI to authorize an application to access (or “get”) a key vault, run “az keyvault set-policy“, followed by the vault name, the App ID and specific permissions. This is equivalent to enabling the Managed Service Identity for your Web App in the Azure Portal.

az keyvault set-policy --name "MyKeyVault" --spn <APP_ID> --secret-permissions get

To use Visual Studio to use your key vault after deployment, take a look at the Publish screen when deploying via Visual Studio. You’ll notice that there is an option to Add Dependencies, including Azure Key Vault. After you’ve added and enabled Key Vault for your application, the option will change to say “Configure” and “Manage Key Vault”.

Add Dependencies during Publish from Visual Studio
Add Dependencies during Publish from Visual Studio
Select Azure Key Vault from list of dependencies
Select Azure Key Vault from list of dependencies

After adding via Visual Studio during the Publish process, your Publish Profile (profile – Web Deploy.pubxml) and Launch Settings profiles (launchSettings.json) should contain the fully qualified domain name for your Key Vault in Azure. You should not include these files in your source control system.

References

EF Core Relationships in ASP .NET Core 3.1

By Shahed C on February 3, 2020

This is the fifth of a new series of posts on ASP .NET Core 3.1 for 2020. In this series, we’ll cover 26 topics over a span of 26 weeks from January through June 2020, titled ASP .NET Core A-Z! To differentiate from the 2019 series, the 2020 series will mostly focus on a growing single codebase (NetLearner!) instead of new unrelated code snippets week.

Previous post:

NetLearner on GitHub:

In this Article:

E is for EF Core Relationships

In my 2018 series, we covered EF Core Migrations to explain how to add, remove and apply Entity Framework Core Migrations in an ASP .NET Core web application project. In this article, we’ll continue to look at the newer 2020 NetLearner project, to identify entities represented by C# model classes and the relationships between them.

NOTE: Please note that NetLearner is a work in progress as of this writing, so its code is subject to change. The UI web apps still needs work (and will be updated at a later date) but the current version has the following models with the relationships shown below:

NetLearner database diagram
NetLearner database diagram

Classes and Relationships

The heart of the application is the LearningResource class. This represents any online learning resource, such as a blog post, single video, podcast episode, ebook, etc that can be accessed with a unique URL.

public class LearningResource
{
    public int Id { get; set; }

    [DisplayName("Resource")]
    public string Name { get; set; }


    [DisplayName("URL")]
    [DataType(DataType.Url)]
    public string Url { get; set; }

    public int ResourceListId { get; set; }
    [DisplayName("In List")]
    public ResourceList ResourceList { get; set; }

    public ContentFeed ContentFeed { get; set; }

    public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
} 

The ContentFeed class represents the RSS Feed (or channel information) for an online resource, a URL that can be used to retrieve more information about the online resource, if available.

public class ContentFeed
{
    public int Id { get; set; }

    [DisplayName("Feed URL")]
    public string FeedUrl { get; set; }

    public int LearningResourceId { get; set; }
    public LearningResource LearningResource { get; set; }
}

The ResourceList class represents a logical container for learning resources in the system. It is literally a list of items, where the items are your learning resources.

public class ResourceList
{
    public int Id { get; set; }

    public string Name { get; set; }

    public List<LearningResource> LearningResources { get; set; }
} 

The TopicTag class represents a single “tag” value that can be used to categorize online resources. Possibly values could be “.NET Core”, “ASP.NET Core” and so on.

public class TopicTag
{
    public int Id { get; set; }

    [DisplayName("Tag")]
    public string TagValue { get; set; }

    public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
} 

At this point, you may have noticed both the LearningResource and TopicTag classes contain a List<T> property of LearningResourceTopicTag. If you browse the database diagram, you will notice that this table appears as a connection between the two aforementioned tables, to establish a many-to-many relationship. (more on this later)

The following diagram shows an example of how the a LearningResource (e.g. link to a doc/video) is a part of a ResourceList, while each LearningResource also has a link back to its root site, channel or RSS feed (via ContentFeed).

One to One

Having looked through the above entities and relationships, we can see that each LearningResource has a ContentFeed. This is an example of a 1-to-1 relationship. For example:

  • Learning Resource = Wake Up and Code! blog site
  • Content Feed = RSS Feed for blog site

In the two classes, we see the following code:

public class LearningResource
{
public int Id { get; set; }

[DisplayName("Resource")]
public string Name { get; set; }


[DisplayName("URL")]
[DataType(DataType.Url)]
public string Url { get; set; }

public int ResourceListId { get; set; }
[DisplayName("In List")]
public ResourceList ResourceList { get; set; }

public ContentFeed ContentFeed { get; set; }

public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
}
public class ContentFeed
{
public int Id { get; set; }

[DisplayName("Feed URL")]
public string FeedUrl { get; set; }

public int LearningResourceId { get; set; }
public LearningResource LearningResource { get; set; }
}

Each Learning Resource has a corresponding Content Feed, so the LearningResource class has a property for ContentFeed. That’s pretty simple. But in the  ContentFeed class, you don’t necessarily need a property pointing back to the  LearningResource . In fact, all you need is a  LearningResourceId property. EF Core will ensure that LearningResource.Id points to ContentFeed.LearningResourceId in the database. But to help with object-property navigation in your code, it is useful to include an actual LearningResource object in the ContentFeed class to point back to LearningResource.

One to One Relationship
One to One Relationship

Another way of looking at the One-to-One relationship is to view the constraints of each database entity in the visuals below. Note that both tables have an Id field that is a Primary Key (inferred by EF Core) while the ContentFeeds table also has a Foreign Key for the LearningResourceId field used for the constraint in the relationship.

LearningResources table
LearningResources table
ContentFeeds table
ContentFeeds table
One to One Relationship
One to One Relationship

One to Many

Next, let’s take a look at the One-to-Many relationship for each ResourceList that has zero or more LearningResources. For example:

  • Resource List = ASP .NET Core Blogs (parent container)
  • Learning Resource = ASP .NET Core A-Z Blog Series (single URL)

In the two classes, we see the following code:

public class ResourceList
{
public int Id { get; set; }

public string Name { get; set; }

public List<LearningResource> LearningResources { get; set; }
}
public class LearningResource
{
public int Id { get; set; }

[DisplayName("Resource")]
public string Name { get; set; }


[DisplayName("URL")]
[DataType(DataType.Url)]
public string Url { get; set; }

public int ResourceListId { get; set; }
[DisplayName("In List")]
public ResourceList ResourceList { get; set; }

public ContentFeed ContentFeed { get; set; }

public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
}

Each Resource List has zero or more Learning Resources, so the ResourceList class has a List<T> property for LearningResources. This is even simpler than the previously described 1-to-1 relationship. In the LearningResource class, you don’t necessarily need a property pointing back to the ResourceList. But once again, to help with object-property navigation in your code, it is useful to include an actual ResourceList object in the LearningResource class to point back to ResourceList.

One to Many Relationship
One to Many Relationship

Another way of looking at the One-to-Many relationship is to view the constraints of each database entity in the visuals below. Note that both tables have an Id field that is a Primary Key (once again, inferred by EF Core) while the ResourceLists table also has a Foreign Key for the  ResourceListsId field used for the constraint in the relationship.

One to Many Constraint
One to Many Constraint

Many to Many

Finally, let’s also take a look at a Many-to-Many relationship, for each TopicTag and LearningResource, either of which can have many of the other. For example:

  • Topic Tag = “ASP .NET Core” (tag as a text description)
  • Learning Resource = Specific blog post on site (single URL)

This relationship is a little more complicated than all of the above, as we will need a “join table” to connect the two tables in question. Not only that, we will have to describe the entity in the C# code with connections to both tables we would like to connect with this relationship.

In the two classes we would like to connect, we see the following code:

public class TopicTag
{
    public int Id { get; set; }

    [DisplayName("Tag")]
    public string TagValue { get; set; }

    public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
} 
public class LearningResource
{
public int Id { get; set; }

[DisplayName("Resource")]
public string Name { get; set; }


[DisplayName("URL")]
[DataType(DataType.Url)]
public string Url { get; set; }

public int ResourceListId { get; set; }
[DisplayName("In List")]
public ResourceList ResourceList { get; set; }

public ContentFeed ContentFeed { get; set; }

public List<LearningResourceTopicTag> LearningResourceTopicTags { get; set; }
}

Next, we have the LearningResourceTopicTag class as a “join entity” to connect the above:

public class LearningResourceTopicTag
{
    public int LearningResourceId { get; set; }
    public LearningResource LearningResource { get; set; }

    public int TopicTagId { get; set; }
    public TopicTag TopicTag { get; set; }

}

This special class has the following properties:

  • LearningResourceId: integer value, pointing back to LearningResource.Id
  • LearningResource: optional “navigation” property, reference back to connected LearningResource entity
  • TopicTagId: integer value, pointing back to TopicTag.Id
  • TopicTag:  optional “navigation” property, reference back to connected TopicTag entity

To learn more about navigation properties, check out the official docs at:

Many to Many Relationship
Many to Many Relationship

Another way of looking at the Many-to-Many relationship is to view the constraints of each database entity in the visuals below. Note that the two connected tables both have an Id field that is a Primary Key (yes, inferred by EF Core!) while the LearningResourceTopicTag table has a Composite Key for the TopicTagId and LearningResourceId fields used for the constraints in the relationship.

Constraints for LearningResources
Constraints for LearningResources
 Constraints for TopicTags
Constraints for TopicTags

The composite key is described in the LibDbContext class inside the OnModelCreating() method:

public class LibDbContext : IdentityDbContext
{
    ...
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
       ...
       modelBuilder.Entity<LearningResourceTopicTag>()
        .HasKey(lrtt => new { lrtt.LearningResourceId, lrtt.TopicTagId });
    }
}

Here, the HasKey() method informs EF Core that the entity LearningResourceTopicTag has a composite key defined by both LearningResourceId and TopicTagId.

References

For more information, check out the list of references below.

For detailed tutorials that include both Razor Pages and MVC, check out the official tutorials below:

Deploying ASP .NET Core 3.1 to Azure App Service

By Shahed C on January 27, 2020

This is the fourth of a new series of posts on ASP .NET Core 3.1 for 2020. In this series, we’ll cover 26 topics over a span of 26 weeks from January through June 2020, titled ASP .NET Core A-Z! To differentiate from the 2019 series, the 2020 series will mostly focus on a growing single codebase (NetLearner!) instead of new unrelated code snippets week.

Previous post:

NetLearner on GitHub:

In this Article:

D is for Deploying to Azure App Service

In this article, we’ll explore several options for deploying an ASP .NET Core web app to Azure App Service in the cloud. From the infamous Right-Click-Publish to fully automated CI/CD, you’ll learn about the latest Deployment Center option in the Azure Portal for App Service for web apps.

NOTE: If you’re looking for information on deploying to Docker or Kubernetes, please check out the following docs instead:

Right-Click Publish (aka Friends Don’t Let Friends Right-Click Publish)

If you’ve made it this far, you may be thinking one of the following:
a. “Hey, this is how I deploy my web apps right now!”
or
b. “Hey wait a minute, I’ve heard that you should never do this!”

Well, there is a time and place for right-click publish. There have been many debates on this, so I won’t go into the details, but here are some resources for you to see what others are saying:

So, what’s a web developer to do? To quote from the aforementioned MSDN article, “Continuing with the theme of prototyping and experimenting, right click publish is the perfect way for existing Visual Studio customers to evaluate Azure App Service (PAAS). By following the right click publish flow you get the opportunity to provision new instances in Azure and publish your application to them without leaving Visual Studio:”

In other words, you can use this approach for a quick test or demo, as shown in the screenshots below for Visual Studio.

  1. Right-click your ASP .NET Core web app project in Solution Explorer and select Publish.
  2. Click the Start button on the screen that appears and follow the onscreen instructions.
  3. Ensure that you’re logged in to the correct Azure subscription account you want to publish to.
Right-click, Publish from Solution Explorer
Right-click, Publish from Solution Explorer
Pick a Publish Target
Pick a Publish Target

Web Apps in the Azure Portal

In the screenshot above, you may notice an option to “Import Profile” using the button on the lower left. This allows you to import a Web App profile file that was generated by exporting it from an existing Azure Web App. To grab this profile file, simply navigate to your existing Web App in the Azure Portal and click on “Get publish profile” in the top toolbar of your Web App, shown below:

Get Publish Profile
Get Publish Profile

If you want to create a new Web App in Azure starting with the Azure Portal, follow the instructions below:

  1. Log in to the Azure at https://portal.azure.com
  2. On the top left, click + Create a resource
  3. Select “Web App” or search for it if you don’t see it.
  4. Enter/select the necessary values:
    • Subscription (select a subscription)
    • Resource Group (create or use existing to group resources logically)
    • Web App name (enter a unique name)
    • Publish (Code or Docker Image)
    • Runtime stack (.NET Core)
    • App Service Plan (create or use existing to set location and pricing tier)
    • OS (Windows or Linux)
    • Region (e.g. East US)
  5. Click Next through the screens and then click the Create button to complete the creation of your new Web App.
Create New Web App
Create New Web App

Now you can deploy to this Web App using any method you choose.

Runtime Options

If you like to stay ahead of ASP .NET Core releases, you may be using a pre-release version of the runtime. As of this writing, the latest stable version of ASP .NET Core is version 3.1, which is already available on Azure. If you’re looking for future preview releases, Azure App Service also has an option to install an Extension for preview runtimes.

To find the proper runtime:

  1. Navigate to your Web App in the Azure Portal.
  2. Click on Extensions under Development Tools.
  3. Click + Add to add a new extension.
  4. Choose an extension to configure required settings.
  5. Accept the legal terms and complete the installation.
Add Extension
Add Extension

Your options may include both 32-bit (x86) and 64-bit (x64) versions of the ASP .NET Core runtime and any preview versions of future releases. When planning ahead for multiple environments, you also have the option to deploy to Deployments Slots. This feature is available in StandardPremium or Isolated App Service Plan tiers and will covered in a future blog post in this series.

If you’re interested in Deployment Slots right now, check out the official docs at:

Deployment Center

In the list of features for your Web App, you will find an option to open up the new Deployment Center. Note that this has replaced the old Deployment Options. Let’s go over each of these options:

  1. Azure Repos
  2. Github
  3. Bitbucket
  4. Local Git
  5. OneDrive
  6. Dropbox
  7. External
  8. FTP
Deployment Options in Deployment Center
Deployment Options in Deployment Center
More Deployment Options
More Deployment Options

If you choose Azure Repos, you can set up your web app’s CI (Continuous Integration) system with an Azure Repo, which is part of Microsoft’s Azure DevOps services (formerly known as VSTS, aka Visual Studio Team Services). You will have options for using App Service as a Kudu build server or Azure Pipelines as your CI build system.

 Azure Repos choices: Kudu or Pipelines?
Azure Repos choices: Kudu or Pipelines?

If you choose Github or BitBucket or even a local Git account, you’ll have the ability to authorize that account to publish a specific repo, every time a developer pushes their code.

 Authorize Github/Bitbucket
Authorize Github/Bitbucket

If you choose OneDrive or DropBox, you’ll have ability to authorize your App Service to pick up files deployed to a shared folder in either location.

 Authorize OneDrive/DropBox
Authorize OneDrive/DropBox

You may also select an External repo or FTP source. To learn more about Azure Repos and Azure Pipelines, check out the official docs:

GitHub Repos (includes FREE option!)

If you’ve been using GitHub for public open-source projects or private projects on paid accounts, now is a great to time to create private repositories for free! In 2019, GitHub started offering free unlimited private repos, limited to 3 collaborators. This new free option comes with issue/bug tracking and project management as well.

For more information on GitHub pricing, check out their official pricing page:

 GitHub pricing: Free vs Pro, Team and Enterprise
GitHub pricing: Free vs Pro, Team and Enterprise

Now you can easily set up your starter projects in a private GitHub repository and take advantage of the aforementioned CI/CD setup without having to choose between paying a GitHub fee or making all your repos public.

CLI Commands

If you wish to publish to Azure App service using CLI (Command Line Interface) Commands, you may use the following commands, where you can choose a name for your Web App, Resource Group, App Sevice Plan, etc. Single-letter flags are usually preceded by a single hyphen, while flags spelled out with completed words are usually preceded by two hyphens.

First, install the Azure CLI in case you don’t have it already:

Authenticate yourself:

> az login

Create a new resource group:

> az group create -l <LOCATION> -n <RSG>
> az group create --location <LOCATION> --name <RSG>

Create a new App Service Plan, where <SKUCODE> sku may be F1 or FREE, etc

> az appservice plan create -g <RSG> -n <ASP> --sku <SKUCODE> 
> az appservice plan create --resource-group <RSG> --name <ASP> --sku <SKUCODE>

From the documentation, the SKU Codes include: F1(Free), D1(Shared), B1(Basic Small), B2(Basic Medium), B3(Basic Large), S1(Standard Small), P1V2(Premium V2 Small), PC2 (Premium Container Small), PC3 (Premium Container Medium), PC4 (Premium Container Large), I1 (Isolated Small), I2 (Isolated Medium), I3 (Isolated Large).

Create a new Web App within a Resource Group, attached to an App Service Plan:

> az webapp create -g <RSG> -p <ASP> -n <APP> 
> az webapp create --resource-group <RSG> --plan <ASP> --name <APP>

The above command should create a web app available at the following URL:

  • http://<APP>.azurewebsites.net

To push your commits to a Git Repo and configure for App Service Deployment, use the following CLI commands:

Create a new Git repo or reinitialize an existing one:

> git init

Add existing files to the index:

> git add .

Commit your changes with a commit message:

> git commit -m "<COMMIT MESSAGE>“

Set your FTP credentials and Git deployment credentials for your Web App:

> az webapp deployment user set --user-name <USER>

Configure an endpoint and add it as a git remote.

> az webapp deployment source config-local-git -g <RSG> -n <APP> --out tsv  
> az webapp deployment source config-local-git --resource-group <RSG> --name <APP> --out tsv
> git remote add azure <GIT URL>

The value for GIT URL is the value of the Git remote, e.g.

  • https://<USER>@<APP>.scm.azurewebsites.net/<APP>.git

Finally, push to the Azure remote to deploy your Web App:

> git push azure master

For more information on CLI Commands for Git and Azure App Service, check out the official docs:

Azure DevOps and YAML

Wait, what about Azure DevOps and YAML and Pipelines?

Since this is an A-Z series, you will have to wait for “Y is for YAML” to get more detailed information on constructing your build pipeline using YAML in Azure DevOps. If you can’t wait that long, feel free to check out the following .yml sample I uploaded for use with an ASP .NET Core 3.1:

If you’re reading this after June 2020, simply jump right to the “Y is for YAML” post in the 2020 A-Z series.

BONUS: for Azure SQL Database Deployment, watch the following video on MSDN Channel 9:

References

Zero-Downtime* Web Apps for ASP .NET Core

By Shahed C on July 1, 2019

This is the twenty-sixth of a series of posts on ASP .NET Core in 2019. In this series, we’ve cover 26 topics over a span of 26 weeks from January through June 2019, titled A-Z of ASP .NET Core!

ASPNETCoreLogo-300x267 A – Z of ASP .NET Core!

In this Article:

Z is for Zero-Downtime* Web Apps for ASP .NET Core

If you’ve made it this far in this ASP .NET Core A-Z series, hopefully you’ve learned about many important topics related to ASP .NET Core web application development. As we wrap up this series with a look at tips and tricks to attempt zero-downtime, this last post itself has its own lettered A-F mini-series: Availability, Backup & Restore, CI/CD, Deployment Slots, EF Core Migrations and Feature Flags.

Zero-Downtime-Deployment

* While it may not be possible to get 100% availability 24/7/365, you can ensure a user-friendly experience free from (or at least with minimal) interruptions, by following a combination of the tips and tricks outlined below. This write-up is not meant to be a comprehensive guide. Rather, it is more of an outline with references that you can follow up on, for next steps.

Availability

To improve the availability of your ASP .NET Core web app running on Azure, consider running your app in multiple regions for HA (High Availability). To control traffic to/from your website, you may use Traffic Manager to direct web traffic to a standby/secondary region, in case the primary region is unavailable.

Consider the following 3 options, in which the primary region is always active and the secondary region may be passive (as a hot or cold standby) or active. When both are active, web requests are load-balanced between the two regions.

 Options Primary Region Secondary Region
A Active Passive, Hot Standby
B Active Passive, Cold Standby
C Active Active

If you’re running your web app in a Virtual Machine (VM) instead of Azure App Service, you may also consider Availability Sets. This helps build redundancy in your Web App’s architecture, when you have 2 or more VMs in an Availability Set. For added resiliency, use Azure Load Balancer with your VMs to load-balance incoming traffic. As an alternative to Availability Sets, you may also use Availability Zones to counter any failures within a datacenter.

Backup & Restore

Azure’s App Service lets you back up and restore your web application, using the Azure Portal or with Azure CLI commands. Note that this requires your App Service to be in at least the Standard or Premium tier, as it is not available in the Free/Shared tiers. You can create backups on demand when you wish, or schedule your backups as needed. If your site goes down, you can quickly restore your last good backup to minimize downtime.

Zero-Downtime-Backups

In addition to the app itself, the backup process also backs up the Web App’s configuration, file contents and the database connected to your app. Database types include SQL DB (aka SQL Server PaaS), MySQL and PostgreSQL. Note that these backups include a complete backup, and not incremental/delta backups.

Continuous Integration & Continuous Deployment

In the previous post, we covered CI/CD with YAML pipelines. Whether you have to fix an urgent bug quickly or just deploy a planned release, it’s important to have a proper CI/CD pipeline. This allows you to deploy new features and fixes quickly with minimal downtime.

YAML-New-Pipeline

Deployment Slots

Whether you’re deploying your Web App to App Service for the first time or the 100th time, it helps to test out your app before releasing to the public. Deployment slots make it easy to set up a Staging Slot, warm it up and swap it immediately with a Production Slot. Swapping a slot that has already been warmed up ahead of time will allow you to deploy the latest version of your Web App almost immediately.

Zero-Downtime-Slots

Note that this feature is only available in Standard, Premium or Isolated App Service tiers, as it is not available in the Free/Shared tiers. You can combine Deployment Slots with your CI/CD pipelines to ensure that your automated deployments end up in the intended slots.

EF Core Migrations in Production

We covered EF Core Migrations in a previous post, which is one way of upgrading your database in various environments (including production). But wait, is it safe to run EF Core Migrations in a production environment? Even though you can use auto-generated EF Core migrations (written in C# or outputted as SQL Scripts), you may also modify your migrations for your needs.

I would highly recommend reading Jon P Smith‘s two-part series on “Handling Entity Framework Core database migrations in production”:

What you decide to do is up to you (and your team). I would suggest exploring the different options available to you, to ensure that you minimize any downtime for your users. For any non-breaking DB changes, you should be able to migrate your DB easily. However, your site may be down for maintenance for any breaking DB changes.

Feature Flags

Introduced by the Azure team, the Microsoft.FeatureManagement package allows you to add Feature Flags to your .NET application. This enables your web app to include new features that can easily be toggled for various audiences. This means that you could potentially test out new features by deploying them during off-peak times, but toggling them to become available via app configuration.

To install the package, you may use the following dotnet command:

>dotnet add package Microsoft.FeatureManagement --version 1.0.0-preview-XYZ

… where XYZ represents the a specific version number suffix for the latest preview. If you prefer the Package Manager Console in Visual Studio, you may also use the following PowerShell command:

>Install-Package Microsoft.FeatureManagement -Version 1.0.0-preview-XYZ

By combining many/all of the above features, tips and tricks for your Web App deployments, you can release new features while minimizing/eliminating downtime. If you have any new suggestions, feel free to leave your comments.

References