Skip to content

luuthuong/e-shop-microservices

Repository files navigation

ESHOP AspNetCore WebAPI

About  •  Tech Stacks & Research  •  The Solution Architecture  •  How to run  •  References

About

This project was built as a learning to understand the concept of the **Clean Architecture** together with Entity FrameworkCore as ORM and MediatR as CQRS library. The intend purpose was to build a simple store application, where you can store and manage the products as an administrator, and able to order, online payment as the client.

Structure Folder

Service Description
Customer Managing customers
Order Managing order processing
Product Managing product items
Payment Managing payment

Tech Stacks & Researchs

  • AspNetCore 8 WebAPI (using Minimal API)
  • SwaggerUI
  • API Versioning
  • Onion architecture
  • Authentication
  • Testing
  • Caching
  • Logging
  • Performance
  • Mapping (AutoMapper)
  • Background Jobs
  • Exception Handling
  • Code First Approach
  • Dependency injection
  • CRQS with MediatR library
  • MediatR pipelines for: Caching, Validation, Logging
  • Repository pattern
  • Option pattern
  • Dockerized
  • CI/CD
  • Kubernetes

Performance

Async Projections

In a Command and Query Responsibility Segregation (CQRS) system, denormalized asynchronous projections can significantly improve performance for several reasons:

  • Improved Read Performance: In a CQRS system, the read side is separate from the write side and is optimized for querying data. By denormalizing the data in the projections, the read side can access the data it needs more efficiently, reducing the number of joins required to retrieve data and ultimately speeding up query performance.

  • Reduced Latency: When data is denormalized, it's usually stored in a format that's more suitable for the specific use case. This can reduce the amount of data that needs to be retrieved from the database, which can help to minimize latency and improve the overall responsiveness of the system.

  • Increased Scalability: Denormalized projections can handle a larger volume of data more efficiently than normalized ones. This is because denormalized data is usually stored in a format that's optimized for a specific use case, which allows the system to process the data more quickly and with less resources.

  • Simpler Architecture: In a normalized data model, data is often spread out across multiple tables, which can make the system more complex to design, develop, and maintain. By denormalizing the data, it can be easier to manage and understand, which can simplify the overall architecture and make the system more maintainable.

  • Improved Concurrency: Asynchronous projections allow multiple operations to be performed at the same time and, denormalized projections reduce contention, helping to improve concurrent write operation performance.

In summary, denormalized asynchronous projections in a CQRS system can help to improve performance by reducing latency, increasing scalability, simplifying the architecture, and improving concurrency. This results in a more responsive and efficient system that can handle larger volumes of data and more complex queries.

Snapshotting

Snapshotting is an optimisation that reduces time spent on reading event from an event store.

Gunia, Kacper. "Event Sourcing: Snapshotting", domaincentric.net, last edited on 5 Jun 2020

More details in snapshot section.

Minimize Exceptions

Exceptions should be rare. Throwing and catching exceptions is slow relative to other code flow patterns. Because of this, exceptions shouldn't be used to control normal program flow.

Recommendations:

  • Do not use throwing or catching exceptions as a means of normal program flow, especially in hot code paths.
  • Do include logic in the app to detect and handle conditions that would cause an exception.
  • Do throw or catch exceptions for unusual or unexpected conditions.
  • App diagnostic tools, such as Application Insights, can help to identify common exceptions in an app that may affect performance.

"ASP.NET Core Performance Best Practices" MSDN, Microsoft Docs, last edited on 18 Fev 2022

Pool HTTP connections with HttpClientFactory

Closed HttpClient instances leave sockets open in the TIME_WAIT state for a short period of time. If a code path that creates and disposes of HttpClient objects is frequently used, the app may exhaust available sockets.

Recommendations:

  • Do not create and dispose of HttpClient instances directly.
  • Do use HttpClientFactory to retrieve HttpClient instances.

"ASP.NET Core Performance Best Practices" MSDN, Microsoft Docs, last edited on 18 Fev 2022

DbContext Pooling

The basic pattern for using EF Core in an ASP.NET Core application usually involves registering a custom DbContext type into the dependency injection system and later obtaining instances of that type through constructor parameters in controllers. This means a new instance of the DbContext is created for each request.

In version 2.0 we are introducing a new way to register custom DbContext types in dependency injection which transparently introduces a pool of reusable DbContext instances. This is conceptually similar to how connection pooling operates in ADO.NET providers and has the advantage of saving some of the cost of initialization of DbContext instance.

"New features in EF Core 2.0" MSDN, Microsoft Docs, last edited on 11 Oct 2020

The Solution Architecture

flow drawio

Workflow

image

How to run

Clone the repository git clone https://github.com/luuthuong/eshop-microservices

In root directory

dotnet run --project .\src\ProductSyncService\ProductSyncService.API

Or docker: docker compose up --build

Authors

References

Articles

Blogs

Posts