ASP.NET Core Middleware Configuration settings access

How do we access the configuration settings in the Middleware component in ASP.NET Core applications?

As we know middleware is a component that is used in the application pipeline to handle requests and responses which can help perform pre and post-operation within the request and response API pipeline.

We will be using two approaches, one with simple configuration and second with IOptions pattern. You can read more about it here;

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-6.0

Create ASP.NET Core API application based on .NET Core 3.1. We will be using this configuration;

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "GlobalConfigurationSettings": {
    "LowerEnvironment": "true",
    "CustomerConfig": {
      "CustomerKeyurl": "http://customer/key",
      "CustomerdetailsUrl": "http://customer/id",
      "Agency": {
        "AgencyID": "subvalue1_from_json",
        "AccountKey": 200
      }
    },
    "AllowedHosts": "*"
  }
}

This is a generic custom middleware;

public class CustomMiddleware
{
   private readonly RequestDelegate _next;

   public CustomMiddleware(RequestDelegate next)
   {
       _next = next;
   }
 
   public async Task InvokeAsync(HttpContext httpContext)
   {
       try
       {
           await _next(httpContext);
       }
       catch (Exception ex)
       {
           throw ex;
           //_logger.LogError($"Something went wrong: {ex.Message}");
       }
   }
}

Approach 1- Using IConfiguration to load the Config settings in Middleware

This approach does not require any custom interface. When CreateDefaultBuilder runs, it load application configuration by default from appsettings.json. This is available to any component in the application.

We are going to inject RequestDelegete and IConfiguration from the constructor in middleware;

