nuget Package Manager fails with 401 error

If you are connecting to a private nuget feed you may run into an issue when you first set up the connection, or after updating your password, that you can’t connect to the feed. The error console will report that it was unable to load the service index and the status result was 401. The fix that I’ve found to work has been using the update option through the dotnet nuget command. In my experience, it is often caused because credentials haven’t been set or have changed and the feed is using the old ones.

Update nuget feed

Updating a nuget source is fairly straightforward. The only way I have been able to do so is via the command line, if there is a way through Visual Studio I’d be interested to hear about it. Before using the command line you’ll need to download the .NET SDK if you haven’t done so already. If you are already compiling code on the machine then it is installed and you are ready to go.

To update an existing nuget feed, let’s call the feed InternalCompanyFeed, you need to run the update option. In the below example, we will update the InternalCompanyFeed by setting the username to bnolan and the password to $3cuR3PaS$w0rd.

dotnet nuget update source InternalCompanyFeed --username bnolan --password $3cuR3PaS$w0rd

Depending on the authentication type you may need to set the type(s) to use the --valid-authentication-types option. The standard options are basic, negotiate, kerberos, ntlm, and digest. I haven’t needed that yet but would be interested to hear what setup has required someone to set the option.

CSS breaking Leaflet map rendering

TLDR; Be specific with img element styling definitions, otherwise they could impact the rendering of Leaflet maps.

I didn’t do it on purpose, but at some point, over the last few months, I broke my usage of Leaflet.js in a React app using the react-leaflet library. It was one of those worst-case scenarios where it kind of works but definitely doesn’t work and quite frankly I couldn’t wrap my head around what caused the break. I hope that my suffering can keep someone else from going through the same. Here is what happened.

After I had made some updates to incorporate the MUI library as the primary user interface, and added components to handle the main layout of the website, I ran through some tests to verify there were no unintended side-effects. Everything checked out except the mapping feature. What I saw was that the tiles were all visible but laid out in the wrong order and the marker pin was taller than it should along with appearing cropped.

Broken Leaflet map

The typical problems with Leaflet are implementations that don’t reference the Leaflet CSS style sheet. When this happens you’ll see either no tiles or tiles with lots of white space surrounding them. However, since my project uses the react-leaflet library there is no need to also reference the Leaflet JavaScript. The CSS reference was verified to have been added to the index.html file of the project and there were no references to the Leaflet JavaScript code.

My next thought was that some parts of the UI libraries being used were causing problems. Going through the packages.json file I saw that there were multiple bootstrap libraries referenced in addition to the MUI library. There was no need for them so I pulled out all of the bootstrap references and cleaned up the core CSS/SCSS files. Still no luck.

At this point, I thought it made sense to try and recreate the issue in a clean project. I took all of the packages referenced in my current project and added them to a new project on Stackblitz, ReactJS-MaterialUI-Leaflet. In doing so I created a basic implementation that used MUI and Leaflet but still didn’t see the issue.

Since this implementation ruled out possible conflicts with MUI and other referenced JavaScript libraries I assumed that somewhere in my code I must have a component defining CSS/SCSS that was causing the problems. To prove it out I then brought over the parent components. An immediate success, the failure was repeated.

To find the specific cause of the failure I began removing the parent components until the maps started rendering correctly. Luckily it didn’t take long to find that there was a style defined for the header image which was causing the problem.

img {
  object-fit: cover;
  width: 100%;
  max-height: 400px;
  min-height: 400px;
}

This style was used as part of the main header image and not one I wanted to remove. To keep it, I changed the style from being element-focused to being a class name, .header-img, and scoped to the particular component. A simple change, eight total characters, but it ensured that the images used by the map weren’t given the wrong styling.

You can see the problematic implementation in my Github and Stackblitz projects. Feel free to fork the project and remove the bad styling to see the fix in action.

Using Serilog sub-loggers in .NET Core/5

If you aren’t familiar with Serilog, it is a powerful, full-featured logging library that integrates seamlessly with .NET Core/5. Some of the features it provides are flat and structured logging, numerous plugins to write data to various endpoints (called sinks), and an implementation that can be easily extended.

One of the concepts that Serilog brings to the logging world is the ability to create sub-loggers. A standard logging setup will have logs written out to a file, console, and/or a database. But if you want to write out to multiple instances of a sink then what you’ll want to look into are sub-loggers. Sub-loggers enable the instantiation of more than one instance of a sink with a custom configuration applied to each one. Some reasons that you might want to do this would be:

  • Output multiple formats of logs to a file system for digestion by different monitoring applications.
  • Recording log output from specific classes to their own files.
  • Generating multiple log files based on specific filters.

