May 26 2025
dotnet add package Carter
dotnet add package FluentValidation
dotnet add package FluentValidation.DependencyInjectionExtensions
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCarter();
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddValidatorsFromAssemblyContaining<CreateUserValidator>();
var app = builder.Build();
app.MapCarter();
app.Run();
public class User
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
public record CreateUserRequest(string Name, string Email);
// Validators/CreateUserValidator.cs
using FluentValidation;
public class CreateUserValidator : AbstractValidator<CreateUserRequest>
{
public CreateUserValidator()
{
RuleFor(x => x.Name).NotEmpty().WithMessage("Name is required");
RuleFor(x => x.Email).EmailAddress().WithMessage("Invalid email format");
}
}
public interface IUserService
{
IEnumerable<User> GetAllUsers();
User? GetUserById(int id);
User CreateUser(CreateUserRequest request);
}
public class UserService : IUserService
{
private readonly List<User> _users =
[
new User { Id = 1, Name = "Alice", Email = "alice@example.com" },
new User { Id = 2, Name = "Bob", Email = "bob@example.com" }
];
public List<User> GetAllUsers()
{
return _users;
}
public User? GetUserById(int id)
{
return _users.FirstOrDefault(u => u.Id == id);
}
public User CreateUser(CreateUserRequest request)
{
var user = new User
{
Id = _users.Max(u => u.Id) + 1,
Name = request.Name,
Email = request.Email
};
_users.Add(user);
return user;
}
}
public class UserModule : ICarterModule
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapGet("/users", (IUserService userService) =>
{
var users = userService.GetAllUsers();
return Results.Ok(users);
});
app.MapGet("/users/{id:int}", (int id, IUserService userService) =>
{
var user = userService.GetUserById(id);
return user is null ? Results.NotFound("User not found") : Results.Ok(user);
});
app.MapPost("/users", async (
HttpRequest req,
IUserService userService,
IValidator<CreateUserRequest> validator) =>
{
var userRequest = await req.ReadFromJsonAsync<CreateUserRequest>();
if (userRequest is null)
return Results.BadRequest("Invalid request payload");
ValidationResult validationResult = await validator.ValidateAsync(userRequest);
if (!validationResult.IsValid)
return Results.BadRequest(validationResult.Errors);
var newUser = userService.CreateUser(userRequest);
return Results.Created($"/users/{newUser.Id}", newUser);
});
}
}
var group = app.MapGroup("/users");
group.MapGet("/", (IUserService service) =>
Results.Ok(service.GetAllUsers()));
group.MapGet("/{id:int}", (int id, IUserService service) =>
{
var user = service.GetUserById(id);
return user is null ? Results.NotFound() : Results.Ok(user);
});
public UserModule()
: base("/api") // All endpoints will be prefixed with /api
{
WithTags("Users"); // Swagger/OpenAPI tag for this module
IncludeInOpenApi(); // Automatically include all endpoints in Swagger
}
1. Design Patterns that Deliver
This isn’t just another design patterns book. Dive into real-world examples and practical solutions to real problems in real applications.Check out it here.
Go-to resource for understanding the core concepts of design patterns without the overwhelming complexity. In this concise and affordable ebook, I've distilled the essence of design patterns into an easy-to-digest format. It is a Beginner level. Check out it here.
Every Monday morning, I share 1 actionable tip on C#, .NET & Arcitecture topic, that you can use right away.
Join 15,250+ subscribers to improve your .NET Knowledge.
Subscribe to the TheCodeMan.net and be among the 15,250+ subscribers gaining practical tips and resources to enhance your .NET expertise.