top of page
Writer's pictureThe Tech Platform

Use multiple implementations of an interface with ASP.NET Core DI



In this article, we will be using the same example by extending it to use multiple implementation of logger service by resolving it based on a config setting to log my exception.


First we will create ILoggerService and different implementation of it by creating a Services folder in the project.

namespace CoreWebAPIDemo.Services
{
    public enum LogType
    {
        Trace,
        Debug,
        Information,
        Warning,
        Error
    }
    public interface ILoggerService
    {
        public void Log(LogType logType, object logInfo);
    }
    public class NullLoggerService : ILoggerService
    {
        public void Log(LogType logType, object logInfo)
        {
            //Do Nothing
        }
    }
    public class SerilogFileLoggerService : ILoggerService
    {
        public void Log(LogType logType, object logInfo)
        {
            //your logging code
        }
    }
    public class DbLoggerService : ILoggerService
    {
        public void Log(LogType logType, object logInfo)
        {
            //your logging code
        }
    }
}

Next, Iā€™ll add a delegate to hold a reference of a function which accept the one string argument ā€˜logger typeā€™ and return the ILoggerService instance. For this create a cs file ā€œLoggerServiceResolver.csā€ and add below code.

namespace CoreWebAPIDemo.Services
{
    public delegate ILoggerService LoggerServiceResolver(string loggerType);
}

Now in Startup.ConfigureServices method, add the different logger services and also add LoggerServiceResolver with an implementation to find the right requested service.

services.AddScoped<SerilogFileLoggerService>();
services.AddScoped<DbLoggerService>();
services.AddScoped<NullLoggerService>();
services.AddTransient<LoggerServiceResolver>(serviceProvider => loggerType =>
{
    switch (loggerType)               
    {                   
        case "SerilogFileLogger":                        
            return 
            serviceProvider.GetService<SerilogFileLoggerService>();                   
        case "DbLogger":                      
            return serviceProvider.GetService<DbLoggerService>();                    
        default:                        
            return serviceProvider.GetService<NullLoggerService>();                
        }           
});


I want to set the logger type option configurable through appsettings.json file so will add a setting there as:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "UserLogger": "SerilogFileLogger",
  "AllowedHosts": "*"
}

By this implementation is ready. Now we need to add the code to consume this and for that Iā€™ll enhance my ā€œExceptionHandlingMiddlewareā€ which I use in my previous article. Please read it here: Middleware and Filters power in ASP.NET Core

using CoreWebAPIDemo.Services;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using System;
using System.Net;
using System.Threading.Tasks;
namespace CoreWebAPIDemo.Middleware
{
    public class ExceptionHandlingMiddleware
    {
        private readonly LoggerServiceResolver _serviceResolver;
        private readonly IConfiguration _configuration;
        private readonly RequestDelegate _requestDelegate;
        public ExceptionHandlingMiddleware
        (
            RequestDelegate requestDelegate, 
            IConfiguration configuraiton, 
            LoggerServiceResolver serviceResolver)
        {
            _requestDelegate = requestDelegate;
            _serviceResolver = serviceResolver;
            _configuration = configuraiton;
        }
        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _requestDelegate(context);
            }
            catch (Exception ex)
            {
                await HandleException(context, ex);
            }
        }
        private Task HandleException(HttpContext context, Exception ex)
        {
            var logType = _configuration.GetValue<string>("UserLogger");
            var myLogger = _serviceResolver(logType);
            myLogger.Log(LogType.Error, ex);
            context.Response.ContentType = "application/json";
            context.Response.StatusCode = (int)HttpStatusCode. 
                                          InternalServerError;
        return context.Response.WriteAsync(ex.Message);
        }
    }
}

In above code, Code in Bold is the new code added and needed for this example. Now we all set to use the different implementations of ILoggerService with ASP.NET Core DI with my middleware. Similarly we can implement the same with ā€œExceptionHandlerFilterā€ class and changes would be (highlighted in Bold):

using CoreWebAPIDemo.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Configuration;
using System;
using System.Net;
namespace CoreWebAPIDemo.Middleware
{
    public class ExceptionHandlerFilter : Attribute, IActionFilter
    {
        private readonly LoggerServiceResolver _serviceResolver;
        private readonly IConfiguration _configuration;
        public ExceptionHandlerFilter(
            IConfiguration configuraiton, 
            LoggerServiceResolver serviceResolver)
        {
            _serviceResolver = serviceResolver;
            _configuration = configuraiton;
        }
    public void OnActionExecuting(ActionExecutingContext context) 
    { 
    }
    public void OnActionExecuted(ActionExecutedContext context)
        {
            var logType = _configuration.GetValue<string>("UserLogger");
            var myLogger = _serviceResolver(logType);

            if (context.Exception is Exception exception)
            {
                myLogger.Log(LogType.Error, exception);
                context.Result = new ObjectResult(exception.Message)
                {
                    StatusCode = (int)HttpStatusCode.InternalServerError,
                };
                context.ExceptionHandled = true;
            }
        }
    }
    public class HttpResponseException : Exception
    {
        public int Status { get; set; } = 500;
        public object Value { get; set; }
    }
}



Source: Medium - Binod Mahto


The Tech Platform

0 comments

Comments


bottom of page