<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Adam Swanson</title>
    <description>The latest articles on DEV Community by Adam Swanson (@theaswanson).</description>
    <link>https://dev.to/theaswanson</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F243525%2F6fae1f4e-3406-4b7d-bbed-4c30f90d5afe.png</url>
      <title>DEV Community: Adam Swanson</title>
      <link>https://dev.to/theaswanson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/theaswanson"/>
    <language>en</language>
    <item>
      <title>Adding Authentication with Azure AD to a .NET Angular Web App with MSAL</title>
      <dc:creator>Adam Swanson</dc:creator>
      <pubDate>Thu, 11 Mar 2021 20:13:59 +0000</pubDate>
      <link>https://dev.to/theaswanson/adding-authentication-with-azure-ad-to-a-net-angular-web-app-with-msal-11a5</link>
      <guid>https://dev.to/theaswanson/adding-authentication-with-azure-ad-to-a-net-angular-web-app-with-msal-11a5</guid>
      <description>&lt;p&gt;I recently went through this process and was disappointed at the lack of documentation. Then I realized that the latest version of the &lt;code&gt;msal-angular&lt;/code&gt; library I used was only 8 days old at the time of writing, so that explains some things.&lt;/p&gt;

&lt;p&gt;In any case, I've decided to write out my steps for anyone else looking to setup a similar project with this type of authentication. To walk through this process, we'll be creating a web app from scratch and deploying it to a new App Service in Azure. We'll also register the app in Azure AD.&lt;/p&gt;

&lt;p&gt;You can find the completed web app &lt;a href="https://github.com/theaswanson/my-authenticated-app" rel="noopener noreferrer"&gt;here&lt;/a&gt;, or you can follow along and create it yourself using the steps below.&lt;/p&gt;

