December 28, 2023

Ahead of Time Compilation (AOT) in .NET 8

Ahead of Time Compilation (AOT) is a technology that has been gaining momentum in the world of software development, and .NET 8 brings exciting advancements in this area. AOT offers significant advantages in terms of performance and security, making it an essential feature for modern .NET applications. Let's explore AOT in .NET 8 and its benefits.

What is Ahead of Time Compilation (AOT)?

AOT is a compilation technique that converts high-level code, such as C# or F#, into native machine code before the application is run. Unlike Just-In-Time (JIT) compilation, which compiles code at runtime, AOT compiles code ahead of time, resulting in several advantages: 

Performance Boost: AOT-compiled code runs faster since it doesn't require runtime compilation. This leads to reduced startup times and improved overall application performance.

Predictable Behavior: AOT eliminates the JIT warm-up time, ensuring consistent and predictable application behavior across different executions.

Improved Security: AOT reduces the attack surface by removing the need for a JIT compiler at runtime, making it harder for attackers to exploit vulnerabilities.

.NET 8 introduces enhanced AOT support, making it easier than ever to leverage this technology in your applications. Here are some key improvements:

Single-File AOT: .NET 8 allows you to create single-file AOT-compiled applications, simplifying deployment and distribution.

Cross-Platform AOT: AOT is no longer limited to Windows. .NET 8 brings cross-platform AOT support, enabling AOT-compiled apps to run on various operating systems.

Improved Interoperability: .NET 8 enhances the interoperability between AOT-compiled code and JIT-compiled code, ensuring smooth integration of AOT into existing projects.

In .NET 8, AOT makes your software faster, safer, and works on different devices. I Love it since it makes the Minimal Apis even faster. 

December 17, 2023

How to add Api key validation in Swagger

Just a quick post on how to add api key validation in swagger docs. Pretty easy and here is the code to add in AddSwaggerGen in the program.cs file. You can define your own Api key validation middleware.


    builder.Services.AddSwaggerGen(c =>
    {
    c.AddSecurityDefinition("api_key", new OpenApiSecurityScheme
    {
    Type = SecuritySchemeType.ApiKey,
    Name = "Authorization",
    In = ParameterLocation.Header,
    Description = "API key needed to access the endpoints."
    });

    // Define your security requirement (optional)
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
     {
    new OpenApiSecurityScheme
     {
     Reference = new OpenApiReference
    {
     Type = ReferenceType.SecurityScheme,
     Id = "api_key"
     }
    },
     new string[] { }
    }
    });
    });

December 6, 2023

Title: Announcing My New Book: Crafting Minimal APIs with a Functional Twist!

 

I am thrilled to share with all of you a journey I've passionately embarked on – writing a book dedicated to the world of Minimal APIs with a functional approach. This book is not just a guide; it's a deep dive into the efficient and innovative world of Minimal APIs, explored through the lens of functional programming. I've poured my experience and insights into this work, aiming to offer a fresh perspective on building lean, effective APIs. Whether you're a seasoned developer or just starting out, this book promises to enrich your understanding and skills in creating powerful, minimalistic APIs with a functional twist. Stay tuned for more updates and snippets from my book!


Coming Soon!

November 15, 2023

Azure Service Bus Queue RetryOptions

It's crucial to effectively handle transient errors during message processing. Many developers often attempt to create their own solutions for this issue, but there is already an elegant, built-in solution in the Azure Service Bus client. The key is to create a RetryOption and pass it to the Service Bus client during its creation. This straightforward approach leverages the native capabilities of Azure Service Bus to manage transient errors efficiently.


builder.AddServiceBusClient(settings.ConnectionStrings.AzureWebJobsServiceBus).ConfigureOptions(options =>
{
options.RetryOptions = new ServiceBusRetryOptions()
{
Delay = TimeSpan.FromSeconds(30),
MaxDelay = TimeSpan.FromSeconds(30),
Mode = ServiceBusRetryMode.Exponential,
MaxRetries = 3
};
});

 

