Click here to Skip to main content
14,599,740 members

Simple Transaction: Microservices Sample Architecture for .NET Core Application

Rate this:
4.93 (45 votes)
Please Sign up or sign in to vote.
4.93 (45 votes)
21 Mar 2019CPOL
Microservices sample architecture for .NET Core Application

.Net Core 2.2 Sample With C#.Net, EF and SQL Server


Introduction

This is a .Net Core sample application and an example of how to build and implement a microservices based back-end system for a simple automated banking feature like Balance, Deposit, Withdraw in ASP.NET Core Web API with C#.Net, Entity Framework and SQL Server.

Application Architecture

The sample application is build based on the microservices architecture. There are serveral advantages in building a application using Microservices architecture like Services can be developed, deployed and scaled independently.The below diagram shows the high level design of Back-end architecture.

  • Identity Microservice - Authenticates user based on username, password and issues a JWT Bearer token which contains Claims-based identity information in it.
  • Transaction Microservice - Handles account transactions like Get balance, deposit, withdraw
  • API Gateway - Acts as a center point of entry to the back-end application, Provides data aggregation and communication path to microservices.

Application Architecture

Design of Microservice

This diagram shows the internal design of the Transaction Microservice. The business logic and data logic related to transaction service is written in a seperate transaction processing framework. The framework receives input via Web Api and process those requests based on some simple rules. The transaction data is stored up in SQL database.

Microservice design

Security : JWT Token based Authentication

JWT Token based authentication is implementated to secure the WebApi services. Identity Microservice acts as a Auth server and issues a valid token after validating the user credentitals. The API Gateway sends the token to the client. The client app uses the token for the subsequent request.

JWT Token based Security

Development Environment

Technologies

  • C#.NET
  • ASP.NET WEB API Core
  • SQL Server

Opensource Tools Used

  • Automapper (For object-to-object mapping)
  • Entity Framework Core (For Data Access)
  • Swashbucke (For API Documentation)
  • XUnit (For Unit test case)
  • Ocelot (For API Gateway Aggregation)

Cloud Platform Services

  • Azure App Insights (For Logging and Monitoring)
  • Azure SQL Database (For Data store)

Database Design

Database Design

WebApi Endpoints

The application has four API endpoints configured in the API Gateway to demonstrate the features with token based security options enabled. These routes are exposed to the client app to cosume the back-end services.

End-points configured and accessible through API Gateway

  1. Route: "/user/authenticate" [HttpPost] - To authenticate user and issue a token
  2. Route: "/account/balance" [HttpGet] - To retrieve account balance.
  3. Route: "/account/deposit" [HttpPost] - To deposit amount in an account.
  4. Route: "/account/withdraw" [HttpPost] - To withdraw amount from an account.

End-points implemented at the Microservice level

  1. Route: "/api/user/authenticate" [HttpPost]- To authenticate user and issue a token
  2. Route: "/api/account/balance" [HttpGet]- To retrieve account balance.
  3. Route: "/api/account/deposit" [HttpPost]- To deposit amount in an account.
  4. Route: "/api/account/withdraw" [HttpPost]- To withdraw amount from an account.

Solution Structure

Solution Structure

  • Identity.WebApi
    • Handles the authentication part using username, password as input parameter and issues a JWT Bearer token with Claims-Identity info in it.
  • Transaction.WebApi
    • Supports three http methods 'Balance', 'Deposit' and 'Withdraw'. Receives http request for these methods.
    • Handles exception through a middleware
    • Reads Identity information from the Authorization Header which contains the Bearer token
    • Calls the appropriate function in the 'Transaction' framework
    • Returns the transaction response result back to the client
  • Transaction.Framework
    • Defines the interface for the repository (data) layer and service (business) layer
    • Defines the domain model (Business Objects) and Entity Model (Data Model)
    • Defines the business exceptions and domain model validation
    • Defines the required data types for the framework 'Struct', 'Enum', 'Consants'
    • Implements the business logic to perform the required account transactions
    • Implements the data logic to read and update the data from and to the SQL database
    • Performs the task of mapping the domain model to entity model and vice versa
    • Handles the db update concurrency conflict
    • Registers the Interfaces and its Implementation in to Service Collection through dependency injection
  • Gateway.WebApi
    • Validates the incoming Http request by checking for authorized JWT token in it.
    • Reroute the Http request to a downstream service.
  • SimpleBanking.ConsoleApp
    • A console client app that connects to Api Gateway, can be used to login with username, password and perform transactions like 'Balance', 'Deposit' and 'Withdraw' against a account.

Exception Handling

A Middleware is written to handle the exceptions and it is registered in the startup to run as part of http request. Every http request, passes through this exception handling middleware and then executes the Web API controller action method.

  • If the action method is successfull then the success response is send back to the client.
  • If any exception is thrown by the action method, then the exception is caught and handled by the Middleware and appropriate response is sent back to the client.

