Zum Hauptinhalt springen
Echtzeit-Radar & Feeds
Alle RSS Feeds ➔
👥 Community & Social
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Windows Tipps & SecurityGrafikkarte vor Überhitzung schützen: So geht’s(25.09.2026 um 08:00 Uhr)
••••••••••
Intelligence View
⚡ tsecurity.de Intelligence

Productive Web API Development with FastEndpoints and Vertical Slice Architecture in .NET

In recent projects, I started using Vertical Slice Architecture (VSA). I chose VSA because it provides fast feature development and easy navigation in the codebase. Each slice encapsulates all aspects of a specific feature, including the…

0
↗ Quelle (dev.to)
Reagiere als Erste:r — dein Feedback zählt!

In recent projects, I started using Vertical Slice Architecture (VSA).

I chose VSA because it provides fast feature development and easy navigation in the codebase.

Each slice encapsulates all aspects of a specific feature, including the Web API, business logic, and data access.



I was looking for a way to become more productive with my VSA when creating Web APIs.

And I found a FastEndoints library that helped me with productivity.



Today I want to share with you my personal experience — how to be more productive when developing Web APIs with FastEndpoints and Vertical Slice Architecture.

We will go step-by-step and implement a production ready application that has Web API, validation, stores and retrieves data from a database.




On my website: antondevtips.com I share .NET and Architecture best practices.

Subscribe to become a better developer.

Download the source code for this blog post for free.






What is FastEndpoints?



FastEndpoints is an open-source library for .NET that simplifies the creation of Web APIs by eliminating the need of writing boilerplate code.

Built on top of ASP.NET Core Minimal APIs, it leverages all the performance benefits while providing a more straightforward programming model.



In the Minimal APIs, you need to define yourself how you want to structure your endpoints, how to group or not group them together in a single file.

In FastEndpoints you define each endpoint in a separate class, which results in a Single Responsible and maintainable endpoints.



For me, this concept ideally fits in Vertical Slice Architecture.



Now let's explore an application we will be building.





The Application We Will Be Building



Today I'll show you how to implement a Shipping Application that is responsible for creating customers, orders and shipments for ordered products.



This application implements the following use cases:




  • Create a customer

  • Create an Order with OrderItems, place a Shipment

  • Get a Shipment by number

  • Update Shipment state



Initial steps you need to follow when building this application:




  1. Create domain entities

  2. Create EF Core DbContext and mapping for the entities

  3. Create database migrations

  4. Implement use cases as Web API endpoints



Let's explore an Order and OrderItem entities:




public class Order
{
private readonly List<OrderItem> _items = new();

public Guid Id { get; private set; }
public string OrderNumber { get; private set; }
public Guid CustomerId { get; private set; }
public Customer Customer { get; private set; }
public DateTime Date { get; private set; }
public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();

private Order() { }

public static Order Create(string orderNumber, Customer customer, List<OrderItem> items)
{
return new Order
{
Id = Guid.NewGuid(),
OrderNumber = orderNumber,
Customer = customer,
CustomerId = customer.Id,
Date = DateTime.UtcNow
}.AddItems(items);
}

private Order AddItems(List<OrderItem> items)
{
_items.AddRange(items);
return this;
}
}

public class OrderItem
{
public Guid Id { get; private set; }
public string Product { get; private set; } = null!;
public int Quantity { get; private set; }
public Guid OrderId { get; private set; }
public Order Order { get; private set; } = null!;
private OrderItem() { }

public OrderItem(string productName, int quantity)
{
Id = Guid.NewGuid();
Product = productName;
Quantity = quantity;
}
}






My entities represent a Rich Domain Model — a concept from Domain Driven Design.



This concept allows me to implement business rules within my entities, in one place.

This allows me to avoid spreading business rules throughout the code base in different classes, making my code more manageable.



For example, in my Shipment entity I have the following methods:




public ErrorOr<Success> Process()
{
if (Status is not ShipmentStatus.Created)
{
return Error.Validation("Can only update to Processing from Created status");
}

Status = ShipmentStatus.Processing;
UpdatedAt = DateTime.UtcNow;

return Result.Success;
}