November 3, 2023

Structured logging .Net

Structured logging is an approach to logging that captures data in a way that's easy to parse and analyze, unlike traditional logging, which often involves plain text messages. In structured logging, log entries are composed of discrete fields, such as time stamps, log levels, messages, and other contextual information.

Here is an example:


_logger.LogInformation("Request received {@Request}", request);

Why it is important? Well there are few main reasons. 

Searchability and Filtering: Structured logs allow for easier searching and filtering since each part of the log message is a distinct field. This makes it straightforward to find all logs related to a specific event, error code, or user action. As you can see in the following example, logs are written in a json format where you can easily search. 


Performance: When you use structured logging with deferred execution, such as with Serilog or NLog, the actual string interpolation doesn't happen unless the log level is enabled. This means you avoid unnecessary string manipulation if, for example, your debug logs are turned off in a production environment.

Why you shouldn't use logging with string interpolation?

Utilizing string interpolation in logging compromises the capability to efficiently search or filter through log entries. Additionally, it necessitates memory allocation for each log entry created, due to the fact that, unlike structured logging, the template is not established at compile-time, resulting in potentially higher overhead and less optimal performance.


_logger.LogInformation($"Request received {JsonSerializer.Serialize(request)}");

In conclusion, it is imperative to exercise discretion when implementing structured logging, particularly to mitigate the risks of inadvertently logging sensitive information or excessively large objects. Developers have the capacity to introduce entire objects into the log data, which could lead to breaches of privacy, security concerns, and potential performance issues due to the increased size and complexity of the log data. Therefore, it is essential to establish and adhere to best practices regarding what data should be logged, ensuring that the logs remain informative and valuable without compromising security or performance.

October 18, 2023

.NET 8 Dependency Injection Keyed Services

In .NET 8, Inversion of Control (IOC) has been enhanced to support keyed services, enabling more nuanced dependency injection in application architectures. 

With keyed services, developers can associate specific keys with particular service implementations, granting more fine-grained control over service retrieval from the IOC container. This means that when a consumer requests a service, it can specify a key to receive a particular implementation of the service interface. 

This flexibility is crucial for scenarios where multiple implementations of an interface exist, and the decision to use one over another is determined at runtime. Keyed services in .NET 8’s IOC container therefore facilitate a more dynamic, adaptable, and modular application architecture. 

Here is a simple example of the Keyed services

Multiple implementation for the same interface 


public interface IGreetingService
{
string GetGreeting();
}

public class EnglishGreetingService : IGreetingService
{
public string GetGreeting() => "Hello!";
}

public class SpanishGreetingService : IGreetingService
{
public string GetGreeting() => "¡Hola!";
}

Register the implementation with a key

builder.Services.AddKeyedSingleton<IGreetingService, EnglishGreetingService>("English");
builder.Services.AddKeyedSingleton<IGreetingService, SpanishGreetingService>("Spanish");

Use the key to inject to the required functions


app.MapGet("/greet",
([FromKeyedServices("English")]IGreetingService english,
[FromKeyedServices("Spanish")]IGreetingService spanish) =>
$"English:{english.GetGreeting()} Spanish: {spanish.GetGreeting()}")
.WithName("GreetingEndpoint");

Hope this helps!

June 15, 2023

Request Throttling in Minimal Api

Throttling in Minimal API refers to the practice of limiting the number of requests a client can make within a certain time period. It helps prevent abuse and ensures fair usage of API resources. By implementing throttling mechanisms, developers can control the rate at which clients can access their APIs, improving performance and protecting against potential overloading or denial of service attacks.

Typically these requests are handled via Api Gateway policies. However, .Net provides build in middleware to handle this effectively.


    builder.Services.AddRateLimiter(r => r
    .AddFixedWindowLimiter(policyName: "fixed", options =>
    {
    options.PermitLimit = 4;
    options.Window = TimeSpan.FromSeconds(12);
    }));

    var app = builder.Build();
    app.UseRateLimiter();

    app.MapGet("/", () => Results.Ok($"Hello World"))
    .RequireRateLimiting("fixed");


