Category Archives: Learn

Organizational Accounts for ASP .NET Core

By Shahed C on April 15, 2019

This is the fifteenth of a series of posts on ASP .NET Core in 2019. In this series, we’ll 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:

O is for Organizational Accounts

If you’ve created new ASP .NET Core projects, you’ve probably seen an option to add authentication upon creation. In Visual Studio, the IDE provides radio buttons to select a specific type of Authentication. Using CLI commands (e.g. in the VS Code terminal) you can use the ‐‐auth flag to choose the type of authentication you’d like to add.

The possible values are:

  • None – No authentication (Default).
  • Individual – Individual authentication.
  • IndividualB2C – Individual authentication with Azure AD B2C.
  • SingleOrg – Organizational authentication for a single tenant.
  • MultiOrg – Organizational authentication for multiple tenants.
  • Windows – Windows authentication..

In this article, we will focus on the option for Work or School Accounts. This option can be used to authenticate users with AD (Active Directory, Azure AD or Office 365. In VS2019, a screenshot of the dialog is shown below:

AspNetCore-Auth-Azure

To follow along, take a look at the sample project on Github:

Web Org Authentication Sample: https://github.com/shahedc/AspNetCore2019Org

Adding Authentication

To add authentication to a new project quickly, here are the instructions for Visual Studio 2019.

If you choose to use the new splash screen:

  1. Click “Create a new project”
  2. Select “ASP .NET Core Web Application”
  3. Click Next
  4. Enter Project Name, Location, Solution Name
  5. Optional: check the checkbox to place in the same directory
  6. Click Create
  7. Select .NET Core 3.0 and then ASP .NET Core 3.0 from dropdowns
  8. Select a project type, e.g. Empty, Web Application (Razor Pages or MVC), etc
  9. Click the “Change” action link in the Authentication section

vs2019-project-new

This should allow you to change the authentication type to “Work or School Accounts” so that you may your organizational domain info. As always, you may select the little info buttons (lowercase i) to learn more about each field. Talk to your system administrator if you need more help on what domains to use.

vs2019-auth-options

NOTE: If you’re having trouble locating .NET Core 3.0 project types in Visual Studio, take a look at the previous blog post in this series on .NET Core 3.0 to get some help on how to enable it.

If you wish to skip the Splash Screen instead upon launching VS2019:

  1. Click “Continue without code” in the lower right area of the splash screen.
  2. In the top menu, click File | New | Project (or Ctrl-Shift-N)
  3. Follow the remaining steps outlined earlier in this section

To use CLI Commands in a Terminal window, use the dotnet new command followed by the ‐‐auth flag. The authentication type can be any of the aforementioned authentication types, e.g. Individual.

dotnet new mvc --auth Individual -o myproj

Configuring App Registration

If you’ve used “Individual User Accounts” before, you’ve probably used a database to store user data, either on-premises or in the cloud. If you’ve used “Work or School Accounts” (i.e. organizational accounts), you may have the old App portal at the following URL:

appdevreg-old

You may see a message suggesting that you should go to the Azure Portal to use the new App Registrations feature. Although this feature is currently in preview, you can start using it right now. If you click the link, it should take you directly to the App Registrations page, and may prompt you to log in first.

webreg-azure

If you’re not clear about how you got to this screen or how to come back to it later, here’s a set of steps that may help.

  1. Log in to the Azure Portal
  2. Search for App Registrations
  3. Arrive at the App Registrations page
  4. If necessary, click the banner that takes you to the preview experience.

webreg-portal-to-preview

The preview experience includes both your old and new app registrations. Click “New registration” to add a new app for authentication.

webreg-preview-add

In the form that follows, fill out the values for:

  • Name (which you can change later)
  • Account Type (your org, any org, any org + personal MSA)
  • Redirect URI (where users will return after authentication)

webreg-add-new

Now you should have options to configure your app and also download a pre-written application to get started. In the QuickStart section for your newly registered application (after selecting  the guide for “ASP .NET Core”, you should see a button to make the changes for you and also download a configured Visual Studio application.

webreg-azure-quickstart-aspnetcore

In the steps that follow:

  1. Click the “Make the changes for me” button to make the necessary configuration changes.
  2. Click the “Download” link to download the pre-configured Visual Studio solution.

webreg-azure-quickstart-aspnetcore-zoomed

At the time of this writing, the project type is a VS2017 application. You can download it to inspect it, but I would recommend creating a new project manually in VS2019. There are some subtle diferences between projects created by VS2019 with authentication turned on, versus what you get with the downloaded project.

For further customization using the Manifest file available to you, check out the official documentation on the Azure AD app manifest:

Using Authentication in Your Code

When creating a new project in VS2019, you get the following lines of code in your ConfigureServices() method, including calls to .AddAuthentication() and .addMvc().

// contents of ConfigureServices() when created in VS2019

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));