In this post I’ll show an example where we use appsettings.json to configure the logging library. Within the SpaHost project two log files will be created. One will contain all log entries while the other will hold only log entries with the level error or above. Within a second project, CrossDomainApi, we’ll have another scenario defined where one log file will contain all log entries while a second log file will contain only the log entries that originate from the Api.TestController namespace.

In order to get this configuration working a few NuGet packages need to be added.

Within the startup code of the ASP.NET Core/5 application a small bit of standard code is required. Within the Program.cs:CreateWebHostBuilder() method we need to add .UseSerilog() to the call chain. This will set Serilog as the logger for the web app. In this implementation we also make calls set the configuration, use IIS settings and capture startup errors. Depending on your implementation you may not need those calls.

public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
   var configuration = GetConfiguration();
   return WebHost.CreateDefaultBuilder(args)
      .UseSerilog()
      .UseConfiguration(configuration)
      .UseIIS()
      .CaptureStartupErrors(true)
      .UseStartup<Startup>();
}

The rest of the core logging configuration is defined in the appsettings.Development.json file. If you would rather define the logging setting in code you can do so but I personally like defining the set up in configuration files so we can customize logging based on the environment where the application is executing.

Within this file there is a section named "Serilog" that defines how the logger will handle log events, what gets written, and where those events are written. The sample below is fromthe CrossDomainApi‘s configuration file. As mentioned earlier this configuration writes logs to two files, one with all log events and another with only log events from a specific namespace.

{
  "Serilog": {
    "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ],
    "MinimumLevel": {
      "Default": "Information",
      "Override": {
        "Microsoft": "Warning",
        "System": "Warning"
      }
    },
    "WriteTo": [
      {
        "Name": "Console",
        "Args": {
          "outputTemplate": "{Timestamp:HH:mm:ss.fff zzz}|{Level}|{ThreadId}|{SourceContext}|{Message:lj}|{Exception}{NewLine}"
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "rollingInterval": "Day",
                  "path": "C:/Logs/CrossDomainApi/all-.log",
                  "outputTemplate": "{Timestamp:HH:mm:ss.fff zzz}|{Level}|{ThreadId}|{SourceContext}|{Message:lj}|{Exception}{NewLine}"
                }
              }
            ]
          }
        }
      },
      {
        "Name": "Logger",
        "Args": {
          "configureLogger": {
            "Filter": [
              {
                "Name": "ByIncludingOnly",
                "Args": {
                  "expression": "Contains(SourceContext, 'Api.TestController')"
                }
              }
            ],
            "WriteTo": [
              {
                "Name": "File",
                "Args": {
                  "rollingInterval": "Day",
                  "path": "C:/Logs/CrossDomainApi/api-.log",
                  "outputTemplate": "{Timestamp:HH:mm:ss.fff zzz}|{Level}|{ThreadId}|{SourceContext}|{Message:lj}|{Exception}{NewLine}"
                }
              }
            ]
          }
        }
      }
    ],
    "Enrich": [ "FromLogContext", "WithMachineName", "WithThreadId" ],
    "Properties": {
      "Application": "CrossDomainApi"
    }
  }
}

What makes this configuration use sub-loggers are the child definition of "WriteTo" within the array of "WriteTo" objects. In this case we have two sub-loggers, both write logs via the "File" sink. It is in the last Logger that we apply a filter within the "configureLogger" object definition. This filter first checks that the SourceContext value contains the string Api.TestController. All log events that match this check will be sent to the sub-logger for processing.

With this configuration in place you can add an ILogger<classname> parameter to your controllers for writing out the log files. The Dependency Injection system provided by .NET will automatically pass in the instance of ILogger that was defined during startup. Additionally, any logging output by referenced projects or libraries will also use the configured Serilog instance.

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;

namespace Api
{
    [Route("test")]
    public class TestController : ControllerBase
    {
        private readonly ILogger<TestController> _logger;

        public TestController(ILogger<TestController> logger)
        {
            _logger = logger;
        }
        public IActionResult Get()
        {
            _logger.LogDebug("Request received");
            return new JsonResult("OK");
        }
    }
}

To see the working solution take a look at the BackendForFrontend project. This project also demonstrates using an external Identity Server for authentication which was written up about in How to use Backend for Frontend to simplify authentication in an Angular SPA.

Mind Your Spaces in an IIS web.config Definition

This last week we spent the better part of a day chasing down a space. A single white-space character that was breaking an Internet Information Service (IIS) deployment for a website. Debugging the issue would have been straight forward except that all of the errors were pointing us in the wrong direction. To start let me provide details on our deployment.