&lt;p&gt;To summarize, here's what we're building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web app with .NET 5 Web API and Angular 11, hosted in an Azure App Service&lt;/li&gt;
&lt;li&gt;Authentication with Azure AD using the &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow" rel="noopener noreferrer"&gt;Microsoft Identity platform and OAuth 2.0 authorization code flow&lt;/a&gt;, and the &lt;a href="https://www.npmjs.com/package/@azure/msal-angular" rel="noopener noreferrer"&gt;@azure/msal-angular@2.0.0-beta.0&lt;/a&gt; package&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And here's what we're gonna do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new project from the .NET Angular template&lt;/li&gt;
&lt;li&gt;Upgrade the Angular app from 8 to 11&lt;/li&gt;
&lt;li&gt;Deploy the app to an App Service&lt;/li&gt;
&lt;li&gt;Add a new app registration in Azure AD&lt;/li&gt;
&lt;li&gt;Configure the app redirect URIs to ensure eligibility for the Authorization Code Flow with PKCE.&lt;/li&gt;
&lt;li&gt;Configure the .NET Web API for authentication, authorization, and CORS&lt;/li&gt;
&lt;li&gt;Install MSAL and other dependencies for Angular&lt;/li&gt;
&lt;li&gt;Configure MSAL and Angular app for authentication&lt;/li&gt;
&lt;li&gt;Redeploy to App Service&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Microsoft Azure account with free-tier subscription (for Azure AD and App Service)&lt;/li&gt;
&lt;li&gt;Visual Studio Code (for running and editing the app)&lt;/li&gt;
&lt;li&gt;VSCode Azure App Service extension (for publishing to the App Service)&lt;/li&gt;
&lt;li&gt;.NET 5.0 (for running the app and adding packages)&lt;/li&gt;
&lt;li&gt;Node and npm (for updating Angular, installing MSAL, and Angular CLI)&lt;/li&gt;
&lt;li&gt;Angular CLI (for generating the &lt;code&gt;AuthService&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create the web app
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Generate the app using the .NET Angular template

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dotnet new angular -o my-authenticated-app&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Trust the certificate, if needed

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dotnet dev-certs https --trust&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Upgrade Angular from 8 to 11

&lt;ul&gt;
&lt;li&gt;From the &lt;code&gt;ClientApp&lt;/code&gt; folder, run these commands:&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ng update @angular/core@8 @angular/cli@8&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ng update @angular/core@9 @angular/cli@9&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;export { renderModule, renderModuleFactory } from '@angularplatform-server'&lt;/code&gt; from &lt;code&gt;main.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;progress: false&lt;/code&gt; to &lt;code&gt;progress: true&lt;/code&gt; in &lt;code&gt;angular.json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm uninstall @nguniversal/module-map-ngfactory-loader&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Remove &lt;code&gt;ModuleMapLoaderModule&lt;/code&gt; import and reference from &lt;code&gt;app.server.module.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ng add @angular/localize&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ng update @angular/cli@10 @angular/core@10 rxjs&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ng update @angular/cli@11 @angular/core@11 --force&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm uninstall node-sass&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm i -g npm-check-updates&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ncu -u&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm i&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm audit fix&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm i -D typescript@4.1.5&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Run the app and verify it starts correctly. You should get a page like this:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k98ptvkyfyl4ceob8mh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5k98ptvkyfyl4ceob8mh.png" alt="Hello World" width="800" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View the "Fetch data" page. It should load the weather data. Later, after we add authentication, this page will require authentication and will not load the weather data unless a user is logged in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create the App Service
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;In the Azure portal, under App Services, click "Create"
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flakkgpu870btekdbo5dz.png" alt="Create an App Service" width="256" height="106"&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select your Azure subscription and resource group. Set a name under Instance Details, set Publish to "Code", Runtime stack to ".NET 5", Operating System to "Windows", and select a region. Also select an appropriate Windows Plan. Click "Review + create".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsbg2p2hkq539tr3eyto.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmsbg2p2hkq539tr3eyto.png" alt="Create Web App" width="760" height="885"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Under the Overview section of the App Service, note the URL listed under Essentials. We will need this when configuring the redirect URIs in the app registration.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Add a new app registration in Azure AD
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the Azure Portal, open Azure Active Directory&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3k94ppwl77kfij4u5oq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3k94ppwl77kfij4u5oq4.png" alt="Azure AD" width="232" height="149"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under the Manage menu, open "App registrations" and click "New registration"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl3vjxf487bq1iyy9fq89.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl3vjxf487bq1iyy9fq89.png" alt="New App Registration" width="685" height="516"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enter a name and select the supported account types. Also create a Redirect URI for &lt;code&gt;https://localhost:5001/&lt;/code&gt; and ensure the type is set to "Single-page application (SPA)". Click Register.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds6yxbmjre0bwm3p6lxi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fds6yxbmjre0bwm3p6lxi.png" alt="Register an application" width="800" height="838"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;On the Overview screen for the app registration, you should see an Application (client) ID and Directory (tenant) ID. Make note of these as we'll need them later when we configure the web app for authentication.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fet0jvdclypnkg3c9xqmi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fet0jvdclypnkg3c9xqmi.png" alt="App registration overview" width="724" height="298"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under the Authentication section, under Single-page application Redirect URIs, add a new URI for the URL of the App Service (i.e. &lt;code&gt;https://myauthenticatedapp.azurewebsites.net/&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33m1np5yvo3rd4kgo2fm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33m1np5yvo3rd4kgo2fm.png" alt="Add Redirect URI" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Deploy to App Service
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;From project root: &lt;code&gt;dotnet publish -c Release -o publish&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using the Azure App Service extension in Visual Studio Code, right-click the publish folder and click "Deploy to Web App". Select your newly created App Service and click "Deploy"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n5a7a20mxd4ysw6795k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5n5a7a20mxd4ysw6795k.png" alt="Deploy to App Service" width="385" height="454"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;View the newly deployed web app with the URL provided in the Overview section of the App Service. It should look the same as when you ran the app locally.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configure .NET Web API
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Configure &lt;code&gt;appsettings.json&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Add a new section titled "AzureAd". Replace &lt;code&gt;ENTER_CLIENT_ID_GUID_HERE&lt;/code&gt; with your Application (client) ID listed in the app registration in Azure AD, and replace &lt;code&gt;ENTER_TENANT_ID_GUID_HERE&lt;/code&gt; with the Directory (tenant) ID.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"AzureAd"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Instance"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://login.microsoftonline.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ClientId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ENTER_CLIENT_ID_GUID_HERE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"TenantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ENTER_TENANT_ID_GUID_HERE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Audience"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ENTER_CLIENT_ID_GUID_HERE"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install NuGet packages&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;dotnet add my-authenticated-app.csproj package Microsoft.AspNetCore.Authentication.JwtBearer&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;dotnet add my-authenticated-app.csproj package Microsoft.Identity.Web&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Setup &lt;code&gt;Startup.cs&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add the following uncommented code blocks:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ConfigureServices()&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//services.AddControllersWithViews();&lt;/span&gt;
        &lt;span class="c1"&gt;//services.AddSpaStaticFiles(configuration =&amp;gt;&lt;/span&gt;
        &lt;span class="c1"&gt;//{&lt;/span&gt;
        &lt;span class="c1"&gt;//    configuration.RootPath = "ClientApp/dist";&lt;/span&gt;
        &lt;span class="c1"&gt;//});&lt;/span&gt;

        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthentication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtBearerDefaults&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AuthenticationScheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddMicrosoftIdentityWebApi&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"AzureAd"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;Configure()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Configure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IApplicationBuilder&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IWebHostEnvironment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//if (env.IsDevelopment())&lt;/span&gt;
        &lt;span class="c1"&gt;//{&lt;/span&gt;
        &lt;span class="c1"&gt;//    app.UseDeveloperExceptionPage();&lt;/span&gt;
        &lt;span class="c1"&gt;//}&lt;/span&gt;
        &lt;span class="c1"&gt;//else&lt;/span&gt;
        &lt;span class="c1"&gt;//{&lt;/span&gt;
        &lt;span class="c1"&gt;//    app.UseExceptionHandler("/Error");&lt;/span&gt;
        &lt;span class="c1"&gt;//    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.&lt;/span&gt;
        &lt;span class="c1"&gt;//    app.UseHsts();&lt;/span&gt;
        &lt;span class="c1"&gt;//}&lt;/span&gt;

        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseCors&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;//app.UseHttpsRedirection();&lt;/span&gt;
        &lt;span class="c1"&gt;//app.UseStaticFiles();&lt;/span&gt;
        &lt;span class="c1"&gt;//if (!env.IsDevelopment())&lt;/span&gt;
        &lt;span class="c1"&gt;//{&lt;/span&gt;
        &lt;span class="c1"&gt;//    app.UseSpaStaticFiles();&lt;/span&gt;
        &lt;span class="c1"&gt;//}&lt;/span&gt;

        &lt;span class="c1"&gt;//app.UseRouting();&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthentication&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseAuthorization&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add the &lt;code&gt;Authorize&lt;/code&gt; attribute to &lt;code&gt;WeatherController&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;//[ApiController]&lt;/span&gt;
&lt;span class="c1"&gt;//[Route("[controller]")]&lt;/span&gt;
&lt;span class="c1"&gt;//public class MyController : ControllerBase&lt;/span&gt;
&lt;span class="c1"&gt;//{&lt;/span&gt;
&lt;span class="c1"&gt;//}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Configure Angular app with MSAL
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Install packages&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;From the &lt;code&gt;ClientApp&lt;/code&gt; folder, run &lt;code&gt;npm i msal @azure/msal-browser @azure/msal-angular&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Configure environment settings&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;ENTER_DEV_URL_HERE&lt;/code&gt; with your development URL (i.e. "&lt;a href="https://localhost:5001/%22" rel="noopener noreferrer"&gt;https://localhost:5001/"&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;ENTER_PUBLIC_URL_HERE&lt;/code&gt; with the App Service's URL (i.e. "&lt;a href="https://myauthenticatedapp.azurewebsites.net/%22" rel="noopener noreferrer"&gt;https://myauthenticatedapp.azurewebsites.net/"&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;ENTER_CLIENT_ID_GUID_HERE&lt;/code&gt; with the client ID from the app registration&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;ENTER_TENANT_NAME_HERE&lt;/code&gt; with the tenant name. This can be found in the Azure portal URL when viewing the App Service page ("&lt;a href="https://portal.azure.com/#@YOUR_TENANT_NAME.onmicrosoft.com/resource/subscriptions/and-so-on%22" rel="noopener noreferrer"&gt;https://portal.azure.com/#@YOUR_TENANT_NAME.onmicrosoft.com/resource/subscriptions/and-so-on"&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;environment.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```ts
export const environment = {
  production: false,
  redirectUrl: 'ENTER_DEV_URL_HERE',
  clientId: 'ENTER_CLIENT_ID_GUID_HERE',
  tenantName: 'ENTER_TENANT_NAME_HERE'
};
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;environment.prod.ts&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```ts
export const environment = {
  production: true,
  redirectUrl: 'ENTER_PUBLIC_URL_HERE',
  clientId: 'ENTER_CLIENT_ID_GUID_HERE',
  tenantName: 'ENTER_TENANT_NAME_HERE'
};
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Configure MSAL in &lt;code&gt;app.module.ts&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Add the following imports, functions, and module imports, providers, and bootstraps&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;HTTP_INTERCEPTORS&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/common/http&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;IPublicClientApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PublicClientApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;InteractionType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BrowserCacheLocation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;LogLevel&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalInterceptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalBroadcastService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalInterceptorConfiguration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MSAL_GUARD_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MSAL_INSTANCE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MSAL_INTERCEPTOR_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalGuardConfiguration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@azure/msal-angular&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../environments/environment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isIE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;MSIE &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;navigator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Trident/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Remove this line to use Angular Universal&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;loggerCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;logLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MSALInstanceFactory&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;IPublicClientApplication&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PublicClientApplication&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`https://login.microsoftonline.com/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tenantName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.onmicrosoft.com/`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;redirectUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;cacheLocation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BrowserCacheLocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;LocalStorage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;storeAuthStateInCookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isIE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// set to true for IE 11&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;loggerOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;loggerCallback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;logLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LogLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;piiLoggingEnabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MSALInterceptorConfigFactory&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;MsalInterceptorConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;protectedResourceMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;protectedResourceMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirectUrl&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;weatherforecast`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.default`&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;interactionType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InteractionType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;protectedResourceMap&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;MSALGuardConfigFactory&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;MsalGuardConfiguration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;interactionType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;InteractionType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;authRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;scopes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/.default`&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="nx"&gt;MsalModule&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HTTP_INTERCEPTORS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MsalInterceptor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;multi&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MSAL_INSTANCE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MSALInstanceFactory&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MSAL_GUARD_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MSALGuardConfigFactory&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MSAL_INTERCEPTOR_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MSALInterceptorConfigFactory&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;MsalService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MsalGuard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;MsalBroadcastService&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;...,&lt;/span&gt;
    &lt;span class="nx"&gt;MsalRedirectComponent&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create an auth service&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- From the `ClientApp` folder, run `ng g s auth`

- `auth.service.ts`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ```ts
    import { Inject, Injectable } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { AccountInfo, AuthenticationResult, InteractionStatus, InteractionType, PopupRequest, RedirectRequest } from '@azure/msal-browser';
    import { Subject } from 'rxjs';
    import { filter, takeUntil } from 'rxjs/operators';

    @Injectable({
      providedIn: 'root'
    })
    export class AuthService {
      loggedIn = false;
      private readonly _destroying$ = new Subject&amp;lt;void&amp;gt;();

      constructor(
        @Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration,
        private authService: MsalService,
        private msalBroadcastService: MsalBroadcastService) { }

      updateLoggedInStatus() {
        this.msalBroadcastService.inProgress$
          .pipe(
            filter((status: InteractionStatus) =&amp;gt; status === InteractionStatus.None),
            takeUntil(this._destroying$)
          )
          .subscribe(() =&amp;gt; {
            this.setLoggedIn();
            this.checkAndSetActiveAccount();
          });
      }

      login() {
        if (this.msalGuardConfig.interactionType === InteractionType.Popup) {
          this.loginWithPopup();
        } else {
          this.loginWithRedirect();
        }
      }

      getActiveAccount(): AccountInfo | null {
        return this.authService.instance.getActiveAccount();
      }

      private checkAndSetActiveAccount() {
        /**
        * If no active account set but there are accounts signed in, sets first account to active account
        * To use active account set here, subscribe to inProgress$ first in your component
        * Note: Basic usage demonstrated. Your app may require more complicated account selection logic
        */
        let activeAccount = this.authService.instance.getActiveAccount();

        if (!activeAccount &amp;amp;&amp;amp; this.authService.instance.getAllAccounts().length &amp;gt; 0) {
          let accounts = this.authService.instance.getAllAccounts();
          this.authService.instance.setActiveAccount(accounts[0]);
        }
      }

      private setLoggedIn() {
        this.loggedIn = this.authService.instance.getAllAccounts().length &amp;gt; 0;
      }

      private loginWithPopup() {
        if (this.msalGuardConfig.authRequest) {
          this.authService.loginPopup({ ...this.msalGuardConfig.authRequest } as PopupRequest)
            .subscribe((response: AuthenticationResult) =&amp;gt; {
              this.authService.instance.setActiveAccount(response.account);
            });
        } else {
          this.authService.loginPopup()
            .subscribe((response: AuthenticationResult) =&amp;gt; {
              this.authService.instance.setActiveAccount(response.account);
            });
        }
      }

      private loginWithRedirect() {
        if (this.msalGuardConfig.authRequest) {
          this.authService.loginRedirect({ ...this.msalGuardConfig.authRequest } as RedirectRequest);
        } else {
          this.authService.loginRedirect();
        }
      }

      logout() {
        this.authService.logout();
      }

      destroy() {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Add the &lt;code&gt;app-redirect&lt;/code&gt; component to &lt;code&gt;index.html&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;app-root&amp;gt;&lt;/span&gt;Loading...&lt;span class="nt"&gt;&amp;lt;/app-root&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;app-redirect&amp;gt;&amp;lt;/app-redirect&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implement &lt;code&gt;AuthService&lt;/code&gt; in the &lt;code&gt;AppComponent&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- `app.component.ts`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ```ts
    import { Component, OnInit } from '@angular/core';
    import { AuthService } from './auth.service';

    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html'
    })
    export class AppComponent implements OnInit {
      title = 'app';

      constructor(public authService: AuthService) { }

      ngOnInit(): void {
        this.authService.updateLoggedInStatus();
      }

      login() {
        this.authService.login();
      }

      logout() {
        this.authService.logout();
      }
    }
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- `app.component.html`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ```html
    &amp;lt;body&amp;gt;
      &amp;lt;app-nav-menu [loggedIn]="authService.loggedIn" (loginClicked)="login()" (logoutClicked)="logout()"&amp;gt;&amp;lt;/app-nav-menu&amp;gt;
      &amp;lt;div class="container"&amp;gt;
        &amp;lt;router-outlet&amp;gt;&amp;lt;/router-outlet&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/body&amp;gt;
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update the &lt;code&gt;NavMenuComponent&lt;/code&gt; with login/logout buttons&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- `nav-menu.component.ts`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ```ts
    import { Component, EventEmitter, Input, Output } from '@angular/core';

    @Component({
      selector: 'app-nav-menu',
      templateUrl: './nav-menu.component.html',
      styleUrls: ['./nav-menu.component.css']
    })
    export class NavMenuComponent {
      isExpanded = false;
      @Input() loggedIn: boolean;
      @Output() loginClicked = new EventEmitter&amp;lt;void&amp;gt;();
      @Output() logoutClicked = new EventEmitter&amp;lt;void&amp;gt;();

      collapse() {
        this.isExpanded = false;
      }

      toggle() {
        this.isExpanded = !this.isExpanded;
      }

      login() {
        this.loginClicked.emit();
      }

      logout() {
        this.logoutClicked.emit();
      }
    }
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- `nav-menu.component.html`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    ```html
    &amp;lt;header&amp;gt;
      &amp;lt;nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3"&amp;gt;
        &amp;lt;div class="container"&amp;gt;
          &amp;lt;a class="navbar-brand" [routerLink]="['/']"&amp;gt;my_authenticated_app&amp;lt;/a&amp;gt;
          &amp;lt;button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse"
            aria-label="Toggle navigation" [attr.aria-expanded]="isExpanded" (click)="toggle()"&amp;gt;
            &amp;lt;span class="navbar-toggler-icon"&amp;gt;&amp;lt;/span&amp;gt;
          &amp;lt;/button&amp;gt;
          &amp;lt;div class="navbar-collapse collapse d-sm-inline-flex justify-content-end" [ngClass]="{ show: isExpanded }"&amp;gt;
            &amp;lt;ul class="navbar-nav flex-grow"&amp;gt;
              &amp;lt;li class="nav-item" [routerLinkActive]="['link-active']" [routerLinkActiveOptions]="{ exact: true }"&amp;gt;
                &amp;lt;a class="nav-link text-dark" [routerLink]="['/']"&amp;gt;Home&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
              &amp;lt;li class="nav-item" [routerLinkActive]="['link-active']"&amp;gt;
                &amp;lt;a class="nav-link text-dark" [routerLink]="['/counter']"&amp;gt;Counter&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
              &amp;lt;li class="nav-item" [routerLinkActive]="['link-active']"&amp;gt;
                &amp;lt;a class="nav-link text-dark" [routerLink]="['/fetch-data']"&amp;gt;Fetch data&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
              &amp;lt;li&amp;gt;
                &amp;lt;button class="btn btn-primary" (click)="login()" *ngIf="!loggedIn"&amp;gt;Login&amp;lt;/button&amp;gt;
                &amp;lt;button class="btn btn-primary" (click)="logout()" *ngIf="loggedIn"&amp;gt;Logout&amp;lt;/button&amp;gt;
              &amp;lt;/li&amp;gt;
            &amp;lt;/ul&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/nav&amp;gt;
    &amp;lt;/header&amp;gt;
    ```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Run the app and test authentication&lt;/li&gt;