public class MiddlewareWithIConfiguration
    {
        private readonly RequestDelegate _next;
        private readonly IConfiguration _configurationSettings;

        public MiddlewareWithIConfiguration(RequestDelegate next, IConfiguration optionsSettings)
        {
            _next = next;
            _configurationSettings = optionsSettings;
        }

Implement InvokeAsync (assuming we need asynchronous middleware behavior) method.

public async Task InvokeAsync(HttpContext httpContext)
        {
            try
            {
                var customerKeyUrl = _configurationSettings["GlobalConfigurationSettings:CustomerConfig:CustomerKeyurl"];
                Console.WriteLine($"Middleware using IConfiguration {customerKeyUrl}");
                await _next(httpContext);
            }
            catch (Exception ex)
            {
                throw ex;
                //_logger.LogError($"Something went wrong: {ex.Message}");
            }
        }

Add this line to Startup.cs file;

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{

            app.UseMiddleware<MiddlewareWithIConfiguration>();
}

Approach 2 – Using IOption to load the Config settings in Middleware

We need to add and configure IOptions in Startup.cs file;

public void ConfigureServices(IServiceCollection services)
        {
            //Add functionality to inject IOptions<T>
            services.AddOptions();
            services.Configure<GlobalConfigurationSettings>(Configuration.GetSection("GlobalConfigurationSettings"));
}

We need a custom class to load configuration settings;

    public class GlobalConfigurationSettings
    {
        public string LowerEnvironment { get; set; }
        public CustomerConfig CustomerConfig { get; set; }
    }

    public class CustomerConfig
    {
        public string CustomerKeyurl { get; set; }
        public string CustomerdetailsUrl { get; set; }
        public Agency Agency { get; set; }
    }

Finally, we will be injecting RequestDelegete and IOptions from the constructor in middleware;

public class MiddlewareWithIOptions
    {
        private readonly RequestDelegate _next;
        private readonly GlobalConfigurationSettings _configurationSettings;

        public MiddlewareWithIOptions(RequestDelegate next, IOptions<GlobalConfigurationSettings> optionsSettings)
        {
            _next = next;
            _configurationSettings = optionsSettings.Value;
        }

And InvokeAsync method;

        public async Task InvokeAsync(HttpContext httpContext)
        {
            try
            {
                var lowerEnvironment = _configurationSettings.LowerEnvironment;
                var customerKeyUrl = _configurationSettings.CustomerConfig.CustomerKeyurl;
                Console.WriteLine($"Middleware using IOptions {lowerEnvironment} - {customerKeyUrl}");
                await _next(httpContext);
            }
            catch (Exception ex)
            {
                throw ex;
                //_logger.LogError($"Something went wrong: {ex.Message}");
            }
        }

Add this line to Startup.cs file;

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{

            app.UseMiddleware<MiddlewareWithIOptions>();
}

If we want to restrict URL segment, we can write InvokeMethods like this;

       public async Task Invoke(HttpContext context)
        {
            if (context.Request.Path.StartsWithSegments("/swagger")
                && !context.User.Identity.IsAuthenticated)
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                return;
            }

            await _next.Invoke(context);
        }

For an example in controllers, refer to this article;

Resources

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0

UDM Pro commands

List of commands to troubleshoot UDM Pro;

The best command for packet related issues is tcpdump

tcpdump <interface> -w <filename.pcap>

Most of the commands are just Linux commands. However some are unique to the UDM/UDM-P.

Cisco/EdgeOS/VyOs Command/Best descriptionUDM/UDM-P SSH Command
show versioninfo
show system hardware and installed softwareubnt-device-info summary
show cpu tempetureubnt-systool cputemp
show fan speedubnt-fan-speed
show uptimeuptime
show ip routenetstat -rt -n
show tech-support (dump a file for tech support)ubnt-make-support-file <file.tar.gz>
show ppp summerypppstats
show current userwhoami
show logcat /var/log/messages
show interface summaryifstat
show interfacesifconfig
show other Ubiquiti devices on local LAN segment (ubnt-discovery)ubnt-tools ubnt-discover
show config (wireless)cat /mnt/data/udapi-config/unifi
show DHCP leases (to NSname)cat /mnt/data/udapi-config/dnsmasq.lease
packet capturetcpdump
shutdownpoweroff
reloadreboot
show ipsec saipsec statusall
factory resetfactory-reset.sh
show system burnt in MAC addressubnt-tools hwaddr
Unifi Server commands (logs files)
show unifi server logscat /mnt/data/unifi-os/unifi/logs/server.log
show unifi server setttingscat /mnt/data/unifi-os/unifi-core/config/settings.yaml
show unifi server http logscat /mnt/data/unifi-os/unifi-core/logs/http.log
show unifi server http logs (errors)cat /mnt/data/unifi-os/unifi-core/logs/errors.log
show unifi server discovery logcat /mnt/data/unifi-os/unifi-core/logs/discovery.log
show unifi system logscat /mnt/data/unifi-os/unifi-core/logs/system.log

Tested with 1.8.3-5

To restart UDM Pro to release memory pressure without restarting, SSH and enter this;

unifi-os restart

To update udm pro software;

Start unifi shell = “unifi-os shell” and then apt update && upgrade

Resource

Click this link to see the reference.

Protected web api configuration

Like web apps, the ASP.NET and ASP.NET Core web APIs are protected because their controller actions are prefixed with the [Authorize] attribute. The controller actions can be called only if the API is called with an authorized identity.

Consider the following questions:

  • Only an app can call a web API. How does the API know the identity of the app that calls it?
  • If the app calls the API on behalf of a user, what’s the user’s identity?

Read more here;

https://docs.microsoft.com/en-us/azure/active-directory/develop/scenario-protected-web-api-app-configuration

How to use AppSettings.json in Azure Web App and Web API?

In App Service, app settings are variables passed as environment variables to the application code.

For ASP.NET and ASP.NET Core developers, setting app settings in App Service are like setting them in <appSettings> in Web.config or appsettings.json, but the values in App Service override the ones in Web.config or appsettings.json. You can keep development settings (for example, local MySQL password) in Web.config or appsettings.json and production secrets (for example, Azure MySQL database password) safely in App Service. The same code uses your development settings when you debug locally, and it uses your production secrets when deployed to Azure.

Let’s say we have this AppSettings file;

{
  "ConnectionStrings": {
    "MyDB": "Data Source=localhost;Initial Catalog=ZooDB;Persist Security Info=True;User ID=monkey;Password=pepepe",
    "MyLog": "Data Source=localhost;Initial Catalog=ZoodDBLog;Persist Security Info=True;User ID=banana;Password=eat"
  },
  "AllowedHosts": "*"

The connection settings on Azure Api App or Web App blade under configuration would be;

First Database

Name
MyDB

Value
Data Source=remotehost.com;Initial Catalog=ZooDB;Persist Security Info=True;User ID=remoteMonkey;Password=xxxee

Type
SQL Server

Second Database

Name
MyLog

Value
Data Source=remotehost.com;Initial Catalog=ZooDBLog;Persist Security Info=True;User ID=remoteMonkey;Password=xxxee

Type
SQL Server

Let’s say we have these hierarchal settings in AppSettings file;

"ApplicationSettings": {
    "CanImpersonate": "true",
    "GenerateJwt": "false",
    "ActiveDirectorySource": {
      "DataSource": "Database",
      "ActiveDirectory": {
        "Username": "variable",
        "Password": "variable",
        "DomainName": "variable",
        "EmailKey": "mail",
        "FirstNameKey": "givenName",
        "LastNameKey": "sn",
        "PhoneKey": "telephoneNumber",
      },
      "Database": {
        "ConnectionString": "Data Source=localhost;Initial Catalog=ZooDB;Persist Security Info=True;User ID=monkey;Password=pepepe",
        "Table": "ad.monkeytable",
      }
    },
"AllowedHosts": "*"

The connection settings on Azure Api App or Web App blade under configuration would be;

Name
ApplicationSettings:ActiveDirectorySource:Database:ConnectionString

Value
Data Source=remotehost;Initial Catalog=ZooDB;Persist Security Info=True;User ID=monkey;Password=pepepe

Type
SQLServer

If there are application settings other than connection string, they would be configured like this;

Name
ApplicationSettings__ActiveDirectorySource__Database__Table

Value
ad.monkeytable

The only difference between single and hierarchal structure is addition of : and __ qualifier’s (Two underscores connected).

When reading in ASP.NET core application, hierarchy can be stepped down with (:). for example;

# get value from appsettings
var logConnectionString = configuration.GetSection("ApplicationSetting:ConnectionStrings:LogDatabase");

#use the value
Console.WrtieLine(logConnectionString.Value);

If for some reasons, above configuration doesn’t work, try to publish to app service using Visual Studio publish feature. Make sure to add connection dependency manually.

Sources

https://techcommunity.microsoft.com/t5/apps-on-azure-blog/asp-net-core-appsettings-for-azure-app-service/ba-p/392596

https://docs.microsoft.com/en-us/azure/app-service/configure-common?tabs=portal

https://docs.microsoft.com/en-us/azure/app-service/configure-language-dotnetcore?pivots=platform-windows#access-environment-variables