The website was a .NET 5 Web API hosted in IIS. The project had been modified so that it would generate a DLL and not an EXE upon being compiled. This was done by adding <UseAppHost>false</UseAppHost> within the <PropertyGroup> to the .CSPROJ of the Web API. By default the UseAppHost value is true which will cause the build to generate a framework dependent executable. For our situation the default configuration wasn’t desired. Additionally, since we were no longer generating an EXE that IIS could use to launch the application we also needed to update the web.config.

Within the web.config the launch definition is contained in the <aspNetCore> element. Initially the element was defined with the processPath attribute pointing to the framework built EXE of the project. Now that we weren’t generating this executable we needed to define how IIS would launch the site. To do this we updated the processPath attribute to point to the dotnet.exe binary that was installed with the .NET Core Hosting Bundle. We also added the arguments attribute passing in the exec command and path to the project’s main DLL. In the end the <aspNetCore> element looked like this.

Broken web.config

<aspNetCore processPath="dotnet.exe"
            arguments=" exec .\WebApi.dll"
            stdoutLogEnabled="false"
            stdoutLogFile=".\logs\stdout"
            hostingModel="inprocess">
  <environmentVariables>
    <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
  </environmentVariables>
</aspNetCore>

With these updates in place we deployed the app to our development environment and found that the site was displaying a 500.31 error.

HTTP Error 500.31 – Failed to load ASP.NET Core runtime
Common solutions to this issue:
The specified version of Microsoft.NetCore.App or Microsoft.AspNetCore.App was not found.
Troubleshooting steps:

Check the system event log for error messages
Enable logging the application process' stdout messages
Attach a debugger to the application process and inspect

For more information visit: https://go.microsoft.com/fwlink/?LinkID=2028526

The guidance from the Microsoft page tells us to look at the Application Event logs for further details. In examining the events we see three separate error events reported against IIS.

  1. Unable to locate application dependencies. Ensure that the versions of Microsoft.NetCore.App and Microsoft.AspNetCore.App targeted by the application are installed.
  2. Could not find ‘aspnetcorev2_inprocess.dll’. Exception message:
  3. Failed to start application ‘/LM/W3SVC/1/ROOT/WebApi’, ErrorCode ‘0x8000ffff’.

We verified the installation, and re-installed, the .NET Hosting Bundle, checked to make sure that all of the files needed for the site were being deployed, ran a check for all dependencies, and even ran the dotnet.exe command and arguments from the command line. Everything checked out and looked good. Performed the standard exhaustive search on StackOverflow but didn’t have any success with the suggested fixes.

Finally, since the application worked locally from Visual Studio we started walking through the startup process. Since no logs were generated during startup we took a look at our web.config and transformation files. What we found was that in the arguments definition of the <aspNetCore> element there was an extra space between the quote and exec command.

<aspNetCore processPath="dotnet.exe" arguments=" exec .\WebApi.dll" …/>

It seemed improbable that the extra space would be causing such havoc on the IIS deployment but it was in fact the problem that broke the website. We removed the extra space and the fixed configuration file was deployed. To our surprise all errors went away.

Fixed web.config

<aspNetCore processPath="dotnet.exe"
            arguments="exec .\WebApi.dll"
            stdoutLogEnabled="false"
            stdoutLogFile=".\logs\stdout"
            hostingModel="inprocess">
  <environmentVariables>
    <environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
  </environmentVariables>
</aspNetCore>

So pay attention to the spaces in your web.config deployment and transformation files. The error details provided by IIS and the event logs certainly did not indicate the underlying issue in this instance. But through a process of elimination we were able to track down the cause of issue and fix it.

How to use Backend for Frontend to simplify authentication in an Angular SPA #aspnetcore #identityserver4 #angular

For longer than I care to admit I’ve been trying to find an easy to implement authentication system with my Angular SPA. I’ve looked at rolling my own, utilizing Identity Server and the oidc-connect.js library, Auth0, as well as probably a half dozen other options. After experimenting around, reading blogs and articles on the subject, and checking out some sample implementations I’ve settled on a solution geared towards Single Page Applications (SPAs).

What I’ve picked is known as a Backend for Frontend architecture that uses Identity Server to manage authentication. The structure of the solution moves a lot of the authentication logic out of the SPA and into the backend .NET API. This means that instead of the SPA receiving a JSON Web Token (JWT) after authentication, and then managing the refresh and expiration of said token, the backend API will take ownership of managing the authenticated session and provide the SPA with a way to associate itself with that session. Besides these reasons, there are also security reasons for picking this type of implementation over a more client heavy implementation. Take a look at the post by Dominick Baer on his blog Least Privilege where he goes over many of these reasons. In fact the basis for my example implementation is based on his example from that post.

