Microservices architecture is becoming the go-to solution for enterprises that need to scale efficiently. This architectural style allows applications to be broken down into smaller, independently deployable services that communicate over networks. In this blog, we’ll delve into how to build scalable microservices using .NET Core, showcasing an example and discussing patterns and practices you should incorporate.
In traditional monolithic architecture, all parts of the application are interwoven, making it hard to scale and deploy changes. Microservices, on the other hand, allow different components to be developed, deployed, and scaled independently. This means you can update one part of your application without affecting the rest, resulting in more agility and better resource management.
Key Features of Microservices:
Before we start building our microservices, ensure you have the following installed:
Creating a microservices solution in .NET Core is straightforward. You can use the command line or Visual Studio to create your projects. For our example, we’ll build a simple e-commerce system with two microservices: ProductService
and OrderService
.
Run the following commands to create the solution:
mkdir ECommerceSystem cd ECommerceSystem dotnet new sln dotnet new webapi -n ProductService dotnet new webapi -n OrderService dotnet sln add ProductService/ProductService.csproj dotnet sln add OrderService/OrderService.csproj
In ProductService
, we’ll expose an API to manage products. Here’s a simple Product
model and a controller that allows us to create and retrieve products.
Model: Product.cs
public class Product { public int Id { get; set; } public string Name { get; set; } public decimal Price { get; set; } }
Controller: ProductsController.cs
[ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { private static List<Product> Products = new List<Product>(); [HttpPost] public ActionResult<Product> CreateProduct(Product product) { product.Id = Products.Count + 1; Products.Add(product); return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, product); } [HttpGet("{id}")] public ActionResult<Product> GetProductById(int id) { var product = Products.FirstOrDefault(p => p.Id == id); if (product == null) return NotFound(); return product; } }
For OrderService
, we’ll create an order that references a product.
Model: Order.cs
public class Order { public int Id { get; set; } public int ProductId { get; set; } public int Quantity { get; set; } }
Controller: OrdersController.cs
[ApiController] [Route("api/[controller]")] public class OrdersController : ControllerBase { private static List<Order> Orders = new List<Order>(); [HttpPost] public ActionResult<Order> CreateOrder(Order order) { order.Id = Orders.Count + 1; Orders.Add(order); return CreatedAtAction(nameof(GetOrderById), new { id = order.Id }, order); } [HttpGet("{id}")] public ActionResult<Order> GetOrderById(int id) { var order = Orders.FirstOrDefault(o => o.Id == id); if (order == null) return NotFound(); return order; } }
Microservices often need to communicate with each other. In our case, OrderService
might need to query ProductService
to validate product availability. A common approach is to use HTTP requests, as shown below:
Modified CreateOrder
Method:
[HttpPost] public async Task<ActionResult<Order>> CreateOrder(Order order) { // Validate the product availability var client = new HttpClient(); var response = await client.GetAsync($"http://localhost:5000/api/products/{order.ProductId}"); if (!response.IsSuccessStatusCode) return BadRequest("Product not available."); order.Id = Orders.Count + 1; Orders.Add(order); return CreatedAtAction(nameof(GetOrderById), new { id = order.Id }, order); }
To make our services portable and scalable, we can containerize them using Docker. Create a Dockerfile
in both ProductService
and OrderService
.
Sample Dockerfile:
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base WORKDIR /app EXPOSE 80 FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build WORKDIR /src COPY ["ProductService/ProductService.csproj", "ProductService/"] RUN dotnet restore "ProductService/ProductService.csproj" COPY . . WORKDIR "/src/ProductService" RUN dotnet build "ProductService.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "ProductService.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY /app/publish . ENTRYPOINT ["dotnet", "ProductService.dll"]
You can build both services and run them using Docker Compose for orchestration.
ProductService
and OrderService
require a database, each should manage its own.By adhering to these best practices, your microservices architecture will be both scalable and maintainable, allowing you to respond to changes in business requirements with speed and efficiency.
09/10/2024 | DotNet
19/09/2024 | DotNet
12/10/2024 | DotNet
09/10/2024 | DotNet
09/10/2024 | DotNet
19/09/2024 | DotNet
19/09/2024 | DotNet
19/09/2024 | DotNet
09/10/2024 | DotNet
12/10/2024 | DotNet