RouteDispatcher 1.3.41
dotnet add package RouteDispatcher --version 1.3.41
NuGet\Install-Package RouteDispatcher -Version 1.3.41
<PackageReference Include="RouteDispatcher" Version="1.3.41" />
<PackageVersion Include="RouteDispatcher" Version="1.3.41" />
<PackageReference Include="RouteDispatcher" />
paket add RouteDispatcher --version 1.3.41
#r "nuget: RouteDispatcher, 1.3.41"
#:package RouteDispatcher@1.3.41
#addin nuget:?package=RouteDispatcher&version=1.3.41
#tool nuget:?package=RouteDispatcher&version=1.3.41
RouteDispatcher 
A simple mediator implementation for .NET
Description
This library provides a simple mediator implementation that allows you to decouple request handling from the request source. It uses the IServiceProvider to resolve the appropriate handler for a given request.
Usage
Install the NuGet package:
dotnet add package RouteDispatcherCreate a request class:
public class MyRequest : IRequest<MyResponse> { }Create a response class:
public class MyResponse { }Create a request handler:
public class MyRequestHandler : IInvocationHandler<MyRequest, MyResponse> { public Task<MyResponse> Handle(MyRequest request) { // Handle the request and return a response return Task.FromResult(new MyResponse()); } }Resolve the
IDispatcherfrom theIServiceProvideror through dependency injection:// From IServiceProvider var dispatcher = serviceProvider.GetRequiredService<IDispatcher>(); // Or through dependency injection public class MyClass { private readonly IDispatcher _dispatcher; public MyClass(IDispatcher dispatcher) { _dispatcher = dispatcher; } }Send the request to the mediator:
var response = await _dispatcher.Send(new MyRequest());
Request without response (void)
If you don't need a response from your request handler, you can use IRequest without a generic parameter:
Create a request class:
public class MyVoidRequest : IRequest { public string Content { get; set; } public bool WasHandled { get; set; } }Create a request handler:
public class MyVoidRequestHandler : IInvocationHandler<MyVoidRequest, Empty> { public Task<Empty> Handle(MyVoidRequest request, CancellationToken cancellationToken) { // Handle the request without returning a response request.Content += "Handled by MyVoidRequestHandler"; request.WasHandled = true; return Empty.Value; } }Send the request using the
IDispatcher:await _dispatcher.Send( new MyVoidRequest { Content = "Initial content: " } );
Message Handling
For scenarios where you want to implement the publish-subscribe pattern, you can use IMessage and IMessageHandler<T>:
Create a message class:
public class MyMessage : IMessage { public string Content { get; set; } }Create a message handler:
public class MyMessageHandler : IMessageHandler<MyMessage> { public Task OnMessage(MyMessage message, CancellationToken cancellationToken) { // Process the message Console.WriteLine($"Received message: {message.Content}"); return Task.CompletedTask; } }Publish a message using the
IDispatcher:await _dispatcher.Broadcast( new MyMessage { Content = "Hi from message " } );
Stream Handling
For scenarios where you need to stream multiple responses for a single request, RouteDispatcher supports this through IStreamRequest<TResponse> and handlers that return IAsyncEnumerable<TResponse>. This is useful for operations that produce data over time, such as processing large datasets or long-running tasks that provide incremental updates.
Define your stream request, which must implement
IStreamRequest<TResponse>whereTResponseis the type of item in the stream:// Request for a stream of MyStreamItemResponse objects public class MyDataStreamRequest : IStreamRequest<MyStreamItemResponse> { public int NumberOfItemsToGenerate { get; set; } }Define the class for the items that will be part of the stream:
public class MyStreamItemResponse { public int ItemId { get; set; } public string Message { get; set; } public DateTime Timestamp { get; set; } }Create a handler for your stream request. This handler should implement an interface like
IStreamInvocationHandler<TRequest, TResponse>(whereTRequestis your stream request type andTResponseis your stream item response type). The method responsible for handling the stream (e.g.,Handle) must return anIAsyncEnumerable<TResponse>:// Handler for MyDataStreamRequest, streaming MyStreamItemResponse objects public class MyDataStreamRequestHandler : IStreamInvocationHandler<MyDataStreamRequest, MyStreamItemResponse> { // The Handle method (or the specific method name configured in your Dispatcher for streams) // now returns an IAsyncEnumerable<MyStreamItemResponse> public async IAsyncEnumerable<MyStreamItemResponse> Handle( MyDataStreamRequest request, [EnumeratorCancellation] CancellationToken cancellationToken) // [EnumeratorCancellation] is recommended { for (int i = 0; i < request.NumberOfItemsToGenerate; i++) { // Ensure operation is cancelled if requested by the consumer cancellationToken.ThrowIfCancellationRequested(); // Simulate asynchronous work to generate an item await Task.Delay(TimeSpan.FromMilliseconds(200), cancellationToken); yield return new MyStreamItemResponse { ItemId = i + 1, Message = $"This is item {i + 1} from the stream.", Timestamp = DateTime.UtcNow }; } } }Note: The
[EnumeratorCancellation]attribute on theCancellationTokenparameter is good practice forasync IAsyncEnumerablemethods.Use the
Streammethod on theIDispatcherto initiate the stream. You can then consume theIAsyncEnumerable<TResponse>usingawait foreach:// Resolve the IDispatcher from IServiceProvider or through dependency injection // var dispatcher = serviceProvider.GetRequiredService<IDispatcher>(); // Assuming _dispatcher is an injected IDispatcher instance: var streamRequest = new MyDataStreamRequest { NumberOfItemsToGenerate = 5 }; try { await foreach (var item in _dispatcher.Stream(streamRequest, CancellationToken.None)) { Console.WriteLine($"Received: ID={item.ItemId}, Msg='{item.Message}', Time='{item.Timestamp:O}'"); // Process each item as it arrives // Example: if (item.ItemId == 3) break; // to stop consumption early } } catch (OperationCanceledException) { Console.WriteLine("Stream consumption was cancelled."); } finally { Console.WriteLine("Finished consuming the stream or cancellation occurred."); }
This approach allows the client to process each item as it's generated and yielded by the handler, without needing to wait for the entire sequence of responses to be collected first. This is highly efficient for handling large or continuous data flows.
Extension Method Usage
It is required to use the AddRouteDispatcher extension method to register all IInvocationHandler<,> and IMessageHandler<> implementations. This method accepts a params Assembly[] array, so you can call it with one or more assemblies:
// If handlers are in the same assembly, you can call it without arguments:
services.AddRouteDispatcher();
// Otherwise, specify one or more assemblies:
services.AddRouteDispatcher(typeof(Program).Assembly);
// Or
services.AddRouteDispatcher(
typeof(AnotherAssemblyWithRequestHandlers).Assembly,
typeof(YetAnotherAssemblyWithRequestHandlers).Assembly
);
Recomended ⚠️
You can also configure the dispatcher with caching using the AddRouteDispatcher extension method with an Action<DispatcherConfiguration>. The cache is used to avoid the use of reflection when obtaining the handler type again and again, and reuse a type previously discovered:
services.AddRouteDispatcher(options => {
// options.Assemblies: If not set, the current assembly will be used.
options.Assemblies = new[] { typeof(Program).Assembly };
// options.UseHandlersCache: If false, the following configurations are not needed.
options.UseHandlersCache = true;
// options.DiscardCachedHandlersTimeout: Allows the GC to clean up memory from handlers that are not used for a long time.
options.DiscardCachedHandlersTimeout = TimeSpan.FromSeconds(30);
// default to TimeSpan.FromSeconds(30)
// options.KeepCacheForEver: Prevents the deletion of elements from the cache.
options.KeepCacheForEver = false; // Default to false
});
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 9.0.4)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
-
net6.0
- Microsoft.Bcl.AsyncInterfaces (>= 9.0.4)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 6.0.0)
-
net8.0
- Microsoft.Bcl.AsyncInterfaces (>= 9.0.4)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
-
net9.0
- Microsoft.Bcl.AsyncInterfaces (>= 9.0.4)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.3.41 | 214 | 5/11/2025 |
| 1.2.39 | 143 | 5/9/2025 |
| 1.2.38 | 200 | 5/4/2025 |
| 1.1.36 | 221 | 4/20/2025 |
| 1.1.35 | 213 | 4/19/2025 |
| 1.1.34 | 226 | 4/19/2025 |
| 1.1.32 | 171 | 4/19/2025 |
| 1.0.34 | 193 | 4/18/2025 |
| 1.0.33 | 166 | 4/18/2025 |
| 1.0.32 | 158 | 4/18/2025 |
| 1.0.31 | 181 | 4/18/2025 |
| 1.0.30 | 198 | 4/18/2025 |
| 1.0.0 | 180 | 4/18/2025 |