What I’ve changed from Dominick’s example is that I’ve added an Angular SPA project with a .NET BFF to manage the authenticated sessions. Additionally I swapped out the usage of ProxyKit as a reverse proxy with Microsoft’s Reverse Proxy. ProxyKit‘s development has ceased and the owner recommends migrating over to Microsoft’s implementation. While Reverse Proxy is still in preview it hopefully we will have a 1.0 release in the next few months.

The code for my example project can be found on GitHub. Admittedly there is a lot going on in this project. If you are running the solution in Visual Studio you will want to kick off the SpaHost and CrossDomainApi projects at the same time. The SpaHost will run on it’s own but one of the pages does pull down data from the CrossDomainApi when the user is authenticated so it is good to have them both running.

As it is currently implemented the project uses the publicly available Demo Identity Server. Both the HostSpa and CrossDomainApi point to this Identity Server. The CrossDomainApi checks for a JWT encoded Bearer Authentication header that contains an audience of api. If this isn’t present then the API request from a client will be denied.

The HostSpa hosts the Angular SPA and a reverse proxy to direct some requests to external services, in this case the CrossDomainApi. The configuration for utilizing Identity Server and defining the Reverse Proxy are all performed in the Startup.cs. The Reverse Proxy itself reads it’s configuration out of the appsettings.Development.json. However, in order to include the Bearer token in requests to proxied endpoints, code is added to the endpoint mapping which pulls the JWT out of the context and adds it to the Header.

endpoints.MapReverseProxy(proxyPipeline =>
{
   // The proxied controllers need the bearer token
   proxyPipeline.Use(async (context, next) =>
   {
      // If we are authenticated than we should be able to get the access token
      // from the context associated with this session
      var token = await context.GetTokenAsync("access_token");
      context.Request.Headers.Add("Authorization", $"Bearer {token}");

      await next().ConfigureAwait(false);
   });
});

The majority of the remaining code in the class deals with setting up the identity provider. I highly recommend reading the documentation for Identity Server 4 if you are unsure what all is being defined. Besides the standard OIDC configuration there are also lines of code which setup the token management and storage.

Managing access tokens takes a lot of work. You need to handling refreshes, sliding windows, revocation, storage, etc. Luckily the developers of Identity Server created a .NET library, IdentityModel.AspNetCore, which handles all of this for you. Documentation on it can be found in the Identity Server 4 documentation site.

// We want to enable the automatic management of tokens, auto refresh, in-memory storage
services.AddAccessTokenManagement();

The other piece of the puzzle is where will the tokens be stored. For development purposes keeping the tokens in memory is a suitable solution. For that we can use the AddDistributedMemoryCache() feature which you can learn more about it and other options on the documentation site. This will keep the tokens in memory for as long as the site is running.

// Enable the in-memory storage of tokens. In production or a multi-hosting environment
// you will want to use a SQL Server or Redis-like cache so tokens aren't lost during a
// reboot or deployment.
services.AddDistributedMemoryCache();

Within the Angular SPA the authentication piece is very limited. We don’t handle any of the actual authentication process. Instead we redirect the user to a controller that returns a view which requires the user to be authorized via the [Authorize]decorator. By loading this view the user will be automatically directed to the Identity Server configured in the Startup.cs class if they don’t have an active session. To see the controller logic take a look at the AccountsController.cs class. Within it you will see a function called Index(string redirect) which takes a single parameter, redirect. The value of this variable determines where the user will be sent to after they have been authenticated.

Once the user is authenticated they will have full access to the SPA site. A demonstration of how to restrict users access via authorization guards and how to force a user to authenticate when they access a publicly available page is available in the SpaHost project. Review the fetch-authenticated-data, guarded-root, auth-guard, app.module for details.

Please take a look and let me know if you have any questions or suggestions. I hope this post and the BackendForFrontend GitHub project are able to help you on your project.

TLDR; Go to my BackendForFrontend project on GitHub to see an example solution which uses Microsoft’s Reverse Proxy, Identity Server 4, and Angular to simplify identity configuration in a SPA.

Methods for learning a project’s code base

Picking up an existing code base can be intimidating. If you’re lucky the code is documented and the previous developer(s) is around and willing to explain the architecture. But if you are like everyone else in this world you find yourself staring at thousands of lines of undocumented code with no place to turn for help. There are a number of ways you can attack the problem and this post will go over some of the ways I’ve had success with.