Exception Handler Middleware

public async Task InvokeAsync(HttpContext context, RequestDelegate next)
{
    try
    {
        await next(context);
    }
    catch (Exception ex)
    {
        var message = CreateMessage(context, ex);
        _logger.LogError(message, ex);

        await HandleExceptionAsync(context, ex);
    }
}

Db Concurrency Handling

Db concurrency is related to a conflict when multiple transactions trying to update the same data in the database at the same time. In the below diagram, if you see that Transaction 1 and Transaction 2 are against the same account, one trying to deposit amount into account and the other system tring to Withdraw amount from the account at the same time. The framework contains two logical layers, one handles the Business Logic and the other handles the Data logic.

Db Concurrency Update Exception

When a data is read from the DB and when business logic is applied to the data, at this context, there will be three different states for the values relating to the same record.

  • Database values are the values currently stored in the database.
  • Original values are the values that were originally retrieved from the database
  • Current values are the new values that application attempting to write to the database.

The state of the values in each of the transaction produces a conflict when the system attempts to save the changes and identifies using the concurrency token that the values being updated to the database are not the Original values that was read from the database and it throws DbUpdateConcurrencyException.

Reference: docs.microsoft.com

The general approach to handle the concurrency conflict is:

  1. Catch DbUpdateConcurrencyException during SaveChanges
  2. Use DbUpdateConcurrencyException.Entries to prepare a new set of changes for the affected entities.
  3. Refresh the original values of the concurrency token to reflect the current values in the database.
  4. Retry the process until no conflicts occur.
while (!isSaved)
{
    try
    {
        await _dbContext.SaveChangesAsync();
        isSaved = true;
    }
    catch (DbUpdateConcurrencyException ex)
    {
        foreach (var entry in ex.Entries)
        {
            if (entry.Entity is AccountSummaryEntity)
            {
                var databaseValues = entry.GetDatabaseValues();

                if (databaseValues != null)
                {
                    entry.OriginalValues.SetValues(databaseValues);
                    CalculateNewBalance();

                    void CalculateNewBalance()
                    {
                        var balance = (decimal)entry.OriginalValues["Balance"];
                        var amount = accountTransactionEntity.Amount;

                        if (accountTransactionEntity.TransactionType == TransactionType.Deposit.ToString())
                        {
                            accountSummaryEntity.Balance =
                            balance += amount;
                        }
                        else if (accountTransactionEntity.TransactionType == TransactionType.Withdrawal.ToString())
                        {
                            if(amount > balance)
                                throw new InsufficientBalanceException();

                            accountSummaryEntity.Balance =
                            balance -= amount;
                        }
                    }
                }
                else
                {
                    throw new NotSupportedException();
                }
            }
        }
    }
}  

Azure AppInsights: Logging and Monitoring

Azure AppInsights integrated into the "Transaction Microservice" for collecting the application Telemetry.

public void ConfigureServices(IServiceCollection services)
{           
   services.AddApplicationInsightsTelemetry(Configuration);           
}

AppInsights SDK for Asp.Net Core provides an extension method AddApplicationInsights on ILoggerFactory to configure logging. All transactions related to Deposit and Withdraw are logged through ILogger into AppInsights logs.

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
{
   log.AddApplicationInsights(app.ApplicationServices, LogLevel.Information);     
}

To use AppInsights, you need to have a Azure account and create a AppInsights instance in the Azure Portal for your application, that will give you an instrumentation key which should be configured in the appsettings.json

"ApplicationInsights": {
   "InstrumentationKey": "<Your Instrumentation Key>"
 },

Swagger: API Documentation

Swashbuckle Nuget package added to the "Transaction Microservice" and Swagger Middleware configured in the startup.cs for API documentation. when running the WebApi service, the swagger UI can be accessed through the swagger endpoint "/swagger".

public void ConfigureServices(IServiceCollection services)
{            
     services.AddSwaggerGen(c => {
        c.SwaggerDoc("v1", new Info { Title = "Simple Transaction Processing", Version = "v1" });
     });
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory log)
{           
     app.UseSwagger();
     app.UseSwaggerUI(c => {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "Simple Transaction Processing v1");
     });           
}

Swagger API Doc


Postman Collection

Download the postman collection from here to run the api endpoints through gateway

Postman

How to run the application

  1. Download the Sql script from here,
  2. Run the scirpt against SQL server to create the necessary tables and sample data
  3. Open the solution (.sln) in Visual Studio 2017 or later version
  4. Configure the SQL connection string in Transaction.WebApi -> Appsettings.json file
  5. Configure the AppInsights Instrumentation Key in Transaction.WebApi -> Appsettings.json file. If you dont have a key or don't require logs then comment the AppInsight related code in Startup.cs file
  6. Check the Identity.WebApi -> UserService.cs file for Identity info. User details are hard coded for few accounts in Identity service which can be used to run the app. Same details shown in the below table.
  7. Run the following projects in the solution
    • Identity.WebApi
    • Transaction.WebApi
    • Gateway.WebApi
    • SimpleBanking.ConsoleApp
  8. Gateway host and port should be configured correctly in the ConsoleApp
  9. Idenity and Transaction service host and port should be configured correctly in the gateway -> configuration.json
  • Sample data to test