&lt;/ol&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- When viewing the Fetch Data page, if you are not logged in, you will be redirected to the Microsoft login screen. If you are not redirected, click the Login button.

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;When logging in for the first time, you will need to approve the app's permissions&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs0v2v3kwx3ksthag7sl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs0v2v3kwx3ksthag7sl7.png" alt="Permissions requested" width="476" height="616"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After successfully logging in, refresh the Fetch Data page. The weather data should load.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
&lt;br&gt;
&lt;br&gt;
Redeploy to App Service&lt;br&gt;
&lt;/h2&gt;


&lt;ol&gt;
&lt;li&gt;Following the same steps as before, publish the web app and deploy it to the App Service.&lt;/li&gt;
&lt;li&gt;Load the webpage and verify the authentication works.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Things to Consider
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;For security purposes, you can configure the &lt;code&gt;appsettings.json&lt;/code&gt; settings in the Configuration section in the App Service instead. This way, you aren't committing the client and tenant IDs in source control.&lt;/li&gt;
&lt;li&gt;For each API endpoint you want to secure, add the &lt;code&gt;Authorize&lt;/code&gt; attribute to the controller and add a new entry to the &lt;code&gt;protectedResourceMap&lt;/code&gt; in &lt;code&gt;app.module.ts&lt;/code&gt; with the given endpoint.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Authentication can be tricky, but with the &lt;code&gt;msal-angular&lt;/code&gt; package and the Microsoft Identity platform it's rather easy. With these libraries handling the technical details, we just have to handle the configuration.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>angular</category>
      <category>dotnet</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Differences between Traditional and Event-Driven Systems</title>
      <dc:creator>Adam Swanson</dc:creator>
      <pubDate>Thu, 11 Mar 2021 19:58:40 +0000</pubDate>
      <link>https://dev.to/theaswanson/differences-between-traditional-and-event-driven-systems-1khg</link>
      <guid>https://dev.to/theaswanson/differences-between-traditional-and-event-driven-systems-1khg</guid>
      <description>&lt;p&gt;Application state is often treated like food in a fridge. If we need something, we take it out, use what we need, and put it back. The same is usually done with data: we read the data we need, manipulate it, and write it back to the same place.&lt;/p&gt;

