RouteDispatcher 1.3.41

dotnet add package RouteDispatcher --version 1.3.41
                    
NuGet\Install-Package RouteDispatcher -Version 1.3.41
                    
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="RouteDispatcher" Version="1.3.41" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="RouteDispatcher" Version="1.3.41" />
                    
Directory.Packages.props
<PackageReference Include="RouteDispatcher" />
                    
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 RouteDispatcher --version 1.3.41
                    
#r "nuget: RouteDispatcher, 1.3.41"
                    
#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 RouteDispatcher@1.3.41
                    
#: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=RouteDispatcher&version=1.3.41
                    
Install as a Cake Addin
#tool nuget:?package=RouteDispatcher&version=1.3.41
                    
Install as a Cake Tool

RouteDispatcher NuGet

Production Workflow
Develop Test Workflow

Ask DeepWiki

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

  1. Install the NuGet package:

    dotnet add package RouteDispatcher
    
  2. Create a request class:

    public class MyRequest : IRequest<MyResponse> { }    
    
  3. Create a response class:

    public class MyResponse { }    
    
  4. 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());   
       }   
    }  
    
  5. Resolve the IDispatcher from the IServiceProvider or 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; 
          } 
     }   
    
  6. 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:

  1. Create a request class:

    public class MyVoidRequest : IRequest     
    { 
        public string Content { get; set; } 
        public bool WasHandled { get; set; } 
    } 
    
  2. 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; 
        } 
    }  
    
  3. 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>:

  1. Create a message class:

    public class MyMessage : IMessage    
    { 
        public string Content { get; set; } 
    } 
    
  2. 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; 
        } 
    }   
    
  3. 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.

  1. Define your stream request, which must implement IStreamRequest<TResponse> where TResponse is the type of item in the stream:

    // Request for a stream of MyStreamItemResponse objects
    public class MyDataStreamRequest : IStreamRequest<MyStreamItemResponse>
    {
        public int NumberOfItemsToGenerate { get; set; }
    }
    
  2. 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; }
    }
    
  3. Create a handler for your stream request. This handler should implement an interface like IStreamInvocationHandler<TRequest, TResponse> (where TRequest is your stream request type and TResponse is your stream item response type). The method responsible for handling the stream (e.g., Handle) must return an IAsyncEnumerable<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 the CancellationToken parameter is good practice for async IAsyncEnumerable methods.

  4. Use the Stream method on the IDispatcher to initiate the stream. You can then consume the IAsyncEnumerable<TResponse> using await 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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