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

Excel dropdown list with number and text

There are two methods;

Data validation drop down

There is a list option in Data validation. If this is combined with a VLOOKUP formula you would be able to convert the selected value into a number.

The steps in Excel 2010/2019 are:

  • Create your list with matching values.
  • On the Data tab choose Data Validation
  • The Data validation form will be displayed
  • Set the Allow dropdown to List
  • Set the Source range to the first part of your list
  • Click on OK (User messages can be added if required)

In a cell enter a formula like this

=VLOOKUP(A5,$E$5:$F$8,2,FALSE)

which will return the matching value from the second part of your list.

Form control drop down

Alternatively, Form controls can be placed on a worksheet. They can be linked to a range and return the position number of the selected value to a specific cell.

If you don’t see Developer tab in Excel ribbon, follow this link;

Show the Developer Tab

The steps in Excel 2010/2019 are:

  • Create your list of data in a worksheet
  • Click on the Developer tab and dropdown on the Insert option
  • In the Form section choose Combo box or List box
  • Use the mouse to draw the box on the worksheet
  • Right click on the box and select Format control
  • The Format control form will be displayed
  • Click on the Control tab
  • Set the Input range to your list of data
  • Set the Cell link range to the cell where you want the number of the selected item to appear
  • Click on OK

All about LINQ operators

A short list of LINQ operators.

Using IN clause

This is similar to database IN keyword;

var myInClause = new string[] {"One", "Two", "Three"};

var results = from x in MyTable
              where myInClause.Contains(x.SomeColumn)
              select x;
// OR
var results = MyTable.Where(x => myInClause.Contains(x.SomeColumn));

Using ALL operator

Working with simple types

//does all numbers are greater than 10
int[] IntArray = { 11, 22, 33, 44, 55 };
var Result = IntArray.All(x => x > 10);
Console.WriteLine("Is All Numbers are greater than 10 : " + Result);

//does all names has characters greater than three
string[] stringArray = { "Khan", "Ali", "Adam", "Eve", "Joe" };
Result = stringArray.All(name => name.Length > 3);
Console.WriteLine("Is All Names are greater than 3 Characters : " + Result);

var letterResult = stringArray.All(name => name.StartsWith("A"));
Console.WriteLine("Is All Names start with letter A : " + letterResult);

//all numbers can be divided by three
int[] numbers = { 3, 6, 9, 12};
bool iSNumbersDivided = numbers.All(number => number % 3 == 0);
Console.WriteLine($"Numbers are divisible by three = {iSNumbersDivided}");

Working with complex types

//Check whether age of all animals in the zoo is greater than 1 year
bool response = animalData.All(x => x.AnimalAge > 1);
Console.WriteLine($"Is All Animals are greater than 1 years old : {response}");

//get all animas who are feed by milk
var zooSubSet = animalData.Where(x => x.Food.All(y => y.FoodType == "Milk"));
foreach(var item in zooSubSet)
{
    Console.WriteLine($"Animal Name: {item.AnimalName}");
}

Resources

https://stackoverflow.com/questions/959752/where-in-clause-in-linq

https://coderedirect.com/questions/644629/linq-nested-list-contains