EDITION v2.1.03

DOWNLOAD available at: https://aka.ms/microservicesebook

PUBLISHED BY

Microsoft Developer Division, .NET and Visual Studio product teams

A division of Microsoft Corporation

One Microsoft Way

Redmond, Washington 98052-6399

Copyright © 2018 by Microsoft Corporation

All rights reserved. No part of the contents of this book may be reproduced or transmitted in any form or by any means without the written permission of the publisher.

This book is provided “as-is” and expresses the author’s views and opinions. The views, opinions and information expressed in this book, including URL and other Internet website references, may change without notice.

Some examples depicted herein are provided for illustration only and are fictitious. No real association or connection is intended or should be inferred.

Microsoft and the trademarks listed at http://www.microsoft.com on the “Trademarks” webpage are trademarks of the Microsoft group of companies.

Mac and macOS are trademarks of Apple Inc.

The Docker whale logo is a registered trademark of Docker, Inc. Used by permission.

ImageAll other marks and logos are property of their respective owners.

 

 

Contents

Introduction

About this guide

Version

What this guide does not cover

Additional resources

Who should use this guide

How to use this guide

Related microservice and container-based reference application: eShopOnContainers

Send us your feedback!

Introduction to Containers and Docker

What is Docker?

Comparing Docker containers with virtual machines

A simple analogy

Docker terminology

Docker containers, images, and registries

Choosing Between .NET Core and .NET Framework for Docker Containers

General guidance

Additional resources

When to choose .NET Core for Docker containers

Developing and deploying cross platform

Using containers for new (“green-field”) projects

Creating and deploying microservices on containers

Deploying high density in scalable systems

When to choose .NET Framework for Docker containers

Migrating existing applications directly to a Windows Server container

Using third-party .NET libraries or NuGet packages not available for .NET Core

Using .NET technologies not available for .NET Core

Using a platform or API that does not support .NET Core

Additional resources

Decision table: .NET frameworks to use for Docker

What OS to target with .NET containers

Official .NET Docker images

.NET Core and Docker image optimizations for development versus production

During development and build

In production

Architecting container and microservice-based applications

Container design principles

Containerizing monolithic applications

Deploying a monolithic application as a container

Publishing a single-container-based application to Azure App Service

State and data in Docker applications

Service-oriented architecture

Microservices architecture

Additional resources

Data sovereignty per microservice

The relationship between microservices and the Bounded Context pattern

Additional resources

Logical architecture versus physical architecture

Challenges and solutions for distributed data management

Challenge #1: How to define the boundaries of each microservice

Challenge #2: How to create queries that retrieve data from several microservices

Challenge #3: How to achieve consistency across multiple microservices

Challenge #4: How to design communication across microservice boundaries

Additional resources

Identify domain-model boundaries for each microservice

The API gateway pattern versus the Direct client-to-microservice communication

Direct client-to-microservice communication

Why consider API Gateways instead of direct client-to-microservice communication

What is the API Gateway pattern?

Main features in the API Gateway pattern

Using products with API Gateway features

Azure API Management

Ocelot

Drawbacks of the API Gateway pattern

Additional resources

Communication in a microservice architecture

Communication types

Asynchronous microservice integration enforces microservice’s autonomy

Communication styles

Request/response communication with HTTP and REST

Additional resources

Push and real-time communication based on HTTP

Asynchronous message-based communication

Single-receiver message-based communication

Multiple-receivers message-based communication

Asynchronous event-driven communication

A note about messaging technologies for production systems

Resiliently publishing to the event bus

Additional resources

Creating, evolving, and versioning microservice APIs and contracts

Additional resources

Microservices addressability and the service registry

Additional resources

Creating composite UI based on microservices

Additional resources

Resiliency and high availability in microservices

Health management and diagnostics in microservices

Health checks

Using diagnostics and logs event streams

Orchestrators managing health and diagnostics information

Additional resources

Orchestrating microservices and multi-container applications for high scalability and availability

Software platforms for container clustering, orchestration, and scheduling

Using container-based orchestrators in Microsoft Azure

Using Azure Kubernetes Service

Development environment for Kubernetes

Getting started with Azure Kubernetes Service (AKS)

Deploying with Helm charts into Kubernetes clusters

Use Azure Dev Spaces for your Kubernetes application lifecycle

Additional resources

Using Azure Service Fabric

Service Fabric and containers

Stateless versus stateful microservices

Using Azure Service Fabric Mesh

Choosing orchestrators in Azure

Development Process for Docker-Based Applications

Development environment for Docker apps

Development tool choices: IDE or editor

Additional resources

.NET languages and frameworks for Docker containers

Development workflow for Docker apps

Workflow for developing Docker container-based applications

Step 1. Start coding and create your initial application or service baseline

Set up your local environment with Visual Studio

Additional resources

Step 2. Create a Dockerfile related to an existing .NET base image

Using an existing official .NET Docker image

Additional resources

Using multi-arch image repositories

Multi-stage builds in Dockerfile

Creating your base image from scratch

Additional resources

Step 3. Create your custom Docker images and embed your application or service in them

Creating Docker images with Visual Studio