May 26, 2023

Mediatr Pipelines

MediatR is a popular open-source library in C# that provides a simple and elegant way to implement the Mediator pattern and build pipelines in your application. The library helps decouple components by promoting loose coupling and encapsulation of requests and handlers.

With MediatR, you define requests as plain C# classes representing a unit of work or a command, and you create handlers to process these requests. The library then handles the routing and execution of the requests to their corresponding handlers.

One of the key features of MediatR is its support for pipelines. A pipeline in MediatR is a sequence of behavior or middleware that can be applied before and after the execution of request handlers. Each behavior in the pipeline can intercept and modify the request, perform additional processing, or handle cross-cutting concerns such as validation, logging, caching, or authorization.

Following code example shows a simple Logging and Exception handling pipeline for Medatr requests. 

public class AddUserCommand : IRequest<Unit>
{
public string Username { get; set; }
public string Email { get; set; }
}

public class AddUserCommandHandler : IRequestHandler<AddUserCommand, Unit>
{
private readonly IUserService _userService;

public AddUserCommandHandler(IUserService userService)
{
_userService = userService;
}

public Task<Unit> Handle(AddUserCommand request, CancellationToken cancellationToken)
{
_userService.AddUser(request.Username, request.Email);
return Task.FromResult(Unit.Value);
}
}


//Simple logging behavior
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;

public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}

public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
_logger.LogInformation($"Handling {typeof(TRequest).Name}");

var response = await next();

_logger.LogInformation($"Finished handling {typeof(TRequest).Name}");

return response;
}
}


//Simple Exception handling behavior
public class ExceptionHandlingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger<ExceptionHandlingBehavior<TRequest, TResponse>> _logger;

public ExceptionHandlingBehavior(ILogger<ExceptionHandlingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}

public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
try
{
return await next();
}
catch (Exception ex)
{
_logger.LogError(ex, $"Exception occurred while handling {typeof(TRequest).Name}");
throw;
}
}
}


Next step is to configure the pipeline in startup class.

//Configure the MediatR pipeline in StartUp Class
var services = new ServiceCollection();
services.AddMediatR(typeof(Startup));

// Register any other dependencies your handlers might require
services.AddTransient<IUserService, UserService>();

// Configure pipeline behaviors
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ExceptionHandlingBehavior<,>));

By utilizing MediatR's pipeline capabilities, you can easily insert and compose multiple behaviors in a flexible manner, providing a powerful way to modify and extend the behavior of your application's requests without tightly coupling them to specific implementations.

The pipeline in MediatR is typically implemented using a combination of decorators and the Decorator Pattern. Decorators wrap and modify the behavior of the underlying handler, allowing you to add or modify functionality at various points in the pipeline.

In summary, MediatR is a versatile library that simplifies the implementation of the Mediator pattern and facilitates the creation of pipelines in C# applications. It promotes decoupling, modularity, and extensibility, making it easier to handle requests, apply behaviors, and build scalable and maintainable applications.

https://github.com/jbogard/MediatR 

May 12, 2023

Simplified Messaging using MassTransit

MassTransit is an open-source message bus framework for .NET that makes it easier to build distributed applications by providing a way to communicate between different components or services within a system. https://masstransit.io/

In simple terms, MassTransit allows different parts of a system to send and receive messages, regardless of where they are located or how they are implemented. It provides a way to abstract away the details of communication protocols and message serialization, allowing developers to focus on the business logic of their applications. 

I've used MassTransit many years ago and wanted to highlight the usage of it and the simplicty it provide to integrate with different message brokers. 



I have written a .Net 7 mininal api sample in MassTransit. Have a look at it and see how simple it is to integrate. This will eliminate tons of plumbing code to get the messaging working.