If you're building a .NET application, chances are high that you'll need to call an external API over HTTP. The easy way to make HTTP requests in .NET is to use the HttpClient to send those requests. And it's a great abstraction to work with, especially with the methods supporting JSON payloads and responses. Unfortunately, it's easy to misuse the HttpClient. Port exhaustion and DNS behavior are some of the most common problems. So here's what you need to know about work with HttpClient: - Ho...| www.milanjovanovic.tech
Delegating handlers are like ASP.NET Core middleware. Except they work with the HttpClient. I'll show you how to work with delegating handlers| www.milanjovanovic.tech
In this week's newsletter we will talk about running background tasks in ASP .NET Core. After reading this newsletter, you will be able to set up a background task and have it up and running within minutes. Background tasks are used to offload some work in your application to the background, outside of the normal application flow. A typical example can be asynchronously processing messages from a queue. I will show you how to create a simple background task that runs once and completes. And y...| www.milanjovanovic.tech
Dependency injection (DI) is one of the most exciting features of ASP.NET Core. It helps us build more testable and maintainable applications. However, ASP.NET Core's built-in DI system sometimes needs a little help to achieve more advanced scenarios. So I want to introduce you to a powerful library for enhancing your ASP.NET Core DI - Scrutor.| www.milanjovanovic.tech
In this newsletter, we'll be covering three ways to create middleware in ASP.NET Core applications. Middleware allows us to introduce additional logic before or after executing an HTTP request. You are already using many of the built-in middleware available in the framework. I'm going to show you three approaches to how you can define custom middleware: With Request Delegates, By Convention, and Factory-Based.| www.milanjovanovic.tech
The Pragmatic Clean Architecture course will teach you how to build production-ready applications using Clean Architecture, Domain-Driven Design, and CQRS.| www.milanjovanovic.tech
Validation is an essential cross-cutting concern that you need to solve in your application. You want to ensure the request is valid before you consider processing it. Another important question you need to answer is how you approach different types of validation. For example, I consider input and business validation differently, and each deserves a specific solution. I want to show you an elegant solution for validation using MediatR and FluentValidation. If you aren't using CQRS with Mediat...| www.milanjovanovic.tech
Rate limiting is a technique to limit the number of requests to a server or an API. A limit is introduced within a given time period to prevent server overload and protect against abuse. In ASP.NET Core 7 we have a built-in rate limiter middleware, that's easy to integrate into your API. We're going to cover four rate limiting algorithms: - Fixed window - Sliding window - Token bucket - Concurrency Let's see how we can work with rate limiting.| www.milanjovanovic.tech
.NET • ASP.NET Core • Software Architecture| www.milanjovanovic.tech
Software architecture is a blueprint for how you should structure your system. You can follow this blueprint strictly, or you can give yourself varying levels of freedom. But when deadlines are tight, and you start cutting corners, that beautiful software architecture you built crumbles like a house of cards. How can you enforce your software architecture? By writing architecture tests. Architecture tests are automated tests that verify the structure and design of your code. You can use them ...| www.milanjovanovic.tech
.NET Aspire revolutionizes distributed application development by simplifying service discovery through configuration-based approaches that eliminate the complexity of service-to-service communication.| www.milanjovanovic.tech
Build a robust, automated CI/CD pipeline for .NET 9 applications using GitHub Actions and Azure App Service to transform deployments from stressful events into reliable, repeatable processes.| www.milanjovanovic.tech
Every article about modular monoliths tells you to use public APIs between modules, but they rarely explain why these APIs exist or how to design them properly. After building several large-scale modular monoliths, I've learned that public APIs are not just about clean code - they're about controlling chaos.| www.milanjovanovic.tech
The Modular Monolith Architecture course will teach you how to build production-ready applications using Modular Monolith Architecture, Domain-Driven Design, and CQRS.| www.milanjovanovic.tech
Long-running business processes often require multiple services working together, but traditional distributed transactions can be problematic at scale. Learn how to implement the Saga pattern using MassTransit to break complex workflows into manageable steps with proper error handling and state management.| www.milanjovanovic.tech
Not every API request needs to finish right away. Learn how to build better APIs by moving long-running tasks to the background. This guide shows practical examples using image processing in ASP.NET Core 9.| www.milanjovanovic.tech
Transitioning from a modular monolith to microservices can significantly enhance your system's scalability and your team's productivity, but it's a journey that requires careful planning and execution. In this practical guide, I'll walk you through the key steps of this migration process, from preparing your monolith and selecting the right module to extract, to implementing effective inter-service communication and data migration strategies, all based on real-world experience with .NET appli...| www.milanjovanovic.tech
.NET Aspire promises to revolutionize cloud-native development for .NET applications, but does it live up to the hype? In this hands-on review, I'll share my experience migrating a real project to Aspire, exploring its strengths, limitations, and potential impact on how we build distributed systems.| www.milanjovanovic.tech
Service discovery is a pattern that allows developers to use logical names to refer to external services, instead of physical IP addresses and ports. In this week's issue, we'll see how to implement service discovery in your .NET microservices with Consul.| www.milanjovanovic.tech
Caching is one of the simplest techniques to significantly improve your application's performance. In this newsletter, we will explore how to implement caching in ASP.NET Core applications.| www.milanjovanovic.tech
By designing your applications with resilience in mind, you can create robust and reliable systems, even when the going gets tough. In this newsletter, we'll explore the tools and techniques we have in .NET to build resilient systems.| www.milanjovanovic.tech
Distributed systems offer flexibility but introduce complexity, making troubleshooting a headache. Understanding how requests flow through your system is crucial for debugging and performance optimization. OpenTelemetry is an open-source observability framework that makes this possible.| www.milanjovanovic.tech
Modular monoliths blend the simplicity and robustness of traditional monolithic applications with the flexibility and scalability of microservices. Today, I'll introduce you to the modular monolith architecture and why you should know about it.| www.milanjovanovic.tech
Suppose you're building a modular monolith, a type of software architecture where different components are organized into loosely coupled modules. Or you might need to process data asynchronously. You'll need a tool or service that allows you to implement this.| www.milanjovanovic.tech
Modular monoliths are an architectural approach that's becoming very popular. They combine the benefits of modularity and monolithic design. Data isolation ensures that modules are independent and loosely coupled. Today, I will show you four data isolation approaches for modular monoliths| www.milanjovanovic.tech
Exceptions are for exceptional situations. But they will inevitably happen in your applications, and you need to handle them. You can implement a global exception handling mechanism or handle only specific exceptions. ASP.NET Core gives you a few options on how to implement this. So which one should you choose? Today, I want to show you an old and new way to handle exceptions in ASP.NET Core 8.| www.milanjovanovic.tech
Layered architectures are the foundation of many software systems. However, layered architectures organize the system around technical layers. And the cohesion between layers is low. What if you wanted to organize the system around features instead? This is where Vertical Slice Architecture comes in.| www.milanjovanovic.tech
How should you handle errors in your code? This has been a topic of many discussions, and I want to share my opinion. One school of thought suggests using exceptions for flow control. This is not a good approach because it makes the code harder to reason about. The caller must know the implementation details and which exceptions to handle. Exceptions are for exceptional situations. Today, I want to show you how to implement error handling using the Result pattern. It's a functional approach t...| www.milanjovanovic.tech
Today I want to show you how to use the CQRS pattern to build fast and scalable applications. The CQRS pattern separates the writes and reads in the application. This separation can be logical or physical and has many benefits. I'm also going to show you how to implement CQRS in your application using MediatR.| www.milanjovanovic.tech
Modular monoliths are becoming more popular in the software engineering community. The allure of Microservices is becoming less compelling. We also have seasoned veterans of our industry saying you should reconsider: > You shouldn't start a new project with microservices, even if you're sure your application will be big enough to make it worthwhile. — Martin Fowler Modular monoliths give you the logical architecture of Microservices without the operational complexity. You can safely determi...| www.milanjovanovic.tech
Large Microservice-based systems can consist of tens or even hunders of individual services. A client application needs to have all of this information to be able to make requests to the relevant microservice directly. However, this has numerous issues such as security concerns, complexity, and coupling. We can solve this by introducing an API gateway that acts as a reverse proxy to accept API calls from the client application, forwarding this traffic to the appropriate service. The API gatew...| www.milanjovanovic.tech
Today's modern applications must deliver the latest information without refreshing the user interface. If you need to introduce real-time functionality to your application in .NET, there's one library you will most likely reach for - SignalR. SignalR allows you to push content from your server-side code to any connected clients as changes happen in real-time. Here's what I'll teach you in this week's newsletter: - Creating your first SignalR Hub - Testing SignalR from Postman - Creating stron...| www.milanjovanovic.tech
If you're building a scalable application, it's a common requirement to offload some work in your application to a background job. A few examples of that are: - Publishing email notifications - Generating reports - Updating a cache - Image processing How can you create a recurring background job in .NET? Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems. There are three concepts you need to understand in Quar...| www.milanjovanovic.tech
MediatR is a popular library with a simple mediator pattern implementation in .NET. Here's a definiton taken from MediatR's GitHub: "In-process messaging with no dependencies." With the rise in popularity of the CQRS pattern, MediatR became the go-to library to implement commands and queries. However, MediatR also has support for the publish-subscribe pattern using notifications. You can publish an INotification instance and have multiple subscribers handle the published message. Until recent...| www.milanjovanovic.tech
Entity Framework Core (EF Core) is a popular ORM in .NET that allows you to work with SQL databases. EF Core uses a DbContext, which represents a session with the database and is responsible for tracking changes, performing database operations, and managing database connections. It's common to have only one DbContext for the entire application. But what if you need to have multiple DbContexts? In this week's newsletter we're going to explore: - When you may want to use multiple DbContexts - H...| www.milanjovanovic.tech
.NET • ASP.NET Core • Software Architecture| www.milanjovanovic.tech
In this newsletter, we'll break down the essentials of EF Migrations. We'll explore creating migrations, SQL scripts, applying migrations, migration tooling, and more.| www.milanjovanovic.tech
MassTransit is an open-source distributed application framework for .NET. It provides a messaging abstraction on top of the supported message transports. In this week's issue, I'll show you how to use MassTransit.| www.milanjovanovic.tech
EF Core is my favorite ORM for .NET applications. Yet, its many fantastic features sometimes go unnoticed. For example, query splitting, query filters, and interceptors. EF interceptors are interesting because you can do powerful things with them. For example, you can hook into materialization, handle optimistic concurrency errors, or add query hints. The most practical use case is adding behavior when saving changes to the database.| www.milanjovanovic.tech
More than 63%+ of organizations said in a Dzone survey that they are adopting Microservices for some or all of their applications. As more businesses adopt the use of Microservice architectures, we as developers have to become more skilled with Microservices communication. Working with distributed systems is both fun and challenging at the same time. One of those challenges is designing effective communication between services. More centralization or less centralization? More coupling or less...| www.milanjovanovic.tech
In software engineering, "coupling" means how much different parts of a software system depend on each other. If they are tightly coupled, changes to one part can affect many others. But if they are loosely coupled, changes to one part won't cause big problems in the rest of the system. Domain events are a Domain-Driven Design (DDD) tactical pattern that we can use to build loosely coupled systems. You can raise a domain event from the domain, which represents a fact that has occurred. And ot...| www.milanjovanovic.tech
What happens when a message is retried in an event-driven system? It happens more often than you think. The worst case scenario is that the message is processed twice, and the side effects can also be applied more than once. Do you want your bank account to be double charged? I'll assume the answer is no, of course. You can use the Idempotent Consumer pattern to solve this problem. In this week's issue I'll show you: - How the Idempotent Consumer pattern works - How to implement an Idempotent...| www.milanjovanovic.tech
Designing long-lived processes in a distributed environment is an interesting engineering challenge. And a well known pattern for solving this problem is a Saga. A Saga is a sequence of local transactions, where each local transaction updates the Saga state and publishes a message triggering the next step in the Saga. Sagas come in two forms: Orchestrated Choreographed With an orchestrated Saga, there's a central component responsible for orchestrating the individual steps. In a choreographed...| www.milanjovanovic.tech
Working with Microservices, or any distributed system for that matter, is difficult. In a distributed system many things can go wrong, and there are even research papers about this. If you want to explore this topic futher, I suggest that you read about the fallacies of distributed computing. Reducing the surface area for things to go wrong should be one of your goals, as an engineer. In this week's newsletter, we'll try to achieve exactly that using the Outbox pattern. How can you implement ...| www.milanjovanovic.tech
If you're working in a distributed system, you need to be able to communicate between multiple services. There are a few ways that you can implement this. Depending on your chosen approach, you can either introduce tight coupling between your services or stay loosely coupled. Loose coupling is an important quality in a distributed system. It will allow you to evolve your services independently. So how do you implement loosely coupled communication between services? You'll need a messaging sys...| www.milanjovanovic.tech
Every software engineer working with SQL databases needs to know about transactions. And since most of the time the SQL database will be abstracted by an ORM like EF Core, it's important to understand how you can work with transactions using the available abstractions. So today, I'll show you how to work with transactions in EF Core. Here's what we will cover: - Default transaction behavior - Creating transactions - Using existing transactions| www.milanjovanovic.tech
In this week's newsletter, we're going to explore the new ExecuteUpdate and ExecuteDelete methods that were released with EF7. ExecuteUpdate allows us to write a query and run a bulk update operation on the entities matching that query. Similarly, ExecuteDelete allows us to write a query and delete the entities matching that query. We can significantly improve performance using the new methods in some scenarios, and I'm going to show you what those scenarios are.| www.milanjovanovic.tech
In this week's newsletter, I'll show you how you can remove repetitive conditions in EF Core database queries. An example would be when you implement soft-delete, and have to check if a record was soft-deleted or not in every query. Also, it is practical if you're working in a multi-tenant system and need to specify a tenantId on every query. EF Core has a powerful feature called Query Filters that can help you remove repetitive conditions from your code.| www.milanjovanovic.tech
I recently ran into an issue with Entity Framework Core. The query I was running was constantly timing out. So I used a new EF Core feature called Query Splitting to significantly improve my performance.| www.milanjovanovic.tech