Account NumberCurrencyUsernamePassword
3628101EURspetertest@123
3637897EURgwoodhousepass@123
3648755EURjsmithadmin@123

Console App - Gateway Client

Console App

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

John-ph
Technical Lead
India India
Experienced Software Developer with a demonstrated history of working in the software industry. Skilled in Microsoft .Net technology, Cloud computing, Solution Design, Software Architecture, Enterprise integration, Service Oriented and Microservices based Application Development. Currently, focusing on .Net Core, Web API, Microservices, Azure

Comments and Discussions

 
Generalvery nice article Pin
Alireza_13625-Jul-20 17:44
MemberAlireza_13625-Jul-20 17:44 
QuestionLink is not working. Pin
Shamseer Engineer23-Nov-19 20:42
professionalShamseer Engineer23-Nov-19 20:42 
Questionuse this link Pin
SATHISHKUMAR KARUNAKARAN15-Jul-19 23:29
MemberSATHISHKUMAR KARUNAKARAN15-Jul-19 23:29 
Questionunable to download the example Pin
Member 37494009-Jun-19 16:28
MemberMember 37494009-Jun-19 16:28 
QuestionDonwload Error Pin
Bhuvanesh Mohankumar16-May-19 5:17
MemberBhuvanesh Mohankumar16-May-19 5:17 
AnswerRe: Donwload Error Pin
John-ph20-May-19 4:12
MemberJohn-ph20-May-19 4:12 
QuestionDownload link not working Pin
Kotha Ramesh Babu23-Apr-19 6:44
MemberKotha Ramesh Babu23-Apr-19 6:44 
AnswerRe: Download link not working Pin
John-ph20-May-19 4:12
MemberJohn-ph20-May-19 4:12 
QuestionNeed Help Executing the App Pin
Kaps_10-Apr-19 10:43
MemberKaps_10-Apr-19 10:43 
AnswerRe: Need Help Executing the App Pin
John-ph20-May-19 4:16
MemberJohn-ph20-May-19 4:16 
QuestionSource code not accessible Pin
kumaraguruever1928-Mar-19 7:58
Memberkumaraguruever1928-Mar-19 7:58 
AnswerRe: Source code not accessible Pin
John-ph20-May-19 4:13
MemberJohn-ph20-May-19 4:13 
QuestionModelMappingProfile in Transaction.WebApi project Pin
Mustafa Kok24-Mar-19 23:24
professionalMustafa Kok24-Mar-19 23:24 
AnswerRe: ModelMappingProfile in Transaction.WebApi project Pin
John-ph24-May-19 21:14
MemberJohn-ph24-May-19 21:14 
SuggestionNice article - but why not use ServiceFabric? Pin
Member 1411016222-Mar-19 1:47
MemberMember 1411016222-Mar-19 1:47 
GeneralRe: Nice article - but why not use ServiceFabric? Pin
John-ph20-May-19 4:17
MemberJohn-ph20-May-19 4:17 
QuestionDownload link is not working Pin
sudarsan dash22-Feb-19 0:21
Membersudarsan dash22-Feb-19 0:21 
AnswerRe: Download link is not working Pin
maxoptimus22-Mar-19 2:22
Membermaxoptimus22-Mar-19 2:22 
QuestionNice article. Pin
Bao Tran 198214-Feb-19 15:28
professionalBao Tran 198214-Feb-19 15:28 
AnswerRe: Nice article. Pin
John-ph14-Feb-19 18:41
MemberJohn-ph14-Feb-19 18:41 
GeneralRe: Nice article. Pin
Bao Tran 198216-Feb-19 22:35
professionalBao Tran 198216-Feb-19 22:35 
QuestionGithub to evolve the application? Pin
Marcelo Mohr Maciel14-Feb-19 8:30
MemberMarcelo Mohr Maciel14-Feb-19 8:30 
AnswerRe: Github to evolve the application? Pin
John-ph14-Feb-19 17:47
MemberJohn-ph14-Feb-19 17:47 
QuestionPlease dont use automapper!! Pin
Paolo Vigori13-Feb-19 8:56
MemberPaolo Vigori13-Feb-19 8:56 
QuestionRe: Please dont use automapper!! Pin
John-ph14-Feb-19 20:10
MemberJohn-ph14-Feb-19 20:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Article
Posted 21 Mar 2019

Stats

54.6K views
200 downloads
109 bookmarked