public ErrorOr<Success> Dispatch()
{
if (Status is not ShipmentStatus.Processing)
{
return Error.Validation("Can only update to Dispatched from Processing status");
}

Status = ShipmentStatus.Dispatched;
UpdatedAt = DateTime.UtcNow;

return Result.Success;
}






This encapsulates Shipment state changes within the Shipment entity.




public enum ShipmentStatus
{
Created,
Processing,
Dispatched,
InTransit,
Delivered,
Received,
Cancelled
}







You can download the source code for the entire application at the end of this blog post.




You can follow Domain Driven Design principle for your domain entities or use anemic entities with plain get and set properties:




public class Order
{
public Guid Id { get; set; }
public string OrderNumber { get; set; }
public Guid CustomerId { get; set; }
public Customer Customer { get; set; }
public DateTime Date { get; set; }
public List<OrderItem> Items { get; set; } = [];
}






If you don't have such business logic as I have with shipments, I recommend using plain get and set properties.



Now let's create a Web API endpoint for creating orders.

There are several code architecture styles for implementing use cases presented by an API:




  • Layered Architecture (N-Tier)

  • Clean Architecture

  • Vertical Slice Architecture (VSA)



Now a few words why I prefer VSA.



In Layered Architecture, there is a tendency to create too big classes for services and repositories.

In Clean Architecture, while having a good design in the codebase, a single feature implementation is spread throughout multiple projects.



In Vertical Slice Architecture, I have all implementation needed for a single feature in a single folder or even a single file.

Check out my blog post to learn more about different ways to structure your projects with Vertical Slices.



With Vertical Slices, I tend to start simple: implement all the logic in the webapi endpoint directly without using extra abstractions.

If my endpoint becomes too complex or the logic should be reused across multiple endpoints, I extract the logic into the Application Layer by creating MediatR commands and queries.





Implementing CreateOrder Use Case



Let's create request and response models for creating Order with items:




public sealed record CreateOrderRequest(
string CustomerId,
List<OrderItemRequest> Items,
Address ShippingAddress,
string Carrier,
string ReceiverEmail);

public sealed record OrderItemRequest(
string ProductName,
int Quantity);

public sealed record OrderResponse(
Guid OrderId,
string OrderNumber,
DateTime OrderDate,
List<OrderItemResponse> Items);

public sealed record OrderItemResponse(
string ProductName,
int Quantity);






And now let's create an API endpoint using FastEndpoints:




public class CreateOrderEndpoint(
ShippingDbContext dbContext,
ILogger<CreateOrderEndpoint> logger)
: Endpoint<CreateOrderRequest, Results<Ok<OrderResponse>, ValidationProblem, Conflict<string>, NotFound<string>>>
{
public override void Configure()
{
Post("/api/orders");
AllowAnonymous();
Validator<CreateOrderRequestValidator>();
}

public override async Task<Results<Ok<OrderResponse>, ValidationProblem, Conflict<string>, NotFound<string>>> ExecuteAsync(
CreateOrderRequest request, CancellationToken cancellationToken)
{
var customer = await dbContext.Set<Customer>()
.FirstOrDefaultAsync(c => c.Id == Guid.Parse(request.CustomerId), cancellationToken);

if (customer is null)
{
logger.LogWarning("Customer with ID '{CustomerId}' does not exist", request.CustomerId);
return TypedResults.NotFound($"Customer with ID '{request.CustomerId}' does not exist");
}

var order = Order.Create(
orderNumber: GenerateNumber(),
customer,
request.Items.Select(x => new OrderItem(x.ProductName, x.Quantity)).ToList()
);

var shipment = Shipment.Create(
number: GenerateNumber(),
orderId: order.Id,
address: request.ShippingAddress,
carrier: request.Carrier,
receiverEmail: request.ReceiverEmail,
items: []
);

var shipmentItems = CreateShipmentItems(order.Items, shipment.Id);
shipment.AddItems(shipmentItems);

await dbContext.Set<Order>().AddAsync(order, cancellationToken);
await dbContext.Set<Shipment>().AddAsync(shipment, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);

logger.LogInformation("Created order: {@Order} with shipment: {@Shipment}", order, shipment);

var response = order.MapToResponse();
return TypedResults.Ok(response);
}
}






