CQRS and MediatR: Organize Your Code Like a Pro with LINQPad

If you’ve ever wondered how to keep your C# projects organized as they grow, you’re not alone. One of the best ways to experiment with new architectural patterns is with LINQPad. LINQPad makes it easy to learn, test, and understand concepts like CQRS and MediatR—without the hassle of setting up a full project. It’s my go-to tool for quickly prototyping and exploring code, and it’s perfect for anyone looking to level up their .NET skills.

What is CQRS?

CQRS stands for Command Query Responsibility Segregation. It’s a pattern that helps you separate the code that reads data (queries) from the code that changes data (commands). This separation can make your codebase easier to understand and maintain, especially as your application grows.

But let’s skip the buzzwords and focus on what matters: CQRS is simply a way to organize your code. It’s not magic, and you don’t need to memorize jargon to use it effectively.

MediatR: The Organized Kitchen Manager

MediatR is a popular .NET library that helps you implement CQRS. Think of MediatR as the world’s most organized kitchen manager. It knows what the kitchen (your app) can do, and it handles requests from the staff (your code) like “what’s on the menu?” or “make this cheeseburger.”

With MediatR, you define operations using IRequest (the contract for what can be done) and handle them with IRequestHandler (the implementation). For example, a query to get all tweets is an IRequest, and the code that fetches those tweets is the IRequestHandler. Remember, IRequest tells MediatR that something can be done and IRequestHandler tells MediatR how to do it.

MediatR also supports notifications using INotification and INotificationHandler. This is like a pub/sub system: when something happens (like a new tweet is posted), you can notify other parts of your app to react.

Why Use LINQPad for CQRS and MediatR?

LINQPad is the fastest way to try out CQRS and MediatR. You can write, run, and tweak your code in seconds. It’s perfect for learning, testing, and understanding how these patterns work—before you commit to using them in a big project.

Download LINQPad Today

Get started with the most powerful .NET Rapid Progress Tool (RPT) available.

Get LINQPad Premium

Powerful .NET acceleration. Code at the speed of thought.

Example: CQRS and MediatR in Action

Here’s how you can use LINQPad to explore CQRS and MediatR in a real-world scenario. We’ll break down the example into three parts: querying tweets, inserting a new tweet, and handling notifications. Each part is easy to run and modify in LINQPad, making it perfect for learning and experimentation.

1. Query: Get All Tweets

This code defines a query to fetch all tweets. In CQRS, queries are used to read data. MediatR makes it simple to organize these operations, and LINQPad lets you test them instantly.

public class TweetsGetAllQuery : IRequest<List<Tweet>> { }

public class TweetsGetAllQueryHandler : IRequestHandler<TweetsGetAllQuery, List<Tweet>>
{
	private readonly List<Tweet> _tweets;

	public TweetsGetAllQueryHandler(List<Tweet> tweets)
	{
		_tweets = tweets;
	}

	public Task<List<Tweet>> Handle(TweetsGetAllQuery request, CancellationToken cancellationToken)
	{
		return Task.FromResult(_tweets);
	}
}

2. Command: Insert a New Tweet

Commands in CQRS are used to change data. Here, we define a command to create a new tweet and a handler that adds it to the list. This is a great way to see how MediatR separates write operations, and LINQPad makes it easy to experiment with these patterns.

public class TweetCreateCommand : IRequest<Tweet>
{
	public string Content { get; set; }
	public string Username { get; set; }
}

public class TweetCreateCommandHandler : IRequestHandler<TweetCreateCommand, Tweet>
{
	private readonly List<Tweet> _tweets;
	private readonly IMediator _mediator;

	public TweetCreateCommandHandler(List<Tweet> tweets, IMediator mediator)
	{
		_tweets = tweets;
		_mediator = mediator;
	}

	public async Task<Tweet> Handle(TweetCreateCommand request, CancellationToken cancellationToken)
	{
		var newTweet = new Tweet
		{
			Id = _tweets.Count + 1,
			Content = request.Content,
			Username = request.Username,
			PostedAt = DateTime.UtcNow
		};
		_tweets.Add(newTweet);
		await _mediator.Publish(new TweetPostedNotification { Content = newTweet.Content, Username = newTweet.Username }, cancellationToken);
		return newTweet;
	}
}

3. Notification: Publish When a Tweet is Posted

Notifications in MediatR allow you to broadcast events to multiple handlers. This is useful for things like logging, sending emails, or updating other parts of your system. LINQPad lets you see these notifications in action right away.

public class TweetPostedNotification : INotification
{
	public string Content { get; set; }
	public string Username { get; set; }
}

public class TweetPostedNotificationHandler : INotificationHandler<TweetPostedNotification>
{
	public Task Handle(TweetPostedNotification notification, CancellationToken cancellationToken)
	{
		$"New tweet by @{notification.Username}: {notification.Content}".Dump("new tweet!");
		return Task.CompletedTask;
	}
}

4. Main Method: Wire Up the API in LINQPad

To bring everything together, here’s how you can wire up your CQRS handlers and MediatR in a minimal ASP.NET Core API. This Main method sets up the services, routes, and runs the app—all ready to run in LINQPad. This is the fastest way to see CQRS and MediatR in action, and perfect for hands-on learning.

async Task Main()
{
	var builder = WebApplication.CreateBuilder();
	builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Tweet).Assembly));
	builder.Services.AddSingleton<List<Tweet>>();

	var app = builder.Build();
	app.MapGet("/", () => "MediatR example in LINQPad!");
	app.MapGet("/api/tweets", async (IMediator mediator) =>
	{
		List<Tweet> tweets = await mediator.Send(new TweetsGetAllQuery());
		return Results.Ok(tweets);
	});
	app.MapPost("/api/tweet", async (
		IMediator mediator,
		[FromBody] TweetCreateCommand command
	) =>
	{
		Tweet tweet = await mediator.Send(command);
		return Results.Ok(tweet);
	});
	app.Run();
}

public class Tweet
{
	public int Id { get; set; }
	public string Content { get; set; }
	public string Username { get; set; }
	public DateTime PostedAt { get; set; }
}

5. How to Interact with Your LINQPad CQRS API

Once you run the Main method in LINQPad, your API will be available at http://localhost:5000. Here’s how you can interact with it to test your CQRS and MediatR setup:

Get All Tweets
Open your browser or use a tool like Postman to send a GET request:

GET http://localhost:5000/api/tweets

Insert a New Tweet
You can add a tweet by sending a POST request. Here’s a PowerShell command you can use to post a new tweet directly from your terminal:

Invoke-RestMethod -Uri "http://localhost:5000/api/tweet" -Method Post -ContentType "application/json" -Body '{"content": "Hello, X! #MediatR", "username": "twitterfan"}'

This will create a new tweet and trigger the notification handler, which you’ll see output in LINQPad. This hands-on approach is a great way to learn CQRS and MediatR, and LINQPad makes the process fast and interactive.

Final Thoughts

CQRS and MediatR are just options for organizing your code. They’re not required, but they can make your projects easier to manage. And with LINQPad, you can try these patterns out instantly—no setup, no fuss.

If you want to learn more about LINQPad, CQRS, or MediatR, check out the rest of LearningLinqpad.com. You’ll find guides, tips, and a course designed to help you master modern .NET development. And if you’re ready to take the next step, don’t forget to check out our coding course or grab a LINQPad license through our referral link!


Want to practice these concepts hands-on? Try LINQPad—it’s the fastest way to experiment with code, test database queries, and build your confidence for interviews. For more in-depth learning, check out our coding course and explore our LINQPad referral licenses to support your journey.

CQRS MediatR LINQPad C# .NET Clean Architecture