European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET Core 10.0 Hosting - HostForLIFE :: Handling Global Exceptions in ASP.NET Fundamentals: Creating Secure and Consistent Error Responses

clock July 31, 2026 13:05 by author Peter

In production applications, unhandled exceptions are unavoidable. Unexpected null values occur, database connections break, external APIs stop working, and custom exceptions may be thrown by business rules. These mistakes frequently result in inconsistent answers, reveal private implementation details, and complicate debugging in the absence of centralized exception handling.

Applications may offer consistent error answers while reporting failures for diagnostics thanks to ASP.NET Core's built-in middleware for handling exceptions globally. In addition to improving API accessibility and maintainability, a centralized error-handling approach keeps internal information hidden from clients.

This article describes how to create production-ready global exception handling in ASP.NET Core instead of enclosing each controller action in try-catch blocks.

Note: Without disclosing stack traces, connection strings, or other private implementation information, error replies should give API users enough information to understand what went wrong.

Why Global Exception Handling Matters?
Without centralized exception handling, applications often suffer from:

  • Inconsistent error responses
  • Duplicate try-catch blocks
  • Exposed stack traces
  • Difficult debugging
  • Poor client experience
  • Missing production logs

A single exception handling pipeline keeps error handling consistent across the application.

Common Exception Types

Production applications frequently encounter:

  • Validation exceptions
  • Authentication failures
  • Authorization failures
  • Database exceptions
  • External API failures
  • File system errors
  • Timeout exceptions
  • Business rule violations

Different exceptions should return different HTTP status codes while following the same response format.

Exception Handling Flow

flowchart LR

A[Client Request]
B[ASP.NET Core Middleware]
C[Controller / Service]
D{Exception?}
E[Global Exception Handler]
F[ProblemDetails Response]


A --> B
B --> C
C --> D
D -->|No| A
D -->|Yes| E
E --> F
F --> A


Every unhandled exception flows through the global exception handler before a response is returned to the client.

Using the Built-in Exception Handler

Configure the exception handling middleware.
var app = builder.Build();

app.UseExceptionHandler("/error");

app.MapControllers();

app.Run();

This middleware intercepts unhandled exceptions before they reach the client.

Creating an Error Endpoint

Create a centralized endpoint for handling exceptions.

[ApiExplorerSettings(IgnoreApi = true)]
[Route("/error")]
public class ErrorController : ControllerBase
{
    public IActionResult HandleError()
    {
        return Problem(
            title: "An unexpected error occurred.",
            statusCode: 500);
    }
}


Returning a standardized response makes client-side error handling much simpler.

Using ProblemDetails
ASP.NET Core supports the RFC 7807 Problem Details format.

Example response:
{
  "type": "about:blank",
  "title": "Resource not found.",
  "status": 404,
  "detail": "The requested product does not exist."
}

Using ProblemDetails creates consistent error responses across the API.

Handling Custom Exceptions

Applications often define business-specific exceptions.
public class ProductNotFoundException
    : Exception
{
    public ProductNotFoundException(int id)
        : base($"Product {id} was not found.")
    {
    }
}


Custom exceptions make application logic easier to understand and maintain.

Mapping Exceptions to Status Codes
Different exception types should produce appropriate HTTP responses.

ExceptionHTTP Status
ValidationException 400 Bad Request
UnauthorizedAccessException 401 Unauthorized
ProductNotFoundException 404 Not Found
ConflictException 409 Conflict
TimeoutException 408 Request Timeout
Exception 500 Internal Server Error

Returning meaningful status codes improves API usability and debugging.

Logging Exceptions
Always log unexpected exceptions.
try
{
    await service.ProcessAsync();
}
catch (Exception ex)
{
    logger.LogError(
        ex,
        "Unexpected error while processing request.");

    throw;
}


Structured logging makes production troubleshooting significantly easier.

Returning Validation Errors
Validation failures should return a 400 Bad Request.
if (!ModelState.IsValid)
{
    return ValidationProblem(ModelState);
}

This provides clients with detailed validation information without exposing internal implementation details.

Common Production Mistakes

ProblemRoot Cause
Stack traces returned to clients Developer exception page enabled in production
Inconsistent responses Local try-catch blocks everywhere
Missing logs Exceptions swallowed silently
Incorrect status codes Every exception returns HTTP 500
Difficult debugging No correlation IDs in logs
Sensitive information exposed Internal exception messages returned directly

Most exception handling issues stem from inconsistent implementation rather than framework limitations.

Best Practices

  • Use centralized exception handling middleware.
  • Return consistent ProblemDetails responses.
  • Log every unexpected exception.
  • Map business exceptions to appropriate HTTP status codes.
  • Include correlation IDs in logs.
  • Hide sensitive implementation details from clients.
  • Monitor exception rates using your observability platform.