As you can see I am using EF Core DbContext directly inside endpoint ExecuteAsync method.

And nothing is wrong with this approach.

If I need to create an order from multiple places, like from other API endpoints or event handlers - I will extract this logic into a MediatR command.



In the CreateOrder file, I also have the Validator:




public class CreateOrderRequestValidator : Validator<CreateOrderRequest>
{
public CreateOrderRequestValidator()
{
RuleFor(x => x.CustomerId)
.NotEmpty()
.Must(id => Guid.TryParse(id, out _));

RuleFor(x => x.Items)
.NotEmpty().WithMessage("Order must have at least one item.")
.ForEach(item =>
{
item.SetValidator(new OrderItemRequestValidator());
});

RuleFor(x => x.ShippingAddress)
.NotNull()
.SetValidator(new AddressValidator());

RuleFor(x => x.Carrier)
.NotEmpty();

RuleFor(x => x.ReceiverEmail)
.NotEmpty()
.EmailAddress();
}
}

public class OrderItemRequestValidator : Validator<OrderItemRequest>
{
public OrderItemRequestValidator()
{
RuleFor(x => x.ProductName)
.NotEmpty();

RuleFor(x => x.Quantity)
.GreaterThan(0);
}
}






And in the end of the file, I have mapping:




static file class MappingExtensions
{
public static OrderResponse MapToResponse(this Order order)
{
return new OrderResponse(
OrderId: order.Id,
OrderNumber: order.OrderNumber,
OrderDate: order.Date,
Items: order.Items.Select(x => new OrderItemResponse(
ProductName: x.Product,
Quantity: x.Quantity)).ToList()
);
}
}






Our use case for creating order looks really simple: API endpoint, database logic, validation and mapping all in a single place — in one file.



Here is how all the Vertical Slices look like in my solution.



Screenshot_1



Here is how my solution looks like:



Screenshot_2



You can extract validation and mapping into other files, this is also a good great approach.

For example:



Screenshot_4





Why FastEndpoints?



Why am I using FastEndpoints and not Minimal APIs?



FastEndpoints offer the following advantages:




  • FastEndpoints offer a ready code structure for API endpoints with a great design, so you don't need to implement your own with Minimal APIs

  • FastEndpoints implement REPR pattern (Request-Endpoint-Response) where you need to specify a Request and Response types for the endpoint. It brings compiler time safety as you can't return a wrong object or HTTP status code by a mistake.

  • Each endpoint is implemented in a separate Single Responsible class which makes it an ideal choice for Vertical Slices

  • FastEndpoints has built-in Model Binding which is more flexible than built-in model binding in Minimal APIs

  • FastEndpoints has built-in support for FluentValidation





Implementing DeliverShipmentEndpoint Use Case



Let's explore how to implement a DeliverShipmentEndpoint that changes Shipment state into Delivered state:




public class DeliverShipmentEndpoint(ShippingDbContext dbContext,
ILogger<DeliverShipmentEndpoint> logger)
: EndpointWithoutRequest<Results<NoContent, NotFound<string>, ProblemHttpResult>>
{
public override void Configure()
{
Post("/api/shipments/deliver/{shipmentNumber}");
AllowAnonymous();
}

public override async Task<Results<NoContent, NotFound<string>, ProblemHttpResult>> ExecuteAsync(CancellationToken cancellationToken)
{
var shipmentNumber = Route<string>("shipmentNumber");

var shipment = await dbContext.Shipments.FirstOrDefaultAsync(x => x.Number == shipmentNumber, cancellationToken);
if (shipment is null)
{
logger.LogDebug("Shipment with number {ShipmentNumber} not found", shipmentNumber);
return TypedResults.NotFound($"Shipment with number '{shipmentNumber}' not found");
}

var response = shipment.Deliver();
if (response.IsError)
{
return response.Errors.ToProblem();
}

await dbContext.SaveChangesAsync(cancellationToken);

logger.LogInformation("Delivered shipment with {ShipmentNumber}", shipmentNumber);
return TypedResults.NoContent();
}
}