Where to start.

When you have a project with more than just a few files the problem arises of where to start your investigation. When it comes to executable applications don’t get creative. Find the entry point of the application and start there. For projects where the output is a library you most likely won’t have a single entry point from which to start. In these cases treat each entry point of the library as it’s own mini application. Pick one and start there.

Depending on the size of the code base you may not be able to go through all of the files and functions. Don’t worry about this. If you can get an idea on the main areas of the application that are used then focus on them. Or, take a look at the open issues and feature requests. Use those to help guide you on where to spend your time.

Do while reading unfamiliar code.

Comment. If you can’t look at a file and immediately know what the point of the code is or how it achieves it’s end result then add comments. Breakdown complex logic into an easily understood explanation in the comments. The write-up, 13 Tips to Comment Your Code, gives a great overview of where and how to comment code. If you are in a situation where you can’t comment the code then use your favorite note taking application/book and put your comments there.

If the code is in GitHub or some other repository that allows for easy linking into the code then take advantage of it. As you make notes in your application include a link to the file, function, or line number. When that isn’t possible, be sure to include the filename, and function or line of code in the notes to easily associate the comments back to the code.

When I am able to comment in the code my preference is to, at a minimum, comment at the function-level. Explain the purpose of the code and provide the IDE with details it can show in IntelliSense. This requires using specific commenting styles based on the language or IDE but it is worth it. When you use the function elsewhere in the code your comments will automatically appear in a well formatted structure. In cases where the function is large and can’t be broken up then I’ll add comments to point out where things could be split out should the time come to refactor it.

Diving deeper into the code.

With the entry point(s) found it is time to start tracing through the code. If you can’t execute the code in a test environment then manually walk through the logic and and take notes. Write down a test case of possible input values and the relevant generated output. In some cases you may need to copy the code out to another new project and run it there to understand what the logic is doing. Don’t feel bad doing this; if it helps you understand the logic then do it. If you remember better by drawing out the logic flow then draw it and be sure to include your drawing in your notes. In scenarios where I had an expert in the code at questions available I’ve even used video conferencing applications and screen recording to document both the user-interface and underlying logic as explained by them for future reference.

In some cases a function may be defined in an independent way from the rest of the application that lends it to be testable by unit tests. When this happens then by all means create a unit test. It will not only help you understand the purpose of the function, it will also give you the reassurance later on that the function is operating properly when changes are made.

When you do find yourself struggling to understand what it is you are looking at don’t be afraid to ask for another set of eyes and ears. It doesn’t matter if the other person can code, having someone there for you to talk to about the code, explain the logic, and bounce ideas off of will help. If the person can code then let them take a look before you start explaining what you think is happening. This will let them formulate their own thoughts without the influence of yours. Hopefully, even if you both don’t understand the logic, you can work through it from different perspectives and figure it out. I’ve also had a lot of success getting a user of the application explain what is going on from their perspective. This viewpoint helps get you out of the weeds of the code and see what will be the visual results.

When you can execute the code in a debug session then by all means do it. Step through the code with example inputs and see how the logic handles different use cases. This should simplify the learning process by allowing you to see exactly how the application executes. An even better situation is if you can also comment the code while debugging it.

Remember.

One, of many, things to remember is that if you can’t believe the person wrote the code the way that they did, determine that the original author was a complete idiot, or desire to curse them for life, someone else out there looking at your code will probably feel the same way. Building software systems is not an easy task, nor a one perfect solution task. The person could be new, thrown into the project at the last minute, had a bad day, look at problems differently than you, or be years beyond your expertise. So don’t judge the author, focus on the logic.

TLDR;

  • Find a good entry point to start your investigation.
  • Add comments in the code anywhere you don’t understand the purpose of the code.
  • Don’t be afraid to copy code to a test project, create unit tests, or get a second person to look at it with you.
  • Don’t judge the author, focus on understanding the logic.

Visualizing #D3JS line chart curve styles in #AngularIO

Prior to writing this post I hadn’t realized just how many line charting algorithms D3.js provided. When I started reading about them I thought there would be a fair share of configuration in order to get each one working but to my surprise it was dead simple. With a single line of code a chart can use one of the 18 line curves options that D3.js provides.

In a previous post, Adding a #D3.js line chart to an #Angular.io project, I went over how to create a D3 line chart in Angular. This post will expand on that work to show the various curve options and how to display visual indicators of data points on a chart. If you aren’t familiar with how to get a D3.js chart to work in Angular.io then take a look at the earlier post to get started.