Common Anti-Patterns
Avoid these common mistakes:

  • Wrapping every controller action in try-catch.
  • Returning stack traces in production.
  • Swallowing exceptions without logging.
  • Returning HTTP 200 for failed operations.
  • Using generic HTTP 500 responses for validation errors.
  • Exposing database or server details in error messages.

FAQ
Should every controller use try-catch?

No. Most unhandled exceptions should be processed by centralized exception handling middleware. Use try-catch only when you can recover from a specific exception locally.

What is ProblemDetails?
ProblemDetails is a standardized error response format defined by RFC 7807. It helps APIs return consistent and machine-readable error information.

Should exception details be returned to clients?
Only when they are safe and useful. Avoid exposing stack traces, SQL queries, connection strings, or other internal implementation details.

How should exceptions be monitored in production?
Use structured logging together with Application Insights, OpenTelemetry, Seq, Elasticsearch, or another observability platform to monitor exception frequency, trends, and root causes.

Conclusion
A key component of creating dependable ASP.NET Core apps is global exception handling. You may increase application security and developer efficiency by centralizing error handling, providing uniform ProblemDetails replies, and regularly reporting unexpected failures. Create a single, well-defined exception handling pipeline that generates consistent replies, safeguards sensitive data, and makes production troubleshooting easier rather than dispersing exception handling functionality throughout your codebase.

HostForLIFE.eu ASP.NET Core 10.0 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core 10.0 Hosting - HostForLIFE :: Common Errors and Real-World MediatR Patterns in ASP.NET Core

clock July 24, 2026 11:42 by author Peter

Controllers frequently take on too many responsibilities as ASP.NET Core applications expand, including managing HTTP requests, verifying input, carrying out business logic, and communicating with the data layer. Applications are more difficult to test, maintain, and expand due to this close dependency.

By directing requests through specialized handlers, the well-known library MediatR helps developers separate application components by implementing the Mediator paradigm. Applications that adhere to CQRS and Clean Architecture principles make extensive use of it.

But not all issues can be resolved with MediatR. Although it makes code more organized, when used improperly, it can add needless complexity. We'll look at frequent errors, useful MediatR patterns, and when it makes sense to utilize it in this post.

What Is MediatR?
MediatR is an in-process messaging library that enables communication between different parts of an application without creating direct dependencies.

Instead of a controller calling a service directly:
Controller
    │
ProductService
    │
Repository

The request flows through MediatR:

Controller
    │
MediatR
    │
Request Handler
    │
Repository


The controller only knows about MediatR, while the business logic resides inside dedicated request handlers.

Request and Response Pattern
The most common MediatR pattern is the Request/Response model.

First, define a request:
using MediatR;

public record GetProductQuery(int Id) : IRequest<Product>;


Next, implement the handler:
public class GetProductHandler
    : IRequestHandler<GetProductQuery, Product>
{
    private readonly IProductRepository _repository;

    public GetProductHandler(IProductRepository repository)
    {
        _repository = repository;
    }

    public async Task<Product> Handle(
        GetProductQuery request,
        CancellationToken cancellationToken)
    {
        return await _repository.GetByIdAsync(request.Id);
    }
}


Finally, send the request from a controller:
[HttpGet("{id}")]
public async Task<IActionResult> Get(
    int id,
    IMediator mediator)
{
    var product = await mediator.Send(new GetProductQuery(id));

    return product is null
        ? NotFound()
        : Ok(product);
}


This approach keeps controllers thin and delegates business logic to handlers.

Using Commands for Data Modification

Queries retrieve data, while commands modify it.

Example command:
public record CreateProductCommand(
    string Name,
    decimal Price) : IRequest<int>;


The corresponding handler performs validation, business logic, and persistence before returning the new product ID.

Separating commands and queries improves readability and aligns well with the Command Query Responsibility Segregation (CQRS) pattern.

Notifications for Multiple Actions
Sometimes a single event should trigger multiple independent actions.

For example:

  • Send an email
  • Update inventory
  • Write an audit log
  • Publish an integration event

Instead of placing all logic inside one handler, use notifications.
public record ProductCreatedNotification(int ProductId)
: INotification;


Each notification handler executes independently, making the application easier to extend without modifying existing code.

Pipeline Behaviors

One of MediatR's most powerful features is Pipeline Behaviors.

They allow cross-cutting concerns to execute before or after request handlers.

Common uses include:

  • Validation
  • Logging
  • Performance monitoring
  • Authorization
  • Exception handling

Instead of duplicating logic across handlers, pipeline behaviors centralize these concerns, resulting in cleaner and more maintainable code.

When MediatR Works Best

