Source code
.NET Core C# Visual Studio

Using Extension Methods in a .NET Core Application

Welcome to today’s post.

In today’s post I will be discussing extension methods and how they can be used in a .NET Core Application.

In the application pipeline IAppBuilder, we can use a number of middleware extensions, including those for authentication, authorization, http requests. For example, to enable authentication we call the following extension method:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
	...
    app.UseAuthentication();
	...
}

Custom extension methods allow you to create additional methods to types without having to create methods within new derived types.

For example, we want to create a method to compute the number of alphanumeric characters within a string, AlphanumericCount(). We can create this as a method within a new class, which we would have to build and use separately from our String type.

Extension types that allow query methods for enumerable types are provided by the System.Linq library.

Creating extension methods

Each extension method follows the rules:

  1. The method must be under a namespace.
  2. The method must be under a public static class.
  3. The method must be public visibility of static type.
  4. The method must contain a parameter with the type being extended and preceded by this modifier.

For example, our new string extension method would be implemented as shown:

using System.Linq;
using System.Text;
using System;

namespace StringExtensionMethods
{
    public static class StringExtensions
    {
        public static int AlphanumericCount(this String strval)
        {
            return strval.Count(char.IsLetterOrDigit);
        }
    }
}

To use the above extension method, declare the namespace, StringExtensionMethods then declare a variable of the type that is extended and use the extension method:

using StringExtensionMethods;
string myString = “I am over 21 years of age.”;
int intVal = myString.AlphanumericCount();

Note: Extension methods cannot access private or protected members of the extended class. Also, extension methods cannot override methods within the extending class.

Extending Error Handlers within a .NET Core Web API

In a .NET Core API service application, the use of extension methods is quite abundant within the application builder pipeline. In particular, the use of the UseExceptionHandler() extension method middleware for handling errors is one of the more useful middleware extensions we can utilise to delegate our application errors, filter the error, then output the error response is a more user-friendly way to the caller.

To be able to implement an error handler extension method, we use the above extension method guidelines. A general exception handler is used in the production environment where we wish to sanitise the error instead of displaying the full error and stack trace, which might contain sensitive details.

Below is an example general extension handler (as a lambda function) we use within the Configure() method of the startup.cs file:

if (env.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseExceptionHandler(errorApp =>
    {
        errorApp.Run(async context =>
        {
            context.Response.StatusCode = 500;
            context.Response.ContentType = "application/json";

            var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
            if (contextFeature != null)
            {
                await context.Response.WriteAsync(
  	                new ErrorDetail()
                    {
                        StatusCode = context.Response.StatusCode,
                        Message = "Internal Server Error."
                    }.JsonConvert.SerializeObject(this)	
            }
        });
    });
    app.UseHsts();
}

The above error handler looks quite cumbersome, so we can move the error handler into a it’s own custom extension method, which is the error handler. 

We implement a custom.NET Core middleware extension class as follows:

using GeneralErrorHandling.Models;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Net;

namespace GeneralErrorHandler.Extensions
{
    public static class ExceptionMiddlewareExtensions
    {
        public static void ConfigureExceptionHandler(this IApplicationBuilder app)
        {
            app.UseExceptionHandler(appError =>
            {
                appError.Run(async context =>
                {
                    context.Response.StatusCode = 500;
                    context.Response.ContentType = "application/json";

                    var contextFeature = context.Features.Get<IExceptionHandlerFeature>();
                    if (contextFeature != null)
                    { 
	                    var errorDetails = new ErrorDetails()
                        {
                            StatusCode = context.Response.StatusCode,
                            Message = "Internal Server Error."
                        };
                        await context.Response.WriteAsync(
                            JsonConvert.SerializeObject(errorDetails)
                        );
                    }
                });
            });
        }
    }
}

We also include a model to encapsulate the status code and error message:

namespace GeneralErrorHandler.Models
{
    public class ErrorDetail
    {
        public int StatusCode { get; set; }
        public string Message { get; set; }

    }
}

To use the middleware extension method from the startup.cs we do this as shown:

using GeneralErrorHandler.Extensions;

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) 
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    app.ConfigureExceptionHandler();
    ...
}

I have omitted logging in the above example. In a future post I will be discussing using the general exception handling with logging.

That’s all for today’s post.

I hope you found this post useful and informative.

Social media & sharing icons powered by UltimatelySocial