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 &amp;&amp; value.ToString().Trim().Length == 20;
    }
}

Fixing Sony A6000/A6300/A6500 Buttons Not Responding

My A6300 stopped responding to any button press besides the shutter button one day. I couldn’t figure out what was wrong with it. After some reading online it appeared like the shutter button was getting stuck in the “half pressed” position, usually where focusing happens or exposure lock occurs. The stuck button was making the camera not respond to button presses. Of course, my camera was 1 month out of warranty.

My temporary workaround was pushing the shutter button repeatedly to get the button unstuck, but eventually even that stopped working.

I decided to take a most drastic measure. I grabbed a can of DeOxit and sprayed a very short burst of fluid between the ring that controls the power and the shutter button. I mashed the button a dozen times to get the cleaner into the button then wiped everything off.

All the sudden the buttons started working correctly!

To Infinity, Recursively!