services.AddMvc(options =>
{
   var policy = new AuthorizationPolicyBuilder()
      .RequireAuthenticatedUser()
      .Build();
      options.Filters.Add(new AuthorizeFilter(policy));
})
.AddNewtonsoftJson();

If you download the pre-configured project from the Azure portal, you may notice an additional block of code in between .AddAuthentication() and .addMVC().

// contents of ConfigureServices() when downloaded from Portal

services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
.AddAzureAD(options => Configuration.Bind("AzureAd", options));

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
   options.Authority = options.Authority + "/v2.0/";
   options.TokenValidationParameters.ValidateIssuer = false;
});

services.AddMvc(options =>
{
   var policy = new AuthorizationPolicyBuilder()
      .RequireAuthenticatedUser()
      .Build();
   options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

This additional block calls services.Configure<OpenIdConnectOptions>() method to set up authentication for an Azure AD v2.0 endpoint. According to the documentation displayed in the Portal itself: “All users with a work or school, or personal Microsoft account can use your application or API. This includes Office 365 subscribers. To change the supported accounts for an existing registration, use the manifest editor. Take care, as certain properties may cause errors for personal accounts.

You can copy the this block of code manually into your VS2019 project, and refer to the sample project’s Startup.cs file.

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
   options.Authority = options.Authority + "/v2.0/";
   options.TokenValidationParameters.ValidateIssuer = false;
});

There is also a difference in the Compatibility Version setting in the code. The downloaded project for VS2017 currently sets compatibility for v2.1 but you can manually set this to 3.0 when you create a project manually in VS2019, as seen in this snippet from the sample Startup.cs file.

services.AddMvc(options =>
{
   var policy = new AuthorizationPolicyBuilder()
      .RequireAuthenticatedUser()
      .Build();
   options.Filters.Add(new AuthorizeFilter(policy));
})
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

Endpoint Routing in MVC

In the Configure() method of Startup.cs, the downloaded project contains familiar method calls to various Middleware components.

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();

app.UseAuthentication();

app.UseMvc(routes =>
{
   routes.MapRoute(
   name: "default",
   template: "{controller=Home}/{action=Index}/{id?}");
});

When you create an ASP .NET Core 3.0 project in VS2019, you may see the new Endpoint Routing feature, which makes it look like this:

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting(routes =>
{
   routes.MapControllerRoute(
   name: "default",
   template: "{controller=Home}/{action=Index}/{id?}");
});

app.UseCookiePolicy();

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

You may notice the addition of app.UseRouting() appearing in between app.UseStaticFiles() and app.UseCookiePolicy, and there is no explicit call to app.UseMvc(). This doesn’t mean that the application is calling MVC ahead of time. Rather, the release notes explains it  well:

So think of UseRouting(…) as making a deferred routing decision – where middleware that appear after it run in the middle. Any middleware that run after routing can see the results and read or modify the route data and chosen endpoint. When processing reaches the end of the pipeline, then the endpoint is invoked.

You can read more about this in the writeup for v3.0 Preview 2:

App Settings and Identity