The completed project can be seen running on StackBlitz and the code is available at GitHub. The example shows the following line curves.

  • Default
  • curveBasis
  • curveBasisOpen
  • curveBasisClosed
  • curveBundle
  • curveCardinal
  • curveCardinalOpen
  • curveCardinalClosed
  • curveCatmullrom
  • curveCatmullromOpen
  • curveCatmullromClosed
  • curveLinear
  • curveLinearClosed
  • curveMonotoneX
  • curveMonotoneY
  • curveNatural
  • curveStep
  • curveStepBefore
  • curveStepAfter

As mentioned earlier selecting your curve style is extremely simple. When initializing the line component of the chart, the curve style can be set by calling the curve() function on the line and pass the function for the algorithm to generate the curve. If, for example, you want the line to follow the Cardinal curve algorithm then you would apply that curve by doing line.curve(d3.curveCardinal) before adding the line to the graph svg element. Amazingly enough, that is it. As long as you are going to use a built-in curve you are done.

One thing I noticed was that with some of the curves it can be difficult to tell where the actual data point resides on the chart. To help visualize those points we can add markers to the chart. This next section of code will add a red circle marker with a radius of 5 pixels on each data point.

this.circleMarkers = this.svg
  .selectAll("circle")
  .data(this.data)
  .enter()
  .append("circle")
  .attr("fill", "#ff0000")
  .attr("cx", (d: any) => this.x(d.date))
  .attr("cy", (d: any) => this.y(d.value))
  .attr("r", 5);

The result of a cardinal curve applied to the data and the display of the data points with red circles is shown in the image below . Take a look at all of the examples which are using the same data set but implement different curves to see how the curves differ in style.

Showing an #Angular Component in place of #LeafletJS popup dialog

In an earlier post we went over the steps to add a LeafletJS map to an Angular application. The example initialized the map to be centered over Europe and then when the user clicked on a button the map would pan over to Philadelphia, Pennsylvania USA and draw a circle marker over the city. To improve the usability of the map we are going to add a custom Angular component as the popup that appears when the user clicks on the circle. We’ll also show how to pass data to the component so it can be customized based on the marker clicks.

Starting off we’ll use the code from the original map project, angular-ivy-leaflet-map, as the base for this project. The completed solution for this post can be found on GitHub and a working demonstration can be seen on StackBlitz.

To show a custom popup we’ll create a new component that will serve as the popup dialog. From the console window generate the boiler plate code for the CustomPopup component via

ng g component CustomPopup

In the CustomPopup folder open the custom-popup.component.html file and add {{customText}} in a paragraph element that will serve as the dynamic text element that we’ll set from the calling component.

<h1>Custom Popup</h1>
<p>
An angular component rendered as a map popup.
</p>
<p>
  {{customText}}
</p>

In order to allow the parent component to set the value of the {{customText}} property we need to add it to the custom-popup.component.ts as an @Input property. This will also require adding Input as an import from @angular/core. This is no different then the normal way to pass data to a component in Angular.

import { Component, OnInit, Input } from '@angular/core';

@Component({
  selector: 'app-custom-popup',
  templateUrl: './custom-popup.component.html',
  styleUrls: ['./custom-popup.component.css']
})
export class CustomPopupComponent implements OnInit {
  @Input() customText: string
  constructor() { }

  ngOnInit() {
  }
}

With the popup component complete the next step is to add code to the map component so it will use this CustomPopupComponent instead of the default LeafletJS popup.

For the Angular component to be usable by LeafletJS we need the component to be “transformed” into its final HTML and JavaScript form. Without the component in its final form, LeafletJS will have no idea what to do with component reference when it renders the popup.

Now I can’t take credit for this code that generates the usable form of the component. Credit goes to Darkguy2008 who had run into the exact same issue with LeafletJS that this post is going over. The code uses Angular’s ComponentFactoryResolver to transform the referenced component into a usable form. What follows is my understanding of how Angular renders the component on the fly.

The resolveComponentFactory() builds a model of the component based on its HTML and TypeScript definition. All external references are verified and linked to model. Then when the create() method is called it iterates through the component and builds its final form based on the model from the factory method result. Finally, the built component is attached to the view via the application reference and surround it with a div element so that no matter how the component is defined it has a single parent element for the popup.

private compilePopup(component, onAttach): any {
   const compFactory: any = this.resolver.resolveComponentFactory(component);
   let compRef: any = compFactory.create(this.injector);

   if (onAttach)
     onAttach(compRef);

   this.appRef.attachView(compRef.hostView);
   compRef.onDestroy(() => this.appRef.detachView(compRef.hostView));

   let div = document.createElement('div');
   div.appendChild(compRef.location.nativeElement);
   return div;
}