MediatR provides the greatest value in applications that have:

  • Complex business workflows
  • Multiple use cases
  • Clean Architecture
  • CQRS implementation
  • Large development teams
  • Extensive testing requirements

For these applications, separating requests into dedicated handlers improves maintainability and reduces coupling.

When MediatR May Be Unnecessary

Not every application benefits from MediatR.

For a simple CRUD API with only a few endpoints, adding requests, handlers, and pipeline behaviors may increase complexity without delivering significant value.

A straightforward service layer is often sufficient for:

  • Small internal tools
  • Prototype applications
  • Basic CRUD services
  • Lightweight APIs

Choose MediatR when it solves an architectural problem—not simply because it's popular.

Common Mistakes
Creating a Handler for Every Tiny Operation
Some developers create handlers for trivial methods that simply forward calls to a repository.

For example:

Controller
    │
Handler
    │
Service
    │
Repository


If the handler contains no business logic, MediatR adds an extra layer without improving maintainability.

Putting Business Logic in Controllers

Even when using MediatR, controllers should remain lightweight.

Avoid:

  • Validation logic
  • Business rules
  • Database access

Controllers should receive requests, send them through MediatR, and return responses.

Overusing Notifications

Notifications are excellent for independent actions, but they should not be used when execution order or transactional consistency is critical.

If one operation depends on another, a command handler is usually a better choice.

Ignoring Pipeline Behaviors

Many teams adopt MediatR but continue duplicating validation and logging inside handlers.
Pipeline behaviors provide a cleaner and more reusable solution for cross-cutting concerns.

Best Practices
Keep handlers focused on a single responsibility.
Use commands for writes and queries for reads.

  • Keep controllers thin.
  • Use pipeline behaviors for validation, logging, and exception handling.
  • Inject only the dependencies required by each handler.
  • Avoid creating handlers that simply wrap repository methods.
  • Group requests by feature to improve project organization.
  • Unit test handlers independently from controllers.

HostForLIFE.eu ASP.NET Core 10.0 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core 10.0 Hosting - HostForLIFE :: Explaining the CQRS Pattern: Developing Maintainable and Scalable Applications

clock July 20, 2026 12:17 by author Peter

Managing data operations effectively gets more difficult as applications become more sophisticated. Conventional designs frequently read and write data using the same paradigm. Although this strategy is effective for smaller applications, as company needs change, it may become challenging to expand and sustain.

Imagine an online store that simultaneously handles millions of product searches and thousands of orders per minute. Writing order data and accessing product information can have somewhat distinct needs. Performance bottlenecks and increased application complexity may result from using the same model for both processes.

The CQRS (Command Query Responsibility Segregation) paradigm is useful in this situation. By separating read and write processes, CQRS enables independent optimization of each side.

This article will teach you about the architecture, advantages, difficulties, implementation techniques, and recommended practices for contemporary applications of CQRS.

What Is CQRS?
CQRS stands for:
Command Query Responsibility Segregation

The pattern separates:

Commands

Operations that modify data.

Examples:

  • Create Order
  • Update Product
  • Delete User
  • Process Payment

Queries
Operations that retrieve data.

Examples:

  • Get Order Details
  • Search Products
  • View Dashboard
  • Generate Reports

Instead of using a single model for both operations, CQRS creates separate models for reading and writing.

Traditional CRUD Architecture

Most applications start with a CRUD approach.

Application
      ↓
Single Model
      ↓
Database


The same model handles:

  • Create
  • Read
  • Update
  • Delete

While simple, this approach can become difficult to scale in complex systems.

CQRS Architecture

With CQRS:
Application
      ↓
Commands
      ↓
Write Model
      ↓
Database

Queries
      ↓
Read Model
      ↓
Read Database

Read and write operations are separated.

This allows each side to evolve independently.
Why Use CQRS?
CQRS addresses several common application challenges.

Independent Scaling
Read workloads often exceed write workloads.

Example:
10000 Reads

500 Writes

CQRS allows read systems to scale independently.

Improved Performance

Read models can be optimized specifically for queries.

Better Maintainability
Business logic becomes easier to organize.

Flexible Data Models

Read models and write models can have different structures.

Easier Integration with Event-Driven Systems
CQRS works naturally with event sourcing and messaging systems.

Understanding Commands

Commands represent actions that change system state.

Example:
CreateCustomer

A command contains:

  • Intent
  • Input data
  • Validation rules

Example:
public record CreateCustomerCommand(
    string Name,
    string Email
);


Commands do not return data.

They indicate that something should happen.

Command Handlers

Command handlers process commands.

Example:
public class CreateCustomerHandler
{
    public async Task Handle(
        CreateCustomerCommand command)
    {
        // Save customer
    }
}

