Logging .NET WebAPI for debugging, monitoring, and auditing purposes

Lawson Borges
By -
0

Logging .NET WebAPI for debugging, monitoring, and auditing purposes

Logging requests and responses in a .NET WebAPI application can be crucial for debugging, monitoring, and auditing purposes. You can achieve this by implementing middleware in your ASP.NET WebAPI project. Here's a basic outline of how you can log requests and responses:




Create a Logging Middleware: First, you need to create a middleware class to handle logging. This middleware will intercept requests and responses and log them.

Request Middleware

  1. using Microsoft.AspNetCore.Builder;  
  2. using Microsoft.AspNetCore.Http;  
  3. using Microsoft.Extensions.Hosting;  
  4.   
  5. namespace Lib.Common.Middleware  
  6. {  
  7.     public class RequestMiddleware  
  8.     {  
  9.         private readonly RequestDelegate next;  
  10.   
  11.         public RequestMiddleware(RequestDelegate next)  
  12.         {  
  13.             this.next = next;  
  14.         }  
  15.   
  16.         public async Task Invoke(HttpContext context, IMiddlewareRepository _middlewareRepository)  
  17.         {  
  18.             string[] allowedPaths = new string[]  
  19.             {  
  20.                 "/api/home",  
  21.                 "/favicon.ico"
  22.             };  
  23.   
  24.             if (allowedPaths.Contains(context.Request.Path.Value.ToLower()))  
  25.             {  
  26.                 await next(context);  
  27.             }  
  28.             else  
  29.             {  
  30.                 var requestBodyStream = new MemoryStream();  
  31.   
  32.                 string apiURL = context.Request.Host + context.Request.Path;  
  33.                 var originalRequestBody = context.Request.Body;  
  34.   
  35.                 await context.Request.Body.CopyToAsync(requestBodyStream);  
  36.   
  37.                 requestBodyStream.Seek(0, SeekOrigin.Begin);  
  38.   
  39.                 var requestBodyText = new StreamReader(requestBodyStream).ReadToEnd();  
  40.   
  41.                 var id = await _middlewareRepository.PostRequestLog(apiURL, requestBodyText);  
  42.   
  43.                 context.Items["RequestId"] = id;  
  44.   
  45.                 requestBodyStream.Seek(0, SeekOrigin.Begin);  
  46.                 context.Request.Body = requestBodyStream;  
  47.   
  48.                 await next(context);  
  49.   
  50.                 context.Request.Body = originalRequestBody;  
  51.             }  
  52.         }  
  53.     }  
  54.   
  55.     // Extension method used to add the middleware to the HTTP request pipeline.  
  56.     public static class RequestMiddlewareExtension  
  57.     {  
  58.         public static IApplicationBuilder UseLogRequestMiddleware(this IApplicationBuilder builder)  
  59.         {  
  60.             return builder.UseMiddleware<RequestMiddleware>();  
  61.         }  
  62.     }  
  63. }  


Response Middleware

  1. using Lib.Common.Model;  
  2. using Microsoft.AspNetCore.Builder;  
  3. using Microsoft.AspNetCore.Http;  
  4.   
  5. namespace Lib.Common.Middleware  
  6. {  
  7.     public class ResponseMiddleware  
  8.     {  
  9.         private readonly RequestDelegate _next;  
  10.   
  11.         public ResponseMiddleware(RequestDelegate next)  
  12.         {  
  13.             _next = next;  
  14.         }  
  15.   
  16.         public async Task Invoke(HttpContext context, IMiddlewareRepository _middlewareRepository)  
  17.         {  
  18.             string[] allowedPaths = new string[]  
  19.             {  
  20.                 "/api/home",  
  21.                 "/favicon.ico"                
  22.             };  
  23.   
  24.             if (allowedPaths.Contains(context.Request.Path.Value.ToLower()))  
  25.             {  
  26.                 await _next(context);  
  27.             }  
  28.             else  
  29.             {  
  30.                 var bodyStream = context.Response.Body;  
  31.   
  32.                 var responseBodyStream = new MemoryStream();  
  33.                 context.Response.Body = responseBodyStream;  
  34.   
  35.                 await _next(context);  
  36.   
  37.                 responseBodyStream.Seek(0, SeekOrigin.Begin);  
  38.   
  39.                 long requestId = Convert.ToInt64(context.Items["RequestId"]);  
  40.                 string status = context.Response.StatusCode.ToString();  
  41.                 var responseBody = new StreamReader(responseBodyStream).ReadToEnd();  
  42.   
  43.                 await _middlewareRepository.PostResponseLog(responseBody, status, requestId);  
  44.   
  45.                 responseBodyStream.Seek(0, SeekOrigin.Begin);  
  46.   
  47.                 await responseBodyStream.CopyToAsync(bodyStream);  
  48.             }  
  49.         }  
  50.     }  
  51.   
  52.     // Extension method used to add the middleware to the HTTP response pipeline.  
  53.     public static class ResponseMiddlewareExtensions  
  54.     {  
  55.         public static IApplicationBuilder UseLogResponseMiddleware(this IApplicationBuilder builder)  
  56.         {  
  57.             return builder.UseMiddleware<ResponseMiddleware>();  
  58.         }  
  59.     }  
  60. }  