&lt;p&gt;This approach has its advantages: managing data becomes very simple. Data can be read from, say, a database, and it can be updated in the same format and in the same place. However, there are downsides: the app's state becomes one big blob of data. Sure, it's structured and organized, but how did it get to its current state? There's no record of the steps it took to get there. All we know is we have data.&lt;/p&gt;

&lt;p&gt;Let's use accounting as an example. Say we spend $10. How do we update our balance? Do we take our current balance, remove $10, and update it? If we did that, we would have no way of tracking our account history. Instead, we add a record of it in our account ledger. To get the new balance, we add up all the transactions in the ledger. We never update the balance directly.&lt;/p&gt;

&lt;p&gt;There are a few key differences here. The first is how the balance is defined. The naive approach is to treat it as a value that can be changed at-will. A better approach is to treat it as the result of changes. The second is the distinction between updating and reading. In the first approach, we write to the balance by updating a single value, and to get the balance we read that same value. In the second approach, we write by appending a new change to a log, and we read by adding up all of those changes.&lt;/p&gt;

&lt;p&gt;Event-driven systems introduce these same differences. If we treat each change to the system as an event (like &lt;code&gt;EmailChanged&lt;/code&gt; or &lt;code&gt;ItemAddedToCart&lt;/code&gt;) and store these events, we can add them up to get our app's state. A common example is a version control system like Git. Each change is represented as a commit, and by adding up all the commits we can produce the codebase.&lt;/p&gt;