The last step is to call the compilePopup() method and pass the rendered view to the marker for the popup. We assign the generated view to the markerPopup variable and then assign it to the marker as the popup view through the bindPopup() method call. One other thing to note is the assignment of the customText variable for the CustomPopupComponent. We pass the assignment as an anonymous function that takes the component as a parameter. It then references the built instance and sets the @Input customText variable.

let markerPopup: any =
this.compilePopup(CustomPopupComponent,
(c) => {c.instance.customText = 'Custom Data Injection'});
// Generate a circle marker for this location
let currentLocation: L.CircleMarker = L.circleMarker([lat,

lng], { radius: 5})
// Add a binding for the popup to show a custom component
// instead of the standard leaflet popup
.bindPopup(markerPopup);

The final solution can be seen in action below or at StackBlitz. If you are running the project you will need to click on the Locate Philadelphia, PA button and then click on the circle marker to display the popup. To see the full project source code go to GitHub.

Generating Entity-Framework classes for .NET Core projects in a Database First scenario

Microsoft provides two command line tools in situations when there is a need to generate Entity Framework classes for a .NET Core project. Within the Package Manager console of Visual Studio you can use Scaffold-DbContext and if you are using the .NET Core CLI then the command dotnet ef is available. Details on the capabilities (migration, scaffold, update, drop, and more) as well as instructions on what needs to be installed can be found on EF Core tools reference – .NET Core CLI and Entity Framework Core tools reference – Package Manager Console in Visual Studio.

When using dotnet ef command in the .NET Core CLI you will add the scaffold argument which will allow you to generate classes for an entire database, specific tables, or schemas within a database. If you are using it against a specific set of tables then you will provide each table with the –table flag preceding the table name.

In this example the command will generate EF classes in order to interact with two common Identity tables, AspNetRoleClaims and AspNetRoles, within the dbo schema.

dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=IdentityServer;" Microsoft.EntityFrameworkCore.SqlServer --table dbo.AspNetRoleClaims -table dbo.AspNetRoles

Having the tool generate classes for a schema is just as simple. Instead of using the –table use –schema and provide the schema name.

If there comes a need to regenerate tables or add more then you will need to use the –force flag. This will allow the process to overwrite any files that already exist in the project. Make sure you include all tables or schemas that you want generated. Even if a table hasn’t changed since the earlier schema change you will still need to list it when regenerating the classes.

If you prefer to use the Package Manager console then the same command from above could be executed using only small changes. Instead of a flag for each table you will combine all tables in a space separated list within enclosing quotes.

Scaffold-DbContext -Provider Microsoft.EntityFrameworkCore.SqlServer -Connection "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=IdentityServer;" -Tables dbo.AspNetRoleClaims, dbo.AspNetRoles

This post went over only a small portion of the capabilities that these tools provide. If you are designing a system to be a Code First approach then you’ll become very familiar with these tools as you generate initialization and migration scripts. If you are unfamiliar with with EF migrations then take a look at Managing Database Schemas to guide you through each step.

Edited 26 April 2021 Fix Scaffold-DbContext syntax error.

Adding maps to an #Angular application using the #Leaflet library

If you are looking to add maps to your Angular website or application a great option that I’ve used on a few projects is Leaflet.js. The library provides features like custom markers, ability to use various map sources, multiple layers, and much more. In addition to that it is also free, open source, and actively maintained. The project has been around for years and has an active community continuing to extend it with numerous plugins. The majority of documentation out there for the library focuses on using it in a vanilla JavaScript project so in this post we’re going to explore adding Leaflet.js to an Angular Ivy project.

In this application we’ll create a component that will hold the map object. It will be configured to always show Europe when it starts up but also provide a button to pan the map to a specific location. The user can change the zoom or move the map around as they wish. There will also be callbacks setup to execute when the user changes the zoom level or the center of the map. You can see the complete project on GitHub. A running example can also be seen on StackBlitz.

To start off, if you don’t already have an Angular app to add the mapping feature to, create a new one.

$ ng new leaflet-map-example

Once the project is initialized we will need to add references to Leaflet and its Typings definition to the project. This can be done by opening the package.json file and adding
"leaflet": "^1.6.0"
to the dependencies section. In devDependencies add
"@types/leaflet": "^1.5.7"

Another location that needs to be updated is the angular.json file. Under "projects" --> "demo" --> "architect" --> "build" --> "options" --> "assets" add this code that will copy leaflet assets out to the leaflet folder during the build process.

{
    "glob": "**/*",
    "input": "./node_modules/leaflet/dist/images",
    "output": "leaflet/"
}

