Category Archives: Programming

Validating configuration on startup in ASP.Net core 2.2

The ability to validate configurations in Startup.cs was pushed from .NET Core 2.2 to 3.0. In the mean time I still needed to validate our configurations when they were loaded to ensure all transforms performed correctly and no configuration fields were missing. I found a few solutions online for this, but they involved middleware like Andrew Lock’s solution or using the services.Configure pattern like Vidar Kongsli’s solution. I needed something simpler and easier for developers to implement.

Configuring services in Startup.cs looked like

var cognitoConfiguration = configuration.GetSection("Aws-Cognito").Get<AwsCognitoConfiguration>();
           services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
   .AddJwtBearer(options =>
   {
      options.Audience = cognitoConfiguration.UserPoolClientId;
      options.Authority = cognitoConfiguration.AuthorityUrl.ToString();
   });

But issues can arise with this approach, for instance if UserPoolClientId isn’t populated, or if the entire 'Aws-Cognito' section was missing from the appsettings.json. A simple approach is to create an extension method for the IConfiguration class:

public static class ConfigurationExtensionMethods
{
     public static T GetSectionAndValidate<T>(this IConfiguration configuration, string sectionName)
         where T : DriveConfiguration
     {
         var results = configuration.GetSection(sectionName).Get<T>();

         results.CheckConfigurationValid();

         return results;
     }
 }

Modify all of the configuration POCO’s to use an abstract class for the validation:

public abstract class DriveConfiguration
{
    public void CheckConfigurationValid()
    {
        var results = new List<ValidationResult>();

        var isValid = Validator.TryValidateObject(
            this,
            new ValidationContext(this),
            results,
            true);

        if (!isValid)
        {
            var errorMessage = $"Missing configuration for {this.GetType().Name}: ";

            errorMessage += string
                .Join(", ", results
                    .Select(x => x.ErrorMessage));

            throw new ArgumentException(errorMessage);
        }
    }
}

A configuration POCO then uses theSystem.ComponentModel.DataAnnotations namespace to add validation attributes like [Required] or [EmailAddress]:

public class AwsCognitoConfiguration : DriveConfiguration
{
   [Required]
   public string UserPoolClientId { get; set; }

   [Required]
   public Uri AuthorityUrl { get; set; }
}

in Startup.cs getting the configuration changes to look like:

var cognitoConfiguration = _configuration.GetSectionAndValidate<AwsCognitoConfiguration>("Aws-Cognito");

When the GetSectionAndValidate<T>() executes, it populates the configuration POCO from appsettings.json and then fires off the validation. Aside from using the extension method, nothing else needs to be done in order for all configurations in Startup.cs to be validated automatically! Exceptions look like

System.ArgumentException: 'Missing configuration for CognitoConfiguration: The UserPoolClientId is required'

As you can see, it’s very easy to see what value is missing from what part of appsettings.json. This validation can be used for a health check, or even cause launch failures that an ECS cluster can respond to.

.Net Core 2.2 comes with a good base set of validators, but writing your own validator attributes is as easy as implementing ValidationAttribute:

[AttributeUsage(AttributeTargets.All, AllowMultiple = false)]
public class AwsAccessKeyValidatorAttribute : ValidationAttribute
{
    public AwsAccessKeyValidatorAttribute()
        : base("The {0} field must be a valid AWS Access Key")
    {
    }

    public override bool IsValid(object value)
    {
        return value is string && value.ToString().Trim().Length == 20;
    }
}

DataTables Search box blocking backspace key?

Working with DataTables for the first time I was having some issues with the UI. The search textbox was not allowing the user the backspace. They were able to select the text and use the delete key to clear it out, but it almost felt like there was a script capturing and suppressing the backspace key press. Upon closer inspection the “type” of the input was “Search”. According to w3schools (and Visual Studio’s Intellisense) this was valid HTML. The example of their site worked as well. Perhaps it had something to do with the other scripts running on the page, or possibly the Bootstrap library addon for DataTables? Changing the type to “Text” fixed the issue. I found an easy workaround here until I can fix the root of the problem.