&lt;p&gt;By storing each change like this, we get several advantages. One advantage is we can represent the app's state in any form we want. If we want to use a database, JSON, or something in memory, we can build up a model of the app's state from the events. In fact, we could have several models. Another advantage is we can see all the changes that were made to the system. Log messages can be helpful, but they don't often include all the necessary details to understand what's going on. Events, on the other hand, have all the details already baked in.&lt;/p&gt;

&lt;p&gt;When implementing an event-driven system, the app's architecture must be updated to support an event-driven approach. If a change is made, one can no longer reach into the data and update it themselves. Instead, they simply raise an event with the details of what needs to be changed. This event is then stored and processed by an event handler that can build up a model of the app's state in, say, a database. This database can then be used to read the app's state without needing to touch any events.&lt;/p&gt;

&lt;p&gt;There are several pros to event-driven systems. First, they provide a log of every change made to the system. These are represented in the events. Second, they give the ability to see what the state was at any point in time. This can be done by building up a model of the app's state from the events up to a certain time. Third, the app state can be rebuilt from the events at any time.&lt;/p&gt;

&lt;p&gt;The biggest con to event-driven systems is complexity. It becomes harder to follow the flow of control through the system when most of it happens in event handlers. By raising an event, you don't know what, if anything, will handle that event. It is up to a handler, somewhere, to be watching for it. This is much harder to follow than a simple call like &lt;code&gt;cartService.addItem()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Keep these differences in mind when considering an event-driven architecture for your next project. Not all projects will benefit from this approach, but if the pros outweigh the cons, it may be a good choice.&lt;/p&gt;