Look how easy it is to change the shipment's state by just calling shipment.Deliver() method.

That's because we have encapsulated all business logic inside a Shipment entity.



All the rest use cases in this project are implemented in a same manner.




On my website: antondevtips.com I share .NET and Architecture best practices.

Subscribe to become a better developer.

Download the source code for this blog post for free.


1. Sofort-Triage & Abwehrmaßnahmen

SOC Incident Playbook: Remote Code Execution (RCE) Defense
Syntax validiert (0 Fehler)
title: Detect Exploitation - Productive Web API Development with FastEndpoints and Vertical Slice Architecture in .NET
id: 60bf7057-1906-43c8-829e-2065f3b1a238
status: experimental
description: Automatisch generierte SIEM-Erkennungsregel basierend auf CTI Intelligence
references:
  - https://tsecurity.de/
author: iShareStuff CTI Automated Detection Engine
date: 2026-09-27
logsource:
  category: network_connection
  product: any
detection:
  selection:
      CommandLine|contains:
        - 'exploit'
  condition: selection
falsepositives:
  - Legitime administrative Zugriffe oder Penetrationstests
level: high
tags:
  - attack.initial_access
Syntax validiert (0 Fehler)
rule CTI_Threat_Indicator {
    meta:
        author = "iShareStuff CTI Automated Detection Engine"
        date = "2026-09-27"
        description = "YARA Signature for "
    strings:
        $str = "Productive Web API Development" ascii wide
    condition:
        any of them
}
Syntax validiert (0 Fehler)
index=security sourcetype IN ("cisco:asa", "pan:traffic", "zeek_conn", "suricata", "WinEventLog:Security")
("Productive Web API Development with Fast")
| stats count earliest(_time) as first_seen latest(_time) as last_seen by src_ip, dest_ip, dest_host, signature
| eval first_seen=strftime(first_seen, "%Y-%m-%d %H:%M:%S"), last_seen=strftime(last_seen, "%Y-%m-%d %H:%M:%S")
| sort - count
Syntax validiert (0 Fehler)
message: "*Productive Web API Development with Fast*"
Syntax validiert (0 Fehler)
CommonSecurityLog
| where Message has "Productive Web API Development with Fast"
| summarize EventCount = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated) by SourceIP, DestinationIP, DestinationPort, Activity
| extend DetectionRule = "iShareStuff-CTI-Compiled"
| sort by EventCount desc

2. Cyber Threat Intelligence & Forensik

🎯
MITRE ATT&CK Matrix Navigator 14 Taktiken
Reconnaissance
-
Resource Development
-
Initial Access
Execution
Persistence
-
Privilege Escalation
Defense Evasion
Credential Access
-
Discovery
-
Lateral Movement
-
Collection
-
Command and Control
Exfiltration
-
Impact
tsecurity.de Cognitive Threat RAG
Fokus-Vektor:

Analyse für identifizierte Bedrohung auf Basis von Live-CTI (ENISA EUVD): CVSS 0.0 · EPSS 0.0% · CISA KEV: nein. Handlungsableitung aus den verlinkten Hersteller-Quellen.

🛡️ Angriffsfläche & Exposure

Netzwerk/Remote-Zugriff ohne Vorauthentifizierung möglich.

⚡ Empfohlene Sofortmaßnahmen
  • 1. Perimeter-Inspektion: Relevante Portfreigaben und exponierte Endpunkte unverzüglich scannen.
  • 2. Patch-Applikation: Hersteller-Hotfix einspielen oder betroffene Daemons in isolierte DMZ-Segmente überführen.
  • 3. Telemetrie & EDR-Alerts: Prozessaufrufe und Child-Processes auf anomale Shell-Spawns überwachen.
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Productive Web API Development with FastEndpoints and Vertical Slice Architecture in .NET

Thematisch verwandte Begriffe: Productive, Development, with, FastEndpoints · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-100739 | A vulnerability was detected in mathurvishal CloudClassroom-PHP-Project…
Advisory →
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag