Eml.Mediator 8.0.0

dotnet add package Eml.Mediator --version 8.0.0                
NuGet\Install-Package Eml.Mediator -Version 8.0.0                
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="Eml.Mediator" Version="8.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Eml.Mediator --version 8.0.0                
#r "nuget: Eml.Mediator, 8.0.0"                
#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.
// Install Eml.Mediator as a Cake Addin
#addin nuget:?package=Eml.Mediator&version=8.0.0

// Install Eml.Mediator as a Cake Tool
#tool nuget:?package=Eml.Mediator&version=8.0.0                

Eml.Mediator

  • Has own Visual Studio Addin for easier use.

  • Small size.

  • Capture Business-use-cases and convert it into a modular, highly testable chunk of codes. One step closer to dissecting & migrating monolithic apps. A combination of Command, Request-Response, Mediator and Abstract Class Factory pattern.

  • Provides a common ground for projects with large number of developers.

  • .Net5 is now supported.

Limitations
  • ExecuteAsync will always create a new instance of the engine.
  • The lifetime of the engine ends as soon as ExecuteAsync is completed.
  • If this behavior does not suit your needs, just use dependency injection via the constructor.

A. Usage - Command

    [Fact]
    public async Task Command_ShouldBeCalledOnce()
    {
        var command = new TestAsyncCommand();   //<-Data

        await mediator.ExecuteAsync(command);   //<-Execute

        command.EngineInvocationCount.ShouldBe(1);
    }

1. Create a command class.

TestAsyncCommand contains the needed data for await mediator.ExecuteAsync(command);.

    public class TestAsyncCommand : ICommandAsync
    {
        public int EngineInvocationCount { get; set; }

        /// <summary>
        /// This request will be processed by <see cref="TestAsyncCommandEngine"/>.
        /// </summary>
        public TestAsyncCommand()
        {
            EngineInvocationCount = 0;
        }
    }

2. Create a command engine.

TestAsyncCommandEngine will be auto-discovered and executed by await mediator.ExecuteAsync(command);.

    /// <summary>
    /// DI signature: ICommandAsyncEngine&lt;TestAsyncCommand&gt;.
    /// <inheritdoc cref="ICommandAsyncEngine{TestAsyncCommand}"/>
    /// </summary>
    public class TestAsyncCommandEngine : ICommandAsyncEngine<TestAsyncCommand>
    {
        public async Task ExecuteAsync(TestAsyncCommand commandAsync)
        {
            await Task.Run(() => commandAsync.EngineInvocationCount++);
        }
    }

B. Usage - Request-Response

    [Fact]
    public async Task Response_ShouldReturnCorrectValue()
    {
        var request = new TestAsyncRequest(Guid.NewGuid());     //<-Request

        var response = await mediator.ExecuteAsync(request);    //<-Execute

        response.ResponseToRequestId.ShouldBe(request.Id);      //<-Return Value
    }

1. Create a Request class.

TestAsyncRequest contains the needed data for TestRequestAsyncEngine.

    public class TestAsyncRequest : IRequestAsync<TestAsyncRequest, TestResponse>
    {
        public Guid Id { get; private set; }

        /// <summary>
        /// This request will be processed by <see cref="TestRequestAsyncEngine"/>.
        /// </summary>
        public TestAsyncRequest(Guid id)
        {
            Id = id;
        }
    }

2. Create a Response class.

TestResponse is the return value of await mediator.ExecuteAsync(request);.

    /// <summary>
    /// TestRequestAsyncEngine return value.
    /// </summary>
    public class TestResponse : IResponse
    {
        public Guid ResponseToRequestId { get; }        //<-Return Value

        public TestResponse(Guid responseToRequestId)
        {
            ResponseToRequestId = responseToRequestId;
        }
    }

3. Create a Request engine.

TestRequestAsyncEngine will be auto-discovered and executed by var response = await mediator.ExecuteAsync(request);.

    /// <summary>
    /// DI signature: IRequestAsyncEngine&lt;TestAsyncRequest, TestResponse&gt;.
    /// <inheritdoc cref="IRequestAsyncEngine{TestAsyncRequest, TestResponse}"/>
    /// </summary>
    public class TestRequestAsyncEngine : IRequestAsyncEngine<TestAsyncRequest, TestResponse>
    {
        public async Task<TestResponse> ExecuteAsync(TestAsyncRequest request)
        {
            return await Task.Run(() => new TestResponse(request.Id));
        }
    }

C. DI Registration

Requires Scrutor for the automated registration.

See IntegrationTestDiFixture.cs for more details.

    private static void ConfigureServices(IServiceCollection services)
    {
        services.Scan(scan => scan
            .FromAssemblyDependencies(typeof(IntegrationTestDiFixture).Assembly)

                // Register IMediator
                .AddClasses(classes => classes.AssignableTo<IMediator>())
                .AsSelfWithInterfaces()
                .WithSingletonLifetime()

                // Register RequestEngines, CommandEngines - Async
                .AddClasses(classes => classes.AssignableTo(typeof(IRequestAsyncEngine<,>)))
                .AsImplementedInterfaces()
                .WithTransientLifetime()
                
                // Register RequestEngines, CommandEngines
                .AddClasses(classes => classes.AssignableTo(typeof(IRequestEngine<,>)))
                .AsImplementedInterfaces()
                .WithTransientLifetime()

                // Register CommandEngines - Async
                .AddClasses(classes => classes.AssignableTo(typeof(ICommandAsyncEngine<>)))
                .AsImplementedInterfaces()
                .WithTransientLifetime()
                
                // Register CommandEngines
                .AddClasses(classes => classes.AssignableTo(typeof(ICommandEngine<>)))
                .AsImplementedInterfaces()
                .WithTransientLifetime()

                // IDiDiscoverableTransient
                .AddClasses(classes => classes.AssignableTo(typeof(IDiDiscoverableTransient)))
                .AsImplementedInterfaces()
                .WithTransientLifetime()
        );
    }

D. Sample Class

    public class ConsumerClassWithMediator : IConsumerClassWithMediator
    {
        private readonly IMediator mediator;

        public ConsumerClassWithMediator(IMediator mediator)        //<-Inject IMediator
        {
            this.mediator = mediator;
        }

        public async Task<TestResponse> DoSomething()
        {
            var request = new TestAsyncRequest(Guid.NewGuid());     //<-Request

            var response = await mediator.ExecuteAsync(request);    //<-Execute

            return response;                                        //<-Return Value
        }
    }
    public class ConsumerClassWithoutMediator : IConsumerClassWithoutMediator
    {
        private readonly IRequestAsyncEngine<TestAsyncRequest, TestResponse> engine;

        public ConsumerClassWithoutMediator(IRequestAsyncEngine<TestAsyncRequest, TestResponse> engine)     //<-Normal dependency injection. Inject engine
        {
            this.engine = engine;
        }

        public async Task<TestResponse> DoSomething()
        {
            var request = new TestAsyncRequest(Guid.NewGuid());     //<-Request

            var response = await engine.ExecuteAsync(request);      //<-Execute

            return response;                                        //<-Return Value
        }
    }

That's it.

Check out Eml.Mediator.vsix to automate the steps above.

alternate text is missing from this package README image

Product Compatible and additional computed target framework versions.
.NET 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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (3)

Showing the top 3 NuGet packages that depend on Eml.Mediator:

Package Downloads
Eml.ControllerBase

ControllerBase for WebApi CRUD operations.

Eml.ControllerBase.Mvc

Base Classes for MVC CRUD operations and other useful utilities.

Eml.ControllerBase.Api.MySql

ControllerBase for WebApi with MySql.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
8.0.0 1,769 11/26/2023
7.1.2 711 9/3/2023
7.1.1 263 7/8/2023
7.1.0 235 7/1/2023
7.0.0 449 12/10/2022
6.0.3 568 8/27/2022
6.0.2 520 8/27/2022
6.0.0 1,781 1/19/2022
5.0.8 524 9/17/2021
5.0.7 592 3/16/2021
5.0.6 755 2/28/2021
5.0.0 719 1/16/2021
2.2.0.6 1,655 9/13/2020