The ideal method for creating cloud-native, scalable, and maintainable systems is microservices architecture. Microservices are not the initial state of the majority of real-world systems, though. They begin as monolithic programs that run crucial business logic and were frequently created years ago.

It's a frequent misperception that implementing microservices necessitates a total overhaul. Rewriting a monolith from scratch is actually costly, hazardous, and rarely successful.
This article describes how to use the Strangler Fig Pattern, a secure and tried-and-true migration technique, to create microservices within an existing monolith in .NET Core.

What Is a Monolithic Application?
A monolith is an application where:

  • All features live in a single codebase
  • Components are tightly coupled
  • Deployment happens as one unit

Challenges of a Monolith

  • Slow deployments
  • Difficult scaling
  • High risk when changing code
  • Hard to adopt new technologies

Despite these challenges, monoliths are not “bad”. They are often stable and business-critical, which is why careful evolution is needed.

Why Not Rewrite Everything as Microservices?

A full rewrite introduces:

  • Business downtime
  • Loss of domain knowledge
  • New bugs and regressions
  • Long time-to-market

Instead of replacing the monolith, a gradual migration is the safest approach.

What Does “Microservices via Monolith” Mean?

“Microservices via Monolith” means:

  • Keeping the existing monolith alive
  • Gradually extracting features into microservices
  • Letting both systems coexist during the transition

This approach allows teams to:

  • Reduce risk
  • Deliver value incrementally
  • Learn microservices without breaking production

The Strangler Fig Pattern
The Strangler Fig Pattern is a migration strategy where:

  • New features are built as microservices
  • Existing functionality is slowly moved out
  • The monolith eventually becomes obsolete

Named after the strangler fig tree, which grows around an existing tree until it replaces it.

High-Level Architecture

Client
  |
API Gateway / Reverse Proxy
  |
----------------------------
|          |               |
Monolith  Microservice A  Microservice B

Step-by-Step Migration in .NET Core
Step 1: Modularize the Monolith

Before extracting services, clean up the monolith:

  • Separate business logic from controllers
  • Use layered architecture (API, Application, Domain, Infrastructure)
  • Identify bounded contexts

Tip: If your monolith is already in ASP.NET Core, you are halfway there.

Step 2: Identify a Candidate Microservice

Good candidates:

  • Low coupling with other modules
  • Clear business boundaries
  • High change frequency

Examples:

  • Authentication
  • Notifications
  • Reporting
  • Payments

Step 3: Create a New ASP.NET Core Microservice
Create a new project:
dotnet new webapi -n NotificationService

This service should:

  • Own its database
  • Expose REST APIs
  • Be independently deployable


Step 4: Route Traffic Using an API Gateway
Use tools like:

  • YARP (Yet Another Reverse Proxy)
  • Ocelot
  • Azure API Management

Example with YARP:
    /api/notifications → Microservice
    /api/orders → Monolith


This makes the migration invisible to clients.

Step 5: Data Management Strategy

Avoid sharing databases.

Common approaches:

  • Database per service
  • Data synchronization via events
  • Read replicas for legacy data

Never let microservices directly access the monolith database.

Step 6: Communication Between Monolith and Microservices
Preferred methods:

  • REST APIs
  • Asynchronous messaging (RabbitMQ, Azure Service Bus)

Example:

  • Monolith publishes OrderCreated event
  • Microservice listens and processes it

Example: Extracting Notification Service

Before (Monolith)

public class OrderService
{
    public void CreateOrder()
    {
        // Order logic
        SendEmail();
    }
}


After (Microservice)
// Monolith
PublishEvent(new OrderCreatedEvent());

// Notification Microservice
public class OrderCreatedHandler
{
    public Task Handle(OrderCreatedEvent evt)
    {
        SendEmail();
    }
}


Result:

  • Loose coupling
  • Independent scaling
  • Faster deployments

Benefits of Microservices via Monolith
✔ Lower migration risk
✔ Continuous delivery
✔ Independent scaling
✔ Better maintainability
✔ Cloud readiness

Common Mistakes to Avoid
❌ Extracting too many services at once
❌ Sharing databases
❌ Overusing synchronous calls
❌ Ignoring observability (logs, metrics, tracing)

Tools Commonly Used in .NET Core Microservices

  • ASP.NET Core
  • Docker
  • Kubernetes
  • YARP / Ocelot
  • Serilog
  • OpenTelemetry
  • RabbitMQ / Azure Service Bus

When Should You Stop?
The migration ends when:

  • The monolith no longer handles business logic
  • Remaining code is minimal or retired
  • All core features live in microservices
  • At this point, the monolith can be safely decommissioned.

Conclusion
Migrating from a monolith to microservices does not require a risky rewrite. By using the Microservices via Monolith approach with .NET Core and the Strangler Fig Pattern, teams can modernize their applications safely, incrementally, and confidently.

This strategy is battle-tested, production-friendly, and ideal for organizations that want the benefits of microservices without the pain of starting over.