VOOZH about

URL: https://www.nuget.org/packages/MediatR.Courier/

⇱ NuGet Gallery | MediatR.Courier 7.0.1




MediatR.Courier 7.0.1

dotnet add package MediatR.Courier --version 7.0.1
 
 
NuGet\Install-Package MediatR.Courier -Version 7.0.1
 
 
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MediatR.Courier" Version="7.0.1" />
 
 
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MediatR.Courier" Version="7.0.1" />
 
Directory.Packages.props
<PackageReference Include="MediatR.Courier" />
 
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MediatR.Courier --version 7.0.1
 
 
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: MediatR.Courier, 7.0.1"
 
 
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MediatR.Courier@7.0.1
 
 
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MediatR.Courier&version=7.0.1
 
Install as a Cake Addin
#tool nuget:?package=MediatR.Courier&version=7.0.1
 
Install as a Cake Tool
The NuGet Team does not provide support for this client. Please contact its maintainers for support.

MediatR.Courier 👁 Nuget
👁 Quality Gate Status
👁 Coverage

A simple library to treat MediatR notifications sort of like events.

Main usage target is client applications.

What does this solve?

This library is aimed to provide help for client-side applications using the event aggregator pattern with MediatR.

Usage

Install form NuGet

Basic usage:

services
 .AddMediatR(c => c.RegisterServicesFromAssemblyContaining(typeof(MyType)))
 .AddCourier(typeof(MyType).Assembly);

ICourier _courier;

void SubscribeToCourier()
{
 // Subscribe to a specific notification type your want to receive.
 _courier.Subscribe<ExampleNotification>(HandleNotification)
}

void HandleNotification(ExampleNotification notification, CancellationToken cancellationToken)
{
 //Do your handling logic here.
 Console.WriteLine("ExampleNotification handled");
}

void UnsubscribeFromCourier()
{
 // Unsubscribe with the same delegate you subscribed with, just like with events.
 _courier.UnSubscribe(HandleNotification);
}

// Somewhere else.

private readonly IMediator _mediator;

async Task FireNotification()
{
 // Somewhere some class publishes a notification with the mediator.
 // Courier is just a specialized INotificationHandler<INotification> implementation.
 await _mediator.Publish(new ExampleNotification());
}

Main concepts:

Events become concrete classes:

//Regular class with event
public class EventProducer
{
 public event Action ExampleEvent;
}

//Event defined when using Courier
public class ExampleEvent : INotification
{
 //Your implementation own implementation properties, methods, etc...
}

Working with events:

// Using an regular C# event:
void Handler()
{
 //Implementation
}
EventProducer producer.ExampleEvent += Handler;
EventProducer producer.ExampleEvent -= Handler;

// Using Courier:

void Handler(ExampleEvent notification)
{
 //Implementation
}

ICourier courier = ;//Create courier

courier.Subscribe<ExampleEvent>(Handler);
courier.UnSubscribe<ExampleEvent>(Handler);

Firing events

// Regular C# events
public class EventProducer
{
 public event Action ExampleEvent;

 public void RaiseEvent()
 {
 //Implementation
 ExampleEvent?.Invoke();
 }
}

// Courier
public class EventProducer
{
 private IMediator _mediator = ;//Get mediator

 public void RaiseEvent()
 {
 _mediator.Publish(new ExampleNotification());
 }
}

What benefits does it provide?

  • Your classes handling events don't need a direct reference to a specific instance of an event producer, or some middleman connecting them, just a reference to the Courier
  • If the handler is "far" away from the event producer, you don't need to chain events through other classes to receive them

How is this different from MediatR's INotificationHandler?

MediatR instantiates the classes implementing INotificationHandler through the provided ServiceProvider which is most of the time is some dependency injection container, thus it is rather hard to tie handling an event to a specific event handler.

Let's say you have your View which contains two windows. Both windows have the same ViewModel class. You want this ViewModel class to handle some event. What are some choices to handle the lifetime and state of those view models?

  • You can make your ViewModel singleton, and when MediatR publishes the notification to the single view model instance. This creates the possible problem that your ViewModels can't hold different state in your windows.
  • Have some service handle the notification, then publish it's contents as a regular C# event and then get the reference to that exact service instance to your ViewModels and subscribe to that event. This way you can easily have an individual state in multiple ViewModels, but you need some way to connect them to MediatR notifications.

Courier is a simple implementation of the second choice: Let some middleman handle notifications from MediatR and then pass those notifications to subscribers

Isn't this pattern implemented already in some other libraries?

Yes, quite a few actually, just a few examples:

The difference from those implementations is that most of them implement this concept as part of their framework. When using them in Zenject or Prism you tie some of your implementation to those frameworks, thus having you depend on code you might not want to use. This library has one core dependency: MediatR, and it assumes very little about your architecture. If you are already using MediatR in your business logic layer then adding some reactiveness to it with Courier is easy.

In the same way as using MediatR can be thought of as replacing business layer services to MediatR Requests and RequestHandlers, Courier is the same for events: replacing them with INotifications.

Weak references

You can create a weak subscription by using the SubscribeWeak method. This subscription uses a WeakReference which will let the subscriber to be garbage collected without the need to unsubscribe (although you still can unsubscribe manually). Subscribing methods on MonoBehavior instances in Unity3D might result in unexpected behavior, so you should be careful with it.

courier.SubscribeWeak<MyNotification>(notification => /*...*/);

courier.SubscribeWeak<MyNotification>((notification, cancellation) => /*...*/);

Capturing thread context

You can configure how the Courier awaits the sent notifications. To change the behavior modify the CaptureThreadContext property on the CourierOptions class. When using dependency injection, you can change this behavior during runtime, because the CourierOptions is accessible through DI.