</description>
      <category>eventdriven</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Updating the .NET Core Angular template from Angular 8 to 10</title>
      <dc:creator>Adam Swanson</dc:creator>
      <pubDate>Thu, 11 Mar 2021 19:56:53 +0000</pubDate>
      <link>https://dev.to/theaswanson/updating-the-net-core-angular-template-from-angular-8-to-10-bfi</link>
      <guid>https://dev.to/theaswanson/updating-the-net-core-angular-template-from-angular-8-to-10-bfi</guid>
      <description>&lt;p&gt;Creating a new .NET Core project with the Angular template is pretty handy, but it starts you out on Angular 8. The upgrade process to version 10 is not very straightforward and can cause some serious headaches if you're not sure what to look out for. Thankfully, I recently completed this process and wanted to share the steps I took to perform a successful upgrade.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; a lot of these steps can be found on Angular's Update Guide here: &lt;a href="https://update.angular.io/"&gt;https://update.angular.io/&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All of the following commands should be run from &lt;code&gt;&amp;lt;project-directory&amp;gt;/ClientApp&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Update the current version of Angular 8&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ng update @angular/core@8 @angular/cli@8&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Upgrade to version 9&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ng update @angular/core@9 @angular/cli@9&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Remove &lt;code&gt;export { renderModule, renderModuleFactory } from '@angular/platform-server'&lt;/code&gt; from &lt;code&gt;main.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Without removing these exports, the following error will be thrown at startup: &lt;code&gt;Uncaught SyntaxError: Strict mode code may not include a with statement&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;More info: &lt;a href="https://stackoverflow.com/questions/60114758/uncaught-syntaxerror-strict-mode-code-may-not-include-a-with-statement"&gt;https://stackoverflow.com/questions/60114758/uncaught-syntaxerror-strict-mode-code-may-not-include-a-with-statement&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ng add @angular/localize&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This is required since the Angular template seems to rely on Angular's internationalization system (i18n)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Change &lt;code&gt;progress: false&lt;/code&gt; to &lt;code&gt;progress: true&lt;/code&gt; in &lt;code&gt;angular.json&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Without changing this value, the app will fail to start and the following error will be displayed on startup: &lt;code&gt;TimeoutException: The Angular CLI process did not start listening for requests within the timeout period of 0 seconds&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;More info: &lt;a href="https://stackoverflow.com/questions/60189930/timeoutexception-the-angular-cli-process-did-not-start-listening-for-requests-w"&gt;https://stackoverflow.com/questions/60189930/timeoutexception-the-angular-cli-process-did-not-start-listening-for-requests-w&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;npm uninstall @nguniversal/module-map-ngfactory-loader&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Remove &lt;code&gt;ModuleMapLoaderModule&lt;/code&gt; import and reference from &lt;code&gt;app.server.module.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Upgrade to version 10&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ng update @angular/cli @angular/core rxjs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Upgrade dependencies&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;npm install -g npm-check-updates&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;This package will help upgrade all dependencies to their latest version&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ncu -u&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm install&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm update&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;npm audit fix&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Voila! You are now running your .NET Core Angular project in version 10. Again, these are just the specific steps for going from version 8 to 10. To upgrade to other versions, check out Angular's Update Guide at &lt;a href="https://update.angular.io/"&gt;https://update.angular.io/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>dotnet</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