Step 4. Define your services in docker-compose.yml when building a multi-container Docker application

Working with docker-compose.yml in Visual Studio 2017

Step 5. Build and run your Docker application

Option A: Running a single-container application

Option B: Running a multi-container application

Additional resources

A note about testing and deploying with orchestrators

Step 6. Test your Docker application using your local Docker host

Testing and debugging containers with Visual Studio 2017

Testing and debugging without Visual Studio

Additional resources

Simplified workflow when developing containers with Visual Studio

Additional resources

Using PowerShell commands in a Dockerfile to set up Windows Containers

Additional resources

Designing and Developing Multi-Container and Microservice-Based .NET Applications

Designing a microservice-oriented application

Application specifications

Development team context

Choosing an architecture

eShopOnContainers: A reference application for .NET Core and microservices deployed using containers

Data sovereignty per microservice

Additional resources

Benefits of a microservice-based solution

Downsides of a microservice-based solution

External versus internal architecture and design patterns

The new world: multiple architectural patterns and polyglot microservices

Creating a simple data-driven CRUD microservice

Designing a simple CRUD microservice

Implementing a simple CRUD microservice with ASP.NET Core

Implementing CRUD Web API services with Entity Framework Core

Additional resources

The DB connection string and environment variables used by Docker containers

Implementing versioning in ASP.NET Web APIs

Additional resources

Generating Swagger description metadata from your ASP.NET Core Web API

Why use Swagger?

How to automate API Swagger metadata generation with the Swashbuckle NuGet package

Additional resources

Defining your multi-container application with docker-compose.yml

A simple Web Service API container

Using docker-compose files to target multiple environments

Using multiple docker-compose files to handle several environments

Building optimized ASP.NET Core Docker images

Using a database server running as a container

SQL Server running as a container with a microservice-related database

Seeding with test data on Web application startup

EF Core InMemory database versus SQL Server running as a container

Using a Redis cache service running in a container

Implementing event-based communication between microservices (integration events)

Using message brokers and services buses for production systems

Integration events

The event bus

Observer pattern

Publish/Subscribe (Pub/Sub) pattern

The middleman or event bus

Defining an event bus interface

Implementing an event bus with RabbitMQ for the development or test environment

Implementing a simple publish method with RabbitMQ

Implementing the subscription code with the RabbitMQ API

Subscribing to events

Publishing events through the event bus

Designing atomicity and resiliency when publishing to the event bus

Implementing atomicity when publishing integration events through the event bus

Receiving messages from subscriptions: event handlers in receiver microservices

Idempotency in update message events

Additional resources

Deduplicating integration event messages

Deduplicating message events at the EventHandler level

Deduplicating messages when using RabbitMQ

Additional resources

Testing ASP.NET Core services and web apps

Implementing unit tests for ASP.NET Core Web APIs

Implementing integration and functional tests for each microservice

Implementing service tests on a multi-container application

Testing in eShopOnContainers

Additionl resources

Implement background tasks in microservices with IHostedService and the BackgroundService class

Registering hosted services in your WebHost or Host

The IHostedService interface

Implementing IHostedService with a custom hosted service class deriving from the BackgroundService base class

Summary class diagram

Deployment considerations and takeaways

Implement API Gateways with Ocelot

Architect and design your API Gateways

Sample microservices/containers to re-route through the API Gateways

Implementing your API Gateways with Ocelot

Using a single Docker container image to run multiple different API Gateway / BFF container types

The Gateway aggregation pattern in eShopOnContainers

Authentication and authorization in Ocelot API Gateways

Using Kubernetes Ingress plus Ocelot API Gateways

Additional cross-cutting features in an Ocelot API Gateway

Tackle Business Complexity in a Microservice with DDD and CQRS Patterns

Apply simplified CQRS and DDD patterns in a microservice

Apply CQRS and CQS approaches in a DDD microservice in eShopOnContainers

CQRS and DDD patterns are not top-level architectures

Implement reads/queries in a CQRS microservice

Use ViewModels specifically made for client apps, independent from domain model constraints

Use Dapper as a micro ORM to perform queries

Dynamic versus static ViewModels

ViewModel as dynamic type

ViewModel as predefined DTO classes

Additional resources

Design a DDD-oriented microservice

Keep the microservice context boundaries relatively small

Layers in DDD microservices

The domain model layer

The application layer

The infrastructure layer

Design a microservice domain model

The Domain Entity pattern

Rich domain model versus anemic domain model

The Value Object pattern

The Aggregate pattern

The Aggregate Root or Root Entity pattern

Implement a microservice domain model with .NET Core

Domain model structure in a custom .NET Standard Library

Structure aggregates in a custom .NET Standard library

Implement domain entities as POCO classes

Encapsulate data in the Domain Entities

Map properties with only get accessors to the fields in the database table

Map fields without properties

Additional resources

Seedwork (reusable base classes and interfaces for your domain model)

The custom Entity base class

Repository contracts (interfaces) in the domain model layer

Additional resources

Implement value objects

Important characteristics of value objects

Value object implementation in C#

How to persist value objects in the database with EF Core 2.0

Background and older approaches using EF Core 1.1