Also, just below the "assets" section should be the "styles" section. In this section add this line so we can bring the Leaflet styles over to the application during the build.

"./node_modules/leaflet/dist/leaflet.css"

Next we’ll want to create a new component that will hold our logic for this map. From the command line run:

$ ng generate component map

We should now have a new folder in our project called map that contains three files: map.component.css, map.component.html, map.component.ts. The majority of our work will be in the TypeScript file but we still do need to add some code to the CSS and HTML files.

In map.component.html we’ll add two <div> tags, one to encompass the HTML for the page and another to hold the map. At the bottom of the page we will have a button that calls a function in the TypeScript code to pan the map on a specific location.

<div class="map-container">
  <div id="map"></div>
  <br />
  <button (click)="centerMap(39.95, -75.16)">Locate Philadelphia, PA</button>
</div>

Next we’ll add some CSS to define the size and add a border to the map in map.component.css.

#map{
  border: 2px solid black;
  height: 400px;
  width: 100%;
}

With the scaffolding in place we can now focus on map.component.ts to add the code which will instantiate and customize the actual map. The first line of code we’ll add is to import the Leaflet library at the top of the file.

import * as L from "leaflet";

Within the class definition add a variable to hold the map object.

map: L.Map;

We’ll setup the actual actual initialization of the map object and tie it to the HTML DOM in the ngOnInit() function.

The map object will be configured to center the map on a latitude and longitude over Europe. We’ll have the zoom level set to 4 and restrict the permitted zoom levels to be between 1 and 10. Besides those properties the most important part of the initialization is the first parameter, 'map'. This value matches up to the ID field in one of the map.component.html <div> elements and tells Leaflet to use that element to render the map.

// Initialize the map to display Europe    
this.map = L.map('map',
 {
      center: [49.8282, 8.5795],
      zoom: 4,
      minZoom: 1,
      maxZoom: 10
});

Before anything can be displayed we also need to let Leaflet know where to retrieve the tiles for the map. If you aren’t familiar with tiles they are the background image that is displayed. These can be road maps, start charts, or any other image. In this example the tiles are pulled from the OpenStreetMap.org repository. We’ll do this by creating a Tile Layer and then add that layer to the map object.

const tiles = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
  maxZoom: 10,
  attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
});

tiles.addTo(this.map);

In the HTML for the component there is a button that calls a centerMap() function, passing it latitude and longitude values. When called, this function will pan the map over to the new center coordinates, draw a circle marker on that location, and zoom to a specific level.

centerMap(lat: number, lng: number): void {
this.map.panTo([lat, lng]);
// Generate a circle marker for this location
let currentLocation: L.CircleMarker =
L.circleMarker([lat, lng], {
radius: 5
});
currentLocation.addTo(this.map);
// Wait a short period before zooming to a designated level
setTimeout(() => {this.map.setZoom(8);}, 750);
}

With the definition of the map component completed we need to add the component to the app.component.html file so that we can actually see it in the applicaiton.

<app-map></app-map>

There is one last piece of the puzzle that we need to add in order for the maps to be displayed correctly. We need to reference the Leaflet CSS code in the project’s styles.css file. Without the reference we won’t be able to pull the styles into the project.

@import "~leaflet/dist/leaflet.css";

If you forget this piece you’ll see a partial map appear on the site. A few squares of the map will be visible and if you look in the Console window you won’t see any errors reported. The fact that you missed the styles file isn’t obvious so be sure to include it.

At this point we should be able to run the project and see the map displayed similar to the below image.

$ ng serve

Then when you click on the Locate Philadelphia, PA button it will pan the map over to the city and draw a marker on the city.

If there is a need to take actions when the user changes the zoom level of the map or drags the map to a new location it can be achieved by adding listeners to the "zoomlevelschange" and "moveend" events. In this example we’ll add them during the initialization of the map.

// Initialize the map to display Europe
this.map = L.map('map', {
center: [49.8282, 8.5795],
zoom: 4,
minZoom: 1,
maxZoom: 10
}) // Create a callback for when the user changes the zoom
.addEventListener("zoomlevelschange", this.onZoomChange, this)
// Create a callback for when the map is moved
.addEventListener("moveend", this.onCenterChange, this);

From these callbacks you can grab the new center, zoom level, or map boundaries by accession the map object referenced via the this object. You can see examples of these in the map.component.ts file.

Hopefully this post helps get you on your way adding Leaflet maps to your Angular project. Besides a few behind the scenes updates of files the process is straight forward. In a future post I’ll go over adding markers and custom popup dialogs.