Parallel notification handling

You can configure whether notification handlers should run sequentially or in parallel by using the UseTaskWhenAll property on the CourierOptions class:

// Configure at registration time
services.AddCourier(typeof(MyType).Assembly, options => 
{
 options.UseTaskWhenAll = true; // Enable parallel execution of handlers
});

// Or modify at runtime through dependency injection
var options = serviceProvider.GetRequiredService<CourierOptions>();
options.UseTaskWhenAll = true;

When UseTaskWhenAll is set to true, asynchronous notification handlers are collected and awaited concurrently using Task.WhenAll.

When set to false (the default), handlers are awaited sequentially.

Gotchas

  • No ordering is guaranteed when calling the subscribed methods
  • Async void methods are not awaited.
Product Versions Compatible and additional computed target framework versions.
.NET net5.0 net5.0 was computed.  net5.0-windows net5.0-windows was computed.  net6.0 net6.0 is compatible.  net6.0-android net6.0-android was computed.  net6.0-ios net6.0-ios was computed.  net6.0-maccatalyst net6.0-maccatalyst was computed.  net6.0-macos net6.0-macos was computed.  net6.0-tvos net6.0-tvos was computed.  net6.0-windows net6.0-windows was computed.  net7.0 net7.0 was computed.  net7.0-android net7.0-android was computed.  net7.0-ios net7.0-ios was computed.  net7.0-maccatalyst net7.0-maccatalyst was computed.  net7.0-macos net7.0-macos was computed.  net7.0-tvos net7.0-tvos was computed.  net7.0-windows net7.0-windows was computed.  net8.0 net8.0 was computed.  net8.0-android net8.0-android was computed.  net8.0-browser net8.0-browser was computed.  net8.0-ios net8.0-ios was computed.  net8.0-maccatalyst net8.0-maccatalyst was computed.  net8.0-macos net8.0-macos was computed.  net8.0-tvos net8.0-tvos was computed.  net8.0-windows net8.0-windows was computed.  net9.0 net9.0 was computed.  net9.0-android net9.0-android was computed.  net9.0-browser net9.0-browser was computed.  net9.0-ios net9.0-ios was computed.  net9.0-maccatalyst net9.0-maccatalyst was computed.  net9.0-macos net9.0-macos was computed.  net9.0-tvos net9.0-tvos was computed.  net9.0-windows net9.0-windows was computed.  net10.0 net10.0 was computed.  net10.0-android net10.0-android was computed.  net10.0-browser net10.0-browser was computed.  net10.0-ios net10.0-ios was computed.  net10.0-maccatalyst net10.0-maccatalyst was computed.  net10.0-macos net10.0-macos was computed.  net10.0-tvos net10.0-tvos was computed.  net10.0-windows net10.0-windows was computed. 
.NET Core netcoreapp2.0 netcoreapp2.0 was computed.  netcoreapp2.1 netcoreapp2.1 was computed.  netcoreapp2.2 netcoreapp2.2 was computed.  netcoreapp3.0 netcoreapp3.0 was computed.  netcoreapp3.1 netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 netstandard2.0 is compatible.  netstandard2.1 netstandard2.1 was computed. 
.NET Framework net461 net461 was computed.  net462 net462 was computed.  net463 net463 was computed.  net47 net47 was computed.  net471 net471 was computed.  net472 net472 was computed.  net48 net48 was computed.  net481 net481 was computed. 
MonoAndroid monoandroid monoandroid was computed. 
MonoMac monomac monomac was computed. 
MonoTouch monotouch monotouch was computed. 
Tizen tizen40 tizen40 was computed.  tizen60 tizen60 was computed. 
Xamarin.iOS xamarinios xamarinios was computed. 
Xamarin.Mac xamarinmac xamarinmac was computed. 
Xamarin.TVOS xamarintvos xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on MediatR.Courier:

Package Downloads
MediatR.Courier.DependencyInjection

A simple library to treat MediatR notifications sort of like events. Main usage target is client applications.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
7.0.1 19,906 6/16/2025
7.0.0 244 6/16/2025
7.0.0-preview1 191 6/15/2025
6.0.0 143,548 3/3/2023
5.0.0 160,598 1/24/2022
5.0.0-preview0001 409 1/20/2022
4.0.0 5,382 12/9/2021
3.0.1 16,348 3/16/2021
3.0.0 784 3/16/2021
2.1.2 2,971 7/2/2020
2.1.1 1,420 3/14/2020
2.1.0 1,006 3/4/2020
2.0.0 973 2/10/2020
1.2.0 944 2/10/2020
1.1.0 965 1/28/2020
1.0.1 1,177 1/25/2020
1.0.0 1,376 1/25/2020

# 7.0.1
- Remove unnecessary check for _options.UseTaskWhenAll
- README: Add 'Parallel notification handling' section

# 7.0.0
- Removed Nuke
- Updated to .NET 8
- Fixed sonarcloud. Now only run on master pushes, on PRs we only run dotnet test and format
- Removed old azure devops pipelines
- Pipelines now fully written in github actions
- Updated dependencies
- Added documentation comments to `ICourier`, `CourierInjector` and `CourierOptions`
- Use Invoke iso DynamicInvoke for better performance
- Fix bug where RemoveWeak would sometimes remove too many handlers
- Add `UseTaskWhenAll` option for parallel notification handling

# 6.0.0
- Update MediatR to version 12
- Deprecate DI package
- Move test and sample code into one project
- Removed support for convention and interface clients
- Multi target .NET standard 2.0 and .NET 6
- Use reproducible builds
- Include Readme and Changelog in package

# 5.0.0
- Update MediatR to version 10
- Update target framework to netstandard2.1