Responsibilities include:

  • Validation
  • Business rules
  • Data persistence

Handlers focus exclusively on write operations.

Understanding Queries

Queries retrieve information without changing data.

Example:
GetCustomerById


Query example:
public record GetCustomerQuery(
    int CustomerId
);


Queries should never modify application state.

Query Handlers
Query handlers process read requests.

Example:
public class GetCustomerHandler
{
    public async Task<CustomerDto>
    Handle(
        GetCustomerQuery query)
    {
        return customer;
    }
}


Query handlers focus on data retrieval and presentation.

Read Models vs Write Models

One of CQRS's biggest advantages is model separation.

Write Model
Optimized for:

  • Business rules
  • Validation
  • Transactions

Example:
Customer Entity

Read Model
Optimized for:

  • Fast retrieval
  • Reporting
  • Search operations

Example:
Customer Dashboard View

Different models serve different purposes.

CQRS Workflow

A typical workflow:

Command Flow

User Request
      ↓
Command
      ↓
Command Handler
      ↓
Database


Query Flow
User Request
      ↓
Query
      ↓
Query Handler
      ↓
Read Database

The two paths remain independent.

CQRS with MediatR in ASP.NET Core

MediatR is commonly used to implement CQRS.

Install package:
dotnet add package MediatR

Register MediatR:
builder.Services
.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(
        typeof(Program).Assembly);
});


MediatR simplifies command and query handling.

Command Example

Command:
public record CreateOrderCommand(
    string Product,
    decimal Price
);


Handler:
public class CreateOrderHandler
{
    public async Task Handle(
        CreateOrderCommand command,
        CancellationToken token)
    {
        // Save order
    }
}


This represents the write side.

Query Example
Query:
public record GetOrderQuery(
    int Id
);


Handler:
public class GetOrderHandler
{
    public async Task<OrderDto>
    Handle(
        GetOrderQuery query,
        CancellationToken token)
    {
        return order;
    }
}


This represents the read side.

CQRS and Event Sourcing
CQRS is frequently combined with Event Sourcing.

Instead of storing current state:

Order Status:
Shipped


Store events:
Order Created

Order Paid

Order Shipped

Benefits include:

  • Complete audit trail
  • Historical reconstruction
  • Improved traceability

Many event-driven systems use both patterns together.

CQRS in Microservices
CQRS works well in microservice architectures.

Example:
Order Service
      ↓
Events
      ↓
Read Models

Reporting Service


Analytics Service

Each service can maintain its own optimized read model.
This improves scalability and autonomy.

Practical Example
Consider an online store.

Write operation:
Place Order

Command handler:
Validate Payment
      ↓
Create Order
      ↓
Save Database


Read operation:
View Order History

Query handler:
Retrieve Read Model
      ↓
Return Results

Each workflow is optimized independently.

Benefits of CQRS
Better Scalability
Read and write workloads scale separately.

Improved Performance
Optimized read models improve query speed.

Clear Separation of Responsibilities
Business logic becomes easier to maintain.

Flexible Data Structures
Different models for different needs.

Easier Integration

Works naturally with event-driven architectures.

These benefits become increasingly valuable in large applications.

Challenges of CQRS

CQRS is not without trade-offs.

Increased Complexity
Additional models and handlers are required.

More Infrastructure

Separate read and write paths must be maintained.

Eventual Consistency
Read models may not update instantly.

Higher Learning Curve
Teams must understand additional patterns and concepts.
For small applications, CQRS may introduce unnecessary complexity.

When Should You Use CQRS?

CQRS is a strong choice when:

  • Read and write workloads differ significantly.
  • Business logic is complex.
  • Scalability is important.
  • Event-driven architecture is planned.
  • Multiple read models are required.

Avoid CQRS when:

  • Applications are small.
  • Requirements are simple.
  • CRUD operations dominate.

Complexity should be justified by business needs.

Best Practices
When implementing CQRS:

  • Keep commands focused.
  • Separate read and write models clearly.
  • Avoid sharing entities between sides.
  • Use DTOs for queries.
  • Implement validation at the command level.
  • Monitor eventual consistency.
  • Consider MediatR for ASP.NET Core projects.
  • Introduce CQRS gradually when possible.

These practices improve maintainability and reduce complexity.

Common Mistakes to Avoid
Avoid these common issues:

  • Applying CQRS to simple CRUD systems.
  • Mixing query logic into command handlers.
  • Sharing models unnecessarily.
  • Ignoring eventual consistency.
  • Creating overly complex architectures.
  • Using CQRS without clear business justification.

The pattern should solve a real problem, not create one.

HostForLIFE.eu ASP.NET Core 10.0 Hosting
European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Month List

Tag cloud

Sign in