Middleware repository 

  1. using Dapper;  
  2. using Lib.Common.Enum;  
  3. using Lib.Common.Repository.CustomExceptions;  
  4. using Lib.Common.Repository.Dapper;  
  5.   
  6. using Microsoft.Extensions.Configuration;  
  7.   
  8. namespace Lib.Common.Middleware  
  9. {  
  10.     public class MiddlewareRepository : IMiddlewareRepository  
  11.     {  
  12.         private readonly IConfiguration _configuration;  
  13.         private readonly IExceptionLogger _loggerRepository;  
  14.         private static readonly string exceptionSource = "Lib.Common.Middleware.MiddlewareRepository";  
  15.         private readonly IGenericDapperRepository<string> _genericDapperRepository;  
  16.   
  17.         public MiddlewareRepository(IExceptionLogger loggerRepository, IConfiguration configuration,   
  18.             IGenericDapperRepository<string> genericDapperRepository)  
  19.         {  
  20.   
  21.             _loggerRepository = loggerRepository;  
  22.             _configuration = configuration;  
  23.             _genericDapperRepository = genericDapperRepository;  
  24.         }  
  25.   
  26.         public async Task<long> PostRequestLog(string apiURL, string requestBody, string? purpose = null, string? apiType = null)  
  27.         {  
  28.             try  
  29.             {  
  30.                 requestBody = requestBody.Replace("'", @"''");  
  31.                 string? procedure = _configuration["Procedure:InsertAgamApiLog"];  
  32.   
  33.                 var parameters = new DynamicParameters();  
  34.                 parameters.Add("@p_purpose", purpose);  
  35.                 parameters.Add("@p_apiType", apiType);  
  36.                 parameters.Add("@p_apiURL", apiURL);  
  37.                 parameters.Add("@p_bodyText", requestBody);  
  38.   
  39.                 string? result = await _genericDapperRepository.GetByParamsFirstOrDefaultAsync(procedure, parameters);  
  40.   
  41.                 return Convert.ToInt64(result);  
  42.             }  
  43.             catch (Exception ex)  
  44.             {  
  45.                 _ = _loggerRepository.LogDetails(ExceptionLoggerType.DB, ex, $"{exceptionSource} => PostRequestLog()");  
  46.                 throw;  
  47.             }  
  48.         }  
  49.   
  50.         public async Task PostResponseLog(string responseBody, string status, long requestId)  
  51.         {  
  52.             try  
  53.             {  
  54.                 responseBody = responseBody.Replace("'", @"''");  
  55.                 string? procedure = _configuration["Procedure:InsertAgamApiLog"];  
  56.                 procedure += $"(p_bodytext := '{responseBody}', p_requestid := {requestId}, p_status := '{status}');";  
  57.   
  58.                 await _genericDapperRepository.GetByParamsFirstOrDefaultAsync(procedure);  
  59.             }  
  60.             catch (Exception ex)  
  61.             {  
  62.                 _ = _loggerRepository.LogDetails(ExceptionLoggerType.DB, ex, $"{exceptionSource} => PostResponseLog()");  
  63.                 throw;  
  64.             }  
  65.         }  
  66.     }  
  67. }  

Register Middleware: Register the middleware in your program.cs file in the Configure method:

  1. using Lib.Common.CustomProvider;  
  2. using Lib.Common.Filters;  
  3. using Lib.Common.Middleware;  
  4. using Lib.Common.Model;  
  5. using WebApi.Customer.Extensions;  
  6.   
  7. var builder = WebApplication.CreateBuilder(args);  
  8.   
  9. // Add services to the container.  
  10. var configuration = builder.Configuration;  
  11.   
  12. AppSettings appSettings = new AppSettings();  
  13.   
  14. var ConfigurationBuilder = new ConfigurationBuilder()  
  15.                        //.AddJsonFile("appsettings.json" )  
  16.                        .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json")  
  17.                        .AddEncryptedProvider(configuration, appSettings)  
  18.                        .AddEnvironmentVariables();  
  19.   
  20. builder.Services.AddSingleton(appSettings);  
  21.   
  22. builder.Services.Configure<ClientAssembly>(builder.Configuration.GetSection("ClientAssembly"));  
  23.   
  24. // Added all dependency in Custom Configuration services  
  25. builder.Services.AddCustomConfigureService();  
  26.   
  27. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle  
  28. builder.Services.AddEndpointsApiExplorer();  
  29. builder.Services.AddSwaggerGen();  
  30.   
  31. builder.Services.AddControllers(options =>  
  32. {  
  33.     options.Filters.Add(typeof(ExceptionalHandler));  
  34. });  
  35.   
  36. builder.Services.AddCors(p => p.AddPolicy("corsapp", builder =>  
  37. {  
  38.     builder.WithOrigins("*").AllowAnyMethod().AllowAnyHeader();  
  39. }));  
  40.   
  41. var listenAnyIPPortNo =Convert.ToInt32( Environment.GetEnvironmentVariable("IPPortNumber"));   
  42. builder.WebHost.ConfigureKestrel(serverOptions =>  
  43. {  
  44.     //serverOptions.ListenAnyIP(8114);  
  45.     serverOptions.ListenAnyIP(listenAnyIPPortNo);  
  46.     serverOptions.ListenLocalhost(5001);  
  47. });  
  48. ConfigurationBuilder.Build();  
  49.   
  50. var app = builder.Build();  
  51.   
  52. // Configure the HTTP request pipeline.  
  53. //if (app.Environment.IsDevelopment())  
  54. //{  
  55.     app.UseSwagger();  
  56.     app.UseSwaggerUI();  
  57. //}  
  58.   
  59. //Add new middleware to the pipeline  
  60. app.UseMiddleware<RequestMiddleware>();  
  61. app.UseMiddleware<ResponseMiddleware>();  
  62.   
  63. app.MapControllers();  
  64. app.Run();  
Tags:

Post a Comment

0Comments

Post a Comment (0)