Persist value objects as owned entity types in EF Core 2.0

Additional details on owned entity types

Additional resources

Use enumeration classes instead of enum types

Implement an Enumeration base class

Additional resources

Design validations in the domain model layer

Implement validations in the domain model layer

Validate conditions and throw exceptions

Use validation attributes in the model based on data annotations

Validate entities by implementing the Specification pattern and the Notification pattern

Use deferred validation in the domain

Two-step validation

Additional resources

Client-side validation (validation in the presentation layers)

Additional resources

Validation in Xamarin mobile apps

Validation in ASP.NET Core apps

Validation in SPA Web apps (Angular 2, TypeScript, JavaScript)

Domain events: design and implementation

What is a domain event?

Domain events versus integration events

Domain events as a preferred way to trigger side effects across multiple aggregates within the same domain

Implement domain events

Raise domain events

Single transaction across aggregates versus eventual consistency across aggregates

The domain event dispatcher: mapping from events to event handlers

How to subscribe to domain events

How to handle domain events

Conclusions on domain events

Additional resources

Design the infrastructure persistence layer

The Repository pattern

Define one repository per aggregate

Enforce one aggregate root per repository

The Repository pattern makes it easier to test your application logic

The difference between the Repository pattern and the legacy Data Access class (DAL class) pattern

Repositories shouldn’t be mandatory

Additional resources

Repository pattern

Unit of Work pattern

Implement the infrastructure persistence layer with Entity Framework Core

Introduction to Entity Framework Core

Infrastructure in Entity Framework Core from a DDD perspective

Implement custom repositories with Entity Framework Core

Methods to implement in a repository (updates or transactions versus queries)

Using a custom repository versus using EF DbContext directly

EF DbContext and IUnitOfWork instance lifetime in your IoC container

The repository instance lifetime in your IoC container

Table mapping

Data Annotations versus Fluent API

Fluent API and the OnModelCreating method

The Hi/Lo algorithm in EF Core

Map fields instead of properties

Use shadow properties in EF Core, hidden at the infrastructure level

Implement the Query Specification pattern

Use NoSQL databases as a persistence infrastructure

Introduction to Azure Cosmos DB and the native Cosmos DB API

Implement .NET code targeting MongoDB and Azure Cosmos DB

Use Azure Cosmos DB from .NET containers

Use MongoDB API for local dev/test Linux/Windows containers plus Azure Cosmos DB

Analyze your approach for production applications: MongoDB API vs. Cosmos DB API

The code: Use MongoDB API in .NET Core applications

Design the microservice application layer and Web API

Use SOLID principles and Dependency Injection

Implement the microservice application layer using the Web API

Use Dependency Injection to inject infrastructure objects into your application layer

Register the dependency implementation types and interfaces or abstractions

Implement the Command and Command Handler patterns

The command class

The Command Handler class

The Command process pipeline: how to trigger a command handler

Use the Mediator pattern (in-memory) in the command pipeline

Use message queues (out-of-proc) in the command’s pipeline

Implement the command process pipeline with a mediator pattern (MediatR)

Implement idempotent Commands

Register the types used by MediatR

Apply cross-cutting concerns when processing commands with the Behaviors in MediatR

Implement Resilient Applications

Handle partial failure

Strategies to handle partial failure

Additional resources

Implement retries with exponential backoff

Implement resilient Entity Framework Core SQL connections

Execution strategies and explicit transactions using BeginTransaction and multiple DbContexts

Additional resources

Explore custom HTTP call retries with exponential backoff

Use HttpClientFactory to implement resilient HTTP requests

Issues with the original HttpClient class available in .NET Core

What is HttpClientFactory

Multiple ways to use HttpClientFactory

How to use Typed Clients with HttpClientFactory

HttpClient lifetimes

Implement your Typed Client classes that use the injected and configured HttpClient

Use your Typed Client classes

Additional resources

Implement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies

Add a jitter strategy to the retry policy

Additional resources

Implement the Circuit Breaker pattern

Implement Circuit Breaker pattern with HttpClientFactory and Polly

Test Http retries and circuit breakers in eShopOnContainers

Test the circuit breaker in eShopOnContainers

Additional resources

Health monitoring

Implement health checks in ASP.NET Core services

Use the HealthChecks library in your back-end ASP.NET microservices

Cache health check responses

Query your microservices to report about their health status

Use watchdogs

Health checks when using orchestrators

Advanced monitoring: visualization, analysis, and alerts

Additional resources

Make secure .NET Microservices and Web Applications

Implement authentication in .NET microservices and web applications

Authenticate with ASP.NET Core Identity

Authenticate with external providers

Authenticate with bearer tokens

Authenticate with an OpenID Connect or OAuth 2.0 Identity provider

Issue security tokens from an ASP.NET Core service

Consume security tokens

Additional resources

About authorization in .NET microservices and web applications

Implement role-based authorization

Implement policy-based authorization

Additional resources

Store application secrets safely during development

Store secrets in environment variables

Store secrets with the ASP.NET Core Secret Manager

Use Azure Key Vault to protect secrets at production time

Additional resources

Key Takeaways