In your appsettings.json file, you can set values for your App Settings. This includes the following AzureAd settings:

  • Instance
  • Domain
  • ClientId
  • TenantId
  • CallbackPath
{
  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "<YOUR_SUB_DOMAIN>.onmicrosoft.com",
    "ClientId": "<YOUR_CLIENT_ID>",
    "TenantId": "<YOUR_TENANT_ID>",
    "CallbackPath": "/signin-oidc"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

You can see more information on appsettings.json values in the official docs. You can also open the apssettings.json from the portal-downloaded project to get your own app’s Id values. The following documentation is specifically written for v2, but offers explains for important fields such as ClientId and TenantId.

To ensure that your authentication is working correctly, you can test it out by applying the [Authorize] attribute on a controller, e.g. the HomeController.cs class.

[Authorize]
public class HomeController : Controller
{
   //
}

To get a refresher on how to use the [Authorize] attribute, check out the post on Authorization from earlier in this blog series. For more on assigning users to specific roles, check out the official documentation at the following URL:

Finally, take a look at the Login.partial.cshtml partial view to observe the way a user’s identity is detected and shown. Here is a snippet from the sample:

@if (User.Identity.IsAuthenticated)
{
 <li class="nav-item">
 <span class="nav-text text-dark">Hello @User.Identity.Name!</span>
 </li>
}

Depending on what you have access to, the User.Identity object may not contain everything you expect it to. Here are some things to take note of:

  • User.Identity should be null when not logged in
  • User.Identity should be non-null when logged in…
  • … however, User.Identity.Name may be null even when logged in
  • If User.Identity.Name is null, also check User.Identity.Claims
  • User.Identity.Claims should have more than 0 values when logged in

The following screenshot shows an example of the user information in my debugging environment when logged in:

vs2019-login-identity-claims


References:

 

.NET Core 3.0, VS2019 and C# 8.0 for ASP .NET Core developers

By Shahed C on April 8, 2019

This is the fourteenth of a series of posts on ASP .NET Core in 2019. In this series, we’ll 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:

N is for .NET Core 3.0, VS2019 and C# 8.0

After completing 13 blog posts in this A-Z series, Visual Studio 2019 has now been released. While this is just a coincidence, this is a great opportunity to focus on .NET Core 3.0, VS 2019 and C# 8.0 language features for ASP .NET Core developers. This blog post provides an overview of everything you need to know to get started with the above, as an ASP .NET Core developer.

vs2019-netcore3-csharp8

Visual Studio 2019

First things first: now that Visual Studio 2019 has been released, where can you download it from? Start with the main download page and then select the edition you need:

As before, the Community Edition (comparable to Pro) is free for students, open-source contributors and individuals. The Pro and Enterprise editions add additional products and services from small teams to enterprise companies.

But wait! What if you can’t stay online for the length of the installation or need to reinstall quickly at a later date? If you need an offline installer, check out the instructions on the following page:

What are some cool new and improved features to be aware of? There are so many that I stitched together a series of tweets from Amanda Silver (Director of Program Management for Dev Tools at Microsoft) and created the following thread:

The aforementioned thread highlights the following features. Click each hyperlink in the list below for more info on each.

  • Live Share: Available as an extension in VS Code, Live Share is installed by default with VS2019. Easily collaborate with other developers while coding in real-time!
  • Intellicode: Use AI to write better code. Choose to share what you want with others or keep things private.
  • Git-first workflows: Choose to create a new project from a source code repo or use a template. The new start window provides more options up front.
  • Debug search: Search while debugging. Type in search filters in the Watch, Locals, and Autos panels.
  • Snapshot debugging: Available in the Enterprise Edition, snapshot debugging allows you to get a snapshot of your app’s execution after deployment. This includes cloud deployments, Azure VMs and Kubernetes containers.
  • VS Search: Dynamic search results include commands, menus, components and templates. Note that this was formerly know as Quick Launch.
  • App Service Debugging: Attach the debugger to your app running in Azure App Service!
  • App Service Connectivity: Connect your web app to Azure App Service with ease, including App Insights monitoring.
  • Azure Monitor: Use Azure Monitor to get additional insight on your deployed app!

If you prefer to sit back and relax and just watch new product announcements, I put together a handy list of YouTube videos from the VS2019 launch event. This playlist kicks off with the 50-minute keynote, is followed by a string of videos and ends with a cumulative 7-hour video if you prefer to watch all at once.


 

.NET Core 3.0

If you’ve downloaded Visual Studio 2019, you may have followed the following steps:

  1. Download Visual Studio 2019
  2. Click File | New | Project (or create new from splash screen)
  3. Create a new ASP .NET Core Web App
  4. Select .NET Core 3.0 as the project type/platform… right?

vs2019-new-aspnetcore

But wait a minute, where is the option for ASP .NET Core 3.0? Why isn’t it available for selection? The answer is simple: ASP .NET Core 3.0 is still in preview as of April 2019, after the release of Visual Studio 2019. In order to create ASP .NET Core 3.0 projects with VS2019, you should do the following (for now):

  • Download .NET Core 3.0: https://dotnet.microsoft.com/download/dotnet-core/3.0
  • Enable preview releases of .NET Core
    • Click Tools | Options in the top menu
    • Expand Projects and Solutions | .NET Core 
    • Ensure that “Use previews of the .NET Core SDK” checkbox is checked

vs2019-netcore3-preview

Start to create a new project again and you should now see an option for Core 3.0!

vs2019-new-aspnetcore3

Following some Twitter feedback, here are my results from running MSBuild from a command line:

Here is the specific command, setting the target to rebuild the project:

> MSBuild.exe c:\path\projfile.csproj -t:rebuild

On my development machine, I used MSBuild.exe from the following path:

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\MSBuild\Current\Bin

C# 8.0 Features

To ensure that C# 8.0 preview features are available, you can set the LangVersion property explicitly for your project. This setting is buried deep inside your Advanced settings within your project’s Build tab.

To update the language setting:

  1. Right-click your project in Solution Explorer.
  2. Select Properties to view your project properties.
  3. Click the Build tab within your project properties.
  4. Click the Advanced button on the lower right.
  5. Select the appropriate Language version, e.g. C# 8.0 (beta)
  6. Optional: you may select “unsupported preview…” instead

vs2019-build-advanced-lang

The above screenshots show the aforementioned setting in the Visual Studio UI. If you wish to update your .csproj file directly, you may view/edit the <LangVersion> value. A few samples are shown below:

For a .NET Core 3.0 console app set to use C# preview versions, the value of <LangVersion> is set to the value “preview”:

<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>netcoreapp3.0</TargetFramework>
      <LangVersion>preview</LangVersion>
   </PropertyGroup>
</Project>

For a .NET Core 3.0 console app set to use C# 8.0 explicitly, the value of <LangVersion> is set to the value “8.0”:

<Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
      <OutputType>Exe</OutputType>
      <TargetFramework>netcoreapp3.0</TargetFramework>
      <LangVersion>8.0</LangVersion>
   </PropertyGroup>
</Project> 

Here is a list of C# 8.0 features, from recent preview releases:

  • Nullable reference types: design with intent, decide that some variables must always have a value, while others may be missing a value, using nullable reference types.
  • Asynchronous streams: create and consume async streams, e.g. large streams of data
  • Indices and ranges: Specify subranges of data with Span<T>, indicate indices in the subsets of data
  • Pattern matching enhancements:
    • Switch expressions: replace repetitive switch-case blocks with simpler switch expressions
    • Property patterns: enhance switch statements by matching an object’s properties
    • Tuple patterns: use tuples for cases when matching sets of values
    • Positional patterns: used to simplify the way we apply recursive patterns without having to name an object’s properties
  • Using declarations: used to simplify using blocks (within which an object is disposed when done) by disposing of the object at the end of the enclosing scope, i.e. its parent block.
  • Static local functions: useful for local methods that are intended to be static.
  • Disposable ref structs: allows the use of Dispose() methods to allow implementation of IDisposable in structs declared with a ref modifier.

ASP .NET Core 3.0 Project Types

When you create a new Core 3.0 web project with Visual Studio 2019, you’ll see some familiar project types. You will also see some new project types. These are shown in the 2 screenshots below:

vs2019-web-projects01

Web Projects 1 of 2

Web Projects 2 of 2

Web Projects 2 of 2

The above project types are described below:

  1. Empty: familiar empty project that just writes out Hello World to the HTTP Response, without the use of MVC or Razor Pages
  2. gRPC Service: a new project type using Google’s high-performance Remote Procedure Call (RPC) framework
  3. Razor Components: initially called server-side Blazor, renamed to Razor Components to distinguish it from client-side Blazor, this will be once again be renamed to server-side Blazor again when ASP .NET Core 3.0 is released. Allows full-stack C# web app development.
  4. Worker Service: a new project type that allows creation of background processes, e.g. Windows services or Linux daemons. May be relocated in the template list upon release.
  5. API: familiar project type for creating Web APIs and RESTful services. Can be mixed and matched with Razor Pages or MVC components.
  6. Web Application: familiar project type for creating Web Apps with Razor Pages. Can be mixed and matched with Web API and/or MVC components.
  7. Web Application (MVC): familiar project type for creating Web Apps with MVC application structure. Can be mixed and matched with Razor Pages and/or Web API.
  8. Razor Class Library: relatively new project type for creating reusable UI Class Libraries with Razor Pages. See previous post on Razor Class Libraries.
  9. Angular, React.js, React.js and Redux: familiar web projects for web developers who wish to build a JavaScript front-end, typically with a Web API backend.

Well, what about client-side Blazor? You may have noticed that server-side Blazor (aka Razor Components are mentioned, but there is no sign of client-side Blazor. As of April 2019, client-side Blazor running in the browser with WebAssembly is still experimental. As a result, it is not included with ASP .NET Core 3.0 but can be downloaded separately.

For a quick refresher, check out my previous post on client-side Blazor:

If you need some help getting started, here’s a handy guide from the official docs:

References

 

 

Middleware in ASP .NET Core

By Shahed C on April 3, 2019

This is the thirteenth of a series of posts on ASP .NET Core in 2019. In this series, we’ll 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:

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.

Blog-Diagram-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.

To follow along, take a look at the sample project on Github:

Web Middleware Sample: https://github.com/shahedc/AspNetCoreMiddlewareSample

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 looks like, in a template-generated Startup.cs file:

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

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();

    app.UseAuthentication();

    app.UseSession();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

I have added a call to UseSession()  to call the Session Middleware, as it wasn’t included in the template-generated project. I also enabled authentication and HTTPS when creating the template.

VS2017-Project-New

 

In order to configure the use of the Session middleware, I also had to add the following code in my 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;
    });

    services.AddMvc();

