zhaopinboai.com

Efficiently Automate Minimal API Registration in ASP.NET Core

Written on

Chapter 1: Understanding Minimal API Registration

In ASP.NET Core applications that utilize Minimal APIs, the process of registering each endpoint through methods like app.MapGet, app.MapPost, etc., can lead to repetitive coding practices. As your project expands, this manual registration can become increasingly tedious and difficult to manage.

To address this, you can group your Minimal API endpoints using extension methods, which helps declutter the Program file. This method is effective for scaling projects, yet it can feel reminiscent of traditional controller patterns.

I prefer to conceptualize each Minimal API endpoint as an independent component, aligning with the idea of vertical slices. In this guide, I will demonstrate how to streamline your Minimal API registration through a straightforward abstraction.

Section 1.1: The Importance of Automatic Registration

Automatically registering Minimal APIs reduces boilerplate code, simplifies development, and enhances maintainability by creating a central registration system.

To start, we need to define a basic IEndpoint interface that will represent individual endpoints:

public interface IEndpoint

{

void MapEndpoint(IEndpointRouteBuilder app);

}

Each implementation of IEndpoint should encompass only one Minimal API definition. While you could technically register multiple endpoints within the MapEndpoint method, it is advisable to avoid doing so. Implementing a code analyzer or architectural test can help enforce this guideline.

Subsection 1.1.1: Example Endpoint Implementation

Consider the following implementation of the GetFollowerStats endpoint:

public class GetFollowerStats : IEndpoint

{

public void MapEndpoint(IEndpointRouteBuilder app)

{

app.MapGet("users/{userId}/followers/stats", async (

Guid userId,

ISender sender) =>

{

var query = new GetFollowerStatsQuery(userId);

Result result = await sender.Send(query);

return result.Match(Results.Ok, CustomResults.Problem);

})

.WithTags(Tags.Users);

}

}

Section 1.2: Utilizing Reflection for Dynamic Registration

Reflection enables dynamic inspection of code during runtime. For the purpose of registering Minimal APIs, we can leverage reflection to scan .NET assemblies for classes that implement IEndpoint. These will then be configured as services using dependency injection.

The Assembly parameter should be the assembly that contains the IEndpoint implementations. If you wish to include endpoints from multiple assemblies, the method can be easily adapted to accept a collection.

public static IServiceCollection AddEndpoints(

this IServiceCollection services,

Assembly assembly)

{

ServiceDescriptor[] serviceDescriptors = assembly

.DefinedTypes

.Where(type => type is { IsAbstract: false, IsInterface: false } &&

type.IsAssignableTo(typeof(IEndpoint)))

.Select(type => ServiceDescriptor.Transient(typeof(IEndpoint), type))

.ToArray();

services.TryAddEnumerable(serviceDescriptors);

return services;

}

You only need to invoke this method once within the Program file:

builder.Services.AddEndpoints(typeof(Program).Assembly);

Chapter 2: Automatically Registering Minimal APIs

The final step in our implementation is to create an extension method on the WebApplication to automatically register the endpoints. This method will retrieve all IEndpoint service registrations and register them with the application using MapEndpoint.

public static IApplicationBuilder MapEndpoints(

this WebApplication app,

RouteGroupBuilder? routeGroupBuilder = null)

{

IEnumerable<IEndpoint> endpoints = app.Services

.GetRequiredService<IEnumerable<IEndpoint>>();

IEndpointRouteBuilder builder =

routeGroupBuilder is null ? app : routeGroupBuilder;

foreach (IEndpoint endpoint in endpoints)

{

endpoint.MapEndpoint(builder);

}

return app;

}

Putting It All Together

Here’s how your Program file could look once everything is assembled:

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);

builder.Services.AddEndpointsApiExplorer();

builder.Services.AddSwaggerGen();

builder.Services.AddEndpoints(typeof(Program).Assembly);

WebApplication app = builder.Build();

ApiVersionSet apiVersionSet = app.NewApiVersionSet()

.HasApiVersion(new ApiVersion(1))

.ReportApiVersions()

.Build();

RouteGroupBuilder versionedGroup = app

.MapGroup("api/v{version:apiVersion}")

.WithApiVersionSet(apiVersionSet);

app.MapEndpoints(versionedGroup);

app.Run();

Takeaway

Automating Minimal API registration through techniques like reflection can greatly enhance developer productivity and project maintainability. However, it’s crucial to consider the potential performance implications of reflection during application startup.

As a point of improvement, you might explore using source generators for pre-compiled registration logic. Other alternatives worth considering include extension methods, FastEndpoints, and Carter.

I hope you found this information valuable. See you next week!

P.S. If you're interested in further learning opportunities, consider my Pragmatic Clean Architecture course, which teaches best practices in software architecture. Alternatively, join my Patreon community for exclusive content and discounts.

Share the page:

Twitter Facebook Reddit LinkIn

-----------------------

Recent Post:

Unlocking Income Potential with ChatGPT in 2024: Myths vs. Reality

Explore legitimate ways to earn money with ChatGPT in 2024 while avoiding common misconceptions and myths surrounding AI.

# Rediscovering the Joy of Our Inner Child

Exploring the reasons behind our inner child's unhappiness and how to reconnect with its joy.

Writing About Sobriety: An Essential Reflection on Healing

An exploration of sobriety's impact, reflecting on personal growth and the healing power of writing.

Unleashing Your Potential: How Dr. Julie Smith Built a Brand

Discover how psychologist Dr. Julie Smith turned her 9-5 into a thriving personal brand and amassed millions of followers on social media.

Unlocking the Power of TypeScript: What, Why, and How

Discover the significance of TypeScript, its benefits, and how it can transform your development process.

Navigating Life After Selling My Business: A Golfer's Journey

After selling my business, I explore new opportunities and embrace my passion for golf and blogging.

Finding Inner Peace: The Art of Living Amidst Chaos

Explore the deeper meaning of tranquility and wisdom in life, emphasizing the importance of calmness amidst chaos.

Create a Dynamic Image Slider App Using React and JavaScript

Learn how to create a dynamic image slider app using React and JavaScript with step-by-step guidance.