...

}

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. In the Razor Pages version of Startup.cs, the Configure() method is a little simpler, as it doesn’t need to set up MVC routes for controllers in the call to useMvc().

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 MVC middleware) ensures that cookies can be issued as necessary and that the user can be authenticated before the MVC engine kicks in. For more information, check out the detailed post on Authentication & Authorization in ASP .NET Core.

MVC & Routing:

  • UseMvc(): enables the use of MVC in your web application, with the ability to customize routes for your MVC application and set other options.
  • routes.MapRoute(): set the default route and any custom routes when using MVC.

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. Here, the app.Run() method terminates the pipeline, so you wouldn’t add any additional middleware calls after it.

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    app.Run(async (context) =>
    {
        await context.Response.WriteAsync("Hello World!");
    });
}

The call to app.Use() can be used to trigger the next middleware component with a call to next.Invoke() as shown below:

public void Configure(IApplicationBuilder app)
{
    app.Use(async (context, next) =>
    {
        // ...
        await next.Invoke();
        // ...
    });

    app.Run(...);
}

If there is no call to next.Invoke(), then it essentially short-circuits the middleware pipeline. Finally, there is the Map() method, which creates separate forked paths/branches for your middleware pipeline and multiple terminating ends. The code snippet below shows the contents of a Startup.cs file with mapped branches:

// first branch handler
private static void HandleBranch1(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Branch 1.");
    });
}

// second branch handler
private static void HandleBranch2(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Branch 2.");
    });
}

public void Configure(IApplicationBuilder app)
{
    app.Map("/mappedBranch1", HandleBranch1);

    app.Map("/mappedBranch2", HandleBranch2);

    // default terminating Run() method
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Terminating Run() method.");
    });
}

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.

For example:

  • accessing /mappedBranch1 in an HTTP request will call HandleBranch1()
  • accessing /mappedBranch2 in an HTTP request will call HandleBranch2()
  • 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

The screenshots below illustrate the results of the above scenarios:

 

Scenario 1: https://localhost:44391/mappedBranch1

Branch-1

Scenario 2: https://localhost:44391/mappedBranch2

Branch-2

Scenario 3: https://localhost:44391/

Branch-Root

Scenario 4: https://localhost:44391/RandomTextESDRFTGYHJ

Branch-Random

 

References

Hope you enjoyed learning about Middleware in ASP.NET Core. Here is some feedback I received via Twitter: “Learned so [much] about #ASPNetCore  middleware from this article. The templates should have comments in them with this stuff!”

 

Logging in ASP .NET Core

By Shahed C on March 25, 2019

This is the twelfth of a series of posts on ASP .NET Core in 2019. In this series, we’ll 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:

L is for Logging in ASP .NET Core

You could write a fully functional ASP .NET Core web application without any logging. But in the real world, you should use some form of logging. This blog post provides an overview of how you can use the built-in logging functionality in ASP .NET Core web apps. While we won’t go deep into 3rd-party logging solutions such as Serilog in this article (stay tuned for a future article on that topic), you should definitely consider a robust semantic/structured logging solution for your projects.

To follow along, take a look at the sample project on Github:

Web Logging Sample: https://github.com/shahedc/AspNetCoreLoggingSample

Logging in ASP .NET Core

Logging in ASP .NET Core

Log Messages

The simplest log message includes a call to the extension method ILogger.Log()  by passing on a LogLevel and a text string. Instead of passing in a LogLevel, you could also call a specific Log method such as LogInformation() for a specific LogLevel. Both examples are shown below:

// Log() method with LogLevel passed in 
_logger.Log(LogLevel.Information, "some text");

// Specific LogXX() method, e.g. LogInformation()
_logger.LogInformation("some text");

LogLevel values include Trace, Debug, Information, Warning, Error, Critical and None. These are all available from the namespace Microsoft.Extensions.Logging. For a more structured logging experience, you should also pass in meaningful variables/objects following the templated message string, as all the Log methods take in a set of parameters defined as “params object[] args”.

public static void Log (
   this ILogger logger, LogLevel logLevel, string message, params object[] args);

This allows you to pass those values to specific logging providers, along with the message itself. It’s up to each logging provider on how those values are captured/stored, which you can also configure further. You can then query your log store for specific entries by searching for those arguments. In your code, this could look something like this:

_logger.LogInformation("some text for id: {someUsefulId}", someUsefulId);

Even better, you can add your own EventId for each log entry. You can facilitate this by defining your own set of integers, and then passing an int value to represent an EventId. The EventId type is a struct that includes an implicit operator, so it essentially calls its own constructor with whatever int value you provide.

_logger.LogInformation(someEventId, "some text for id: {someUsefulId}", someUsefulId);

In the sample project, we can see the use of a specific integer value for each EventId, as shown below:

// Step X: kick off something here
_logger.LogInformation(LoggingEvents.Step1KickedOff, "Step {stepId} Kicked Off.", stepId);

// Step X: continue processing here
_logger.LogInformation(LoggingEvents.Step1InProcess, "Step {stepId} in process...", stepId);

// Step X: wrap it up
_logger.LogInformation(LoggingEvents.Step1Completed, "Step {stepId} completed!", stepId);

The integer values can be whatever you want them to be. An example is shown below:

public class LoggingEvents
{
   public const int ProcessStarted = 1000; 

   public const int Step1KickedOff = 1001;
   public const int Step1InProcess = 1002;
   public const int Step1Completed = 1003; 
   ...
}

Logging Providers

The default template-generated web apps include a call to CreateDefaultBuilder() in Program.cs, which automatically includes adds the Console and Debug providers. As of ASP.NET Core 2.2, the EventSource provider is also automatically added by the default builder.

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
      .UseStartup<Startup>();

NOTE: As mentioned in an earlier post in this blog series, the Web Host Builder will be replaced by the Generic Host Builder with the release of .NET Core 3.0.

If you wish to add your own set of logging providers, you can expand the call to CreateDefaultBuilder(), clear the default providers, and then add your own. The built-in providers now include Console, Debug, EventLog, AzureAppServices, TraceSource and EventSource.

public static IWebHostBuilder CreateWebHostBuilder(
   string[] args) => WebHost.CreateDefaultBuilder(args) 
      .UseStartup<Startup>()  
      .ConfigureLogging(logging =>  
      {  
         // clear default logging providers
         logging.ClearProviders();  

         // add built-in providers manually, as needed 
         logging.AddConsole();   
         logging.AddDebug();  
         logging.AddEventLog();
         logging.AddEventSourceLogger();
         logging.AddTraceSource(sourceSwitchName);
      });

The screenshots below show the log results viewable in Visual Studio’s Debug Window and in the Windows 10 Event Viewer. Note that the EventId’s integer values (that we had defined) are stored in the EventId field as numeric value in the Windows Event Viewer log entries.

Logging: VS2017 Debug Window

Logging: VS2017 Debug Window

Logging; Windows Event Viewer

Logging; Windows Event Viewer

For the Event Log provider, you’ll also have to add the following NuGet package and corresponding using statement:

Microsoft.Extensions.Logging.EventLog

For the Trace Source provider, a “source switch” can be used to determine if a trace should be propagated or ignored. For more information on the Trace Source provider and the Source Switch it uses check out the official docs at:

For more information on adding logging providers and further customization, check out the official docs at:

But wait a minute, what happened to the Azure App Services provider mentioned earlier? Why isn’t there a call to add it as a logging provider? Well, you should be aware that there is a method for adding Azure Web App Diagnostics as a logging provider:

logging.AddAzureWebAppDiagnostics();

However, you would only have to call this AddAzureWebAppDiagnostics() method if you’re targeting .NET Framework. You shouldn’t call it if targeting .NET Core. With .NET Core 3.0, ASP.NET Core will run only on .NET Core so you don’t have to worry about this at all. When you deploy the web app to Azure App Service, this logging provider is automatically available for your use. (We will cover this in more detail in a future blog post.)

JSON Configuration

One way to configure each Logging Provider is to use your appsettings.json file. Depending on your environment, you could start with appsettings.Development.json or App Secrets in development, and then use environment variables, Azure Key Vault in other environments. You may refer to earlier blog posts from 2018 and 2019 for more information on the following:

In your local JSON config file, your configuration uses the following syntax:

{
   "Logging": {
      "LogLevel": {
         "Default": "Debug",
         "Category1": "Information",
         "Category2": "Warning"
      },
      "SpecificProvider":
      {
         "ProviderProperty": true
      }
   }
}

The configuration for LogLevel sets one or more categories, including the Default category when no category is specified. Additional categories (e.g. System, Microsoft or any custom category) may be set to one of the aforementioned LogLevel values.

The LogLevel block can be followed by one or more provider-specific blocks (e.g. Console) to set its properties, e.g. IncludeScopes. Such an example is shown below.

{
   "Logging": {
      "LogLevel": {
         "Default": "Debug",
         "System": "Information",
         "Microsoft": "Information"
      },
      "Console":
      {
         "IncludeScopes": true
      }
   }
}

To set logging filters in code, you can use the AddFilter () method for specific providers or all providers in your Program.cs file. The following syntax can be used to add filters for your logs.

WebHost.CreateDefaultBuilder(args)
   .UseStartup<Startup>()
   .ConfigureLogging(logging =>
      logging.AddFilter("Category1", LogLevel.Level1)
         .AddFilter<SomeProvider>("Category2", LogLevel.Level2));

In the above sample, the following placeholders can be replaced with:

  • CategoryX: System, Microsoft, custom categories
  • LogLevel.LevelX: Trace, Debug, Information, Warning, Error, Critical, None
  • SomeProvider: Debug, Console, other providers

Log Categories

To set a category when logging an entry, you may set the string value when creating a logger. If you don’t set a value explicitly, the fully-qualified namespace + class name is used. In the WorkhorseController class seen in your example, the log results seen in the Debug window and Event Viewer were seen to be:

LoggingWebMvc.Controllers.WorkhorseController

This is the category name created using the controller class name passed to the constructor in WorkHoseController as shown below:

private readonly ILogger _logger; 

public WorkhorseController(ILogger<WorkhorseController> logger)
{
   _logger = logger;
}

If you wanted to set this value yourself, you could change the code to the following:

private readonly ILogger _logger; 

public WorkhorseController(ILoggerFactory logger)
{
   _logger = logger.CreateLogger("LoggingWebMvc.Controllers.WorkhorseController");
}

The end results will be the same. However, you may notice that there are a couple of differences here:

  1. Instead of ILogger<classname> we are now passing in an ILoggerFactory type as the logger.
  2. Instead of just assigning the injected logger to the private _logger variable, we are now calling the factory method CreateLogger() with the desired string value to set the category name.

Exceptions in Logs

In addition to EventId values and Category Names, you may also capture Exception information in your application logs. The various Log extensions provide an easy way to pass an exception by passing the Exception object itself.

try 
{
   // try something here
   throw new Exception();
} catch (Exception someException)
{
   _logger.LogError(eventId, someException, "Trying step {stepId}", stepId);
   // continue handling exception
}

Checking the Event Viewer, we may see a message as shown below. The LogLevel is shown as “Error” because we used the LogError() extension method in the above code, which is forcing an Exception to be thrown. The details of the Exception is displayed in the log as well.

Logging; Exception in Event Viewer

Logging; Exception in Event Viewer

Structured Logging with Serilog

At the very beginning, I mentioned the possibilities of structured logging with 3rd-party providers. There are many solutions that work with ASP .NET Core, including (but not limited to) elmah, NLog and Serilog. Here, we will take a brief look at Serilog.

Similar to the built-in logging provider described throughout this article, you should include variables to assign template properties in all log messages, e.g.

Log.Information("This is a message for {someVariable}", someVariable);

To make use of Serilog, you’ll have to perform the following steps:

  1. grab the appropriate NuGet packages: Serilog, Hosting, various Sinks, e,g, Console
  2. use the Serilog namespace, e.g. using Serilog
  3. create a new LoggerConfiguration() in your Main() method
  4. call UseSerilog() when creating your Host Builder
  5. write log entries using methods from the Log static class.

For more information on Serilog, check out the following resources:

References

 

Key Vault for ASP .NET Core Web Apps

By Shahed C on March 18, 2019

This is the eleventh of a series of posts on ASP .NET Core in 2019. In this series, we’ll 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:

K is for Key Vault for ASP .NET Core 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 may download the following sample project to follow along with Visual Studio. You may need to apply migrations if you wish to use the optional authentication features with a data store in the sample app.

Web Key Vault Sample: https://github.com/shahedc/AspNetCoreKeyVaultSample

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

Blog-Diagram-KeyVault

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:

  • Name: alphanumeric, dashes allowed, cannot start with number
  • Subscription: select the desired Azure subscription
  • Resource Group: select a resource group or create a new one
  • Location: select the desired location
  • Pricing Tier: select the appropriate pricing tier (Standard, Premium)
  • Access policies: select/create one or more access policies with permissions
  • Virtual Network Access: select all (or specific) networks to allow access

KeyVault-Create-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.

vs2017-add-connservice

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

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 Details

Secret in Key Vault

Secret in 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 and KeyVault NuGet libraries.
    • Microsoft.Azure.Services.AppAuthentication
    • Microsoft.Azure.KeyVault
  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 IWebHost BuildWebHost(string[] args) =>
   WebHost.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());
         }
      }
   ).UseStartup<Startup>()
   .Build(); 

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

NOTE: Please note that the Web Host Builder in ASP .NET Core 2.x will be replaced by the Generic Host Builder in .NET Core 3.0.

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).

KeyVault-Browser-Values

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
KeyVault-AccessPolicies

KeyVault-AccessPolicies

AppService-Identity

AppService-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 Key Vault” if it hasn’t been added yet. After you’ve added and enabled Key Vault for your application, the option will change to say “Configure” and “Manage Key Vault”.

KeyVault-BeforeAdd

Publish (before adding Key Vault)

KeyVault-Publish

Publish (Manage Key Vault after adding it)

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