Eml.Mediator
8.0.0
dotnet add package Eml.Mediator --version 8.0.0
NuGet\Install-Package Eml.Mediator -Version 8.0.0
<PackageReference Include="Eml.Mediator" Version="8.0.0" />
paket add Eml.Mediator --version 8.0.0
#r "nuget: Eml.Mediator, 8.0.0"
// 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<TestAsyncCommand>.
/// <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<TestAsyncRequest, TestResponse>.
/// <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
- Simply inject IMediator in the constructor. See ConsumerClassWithMediator.cs for more details.
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
}
}
- This is the equivalent class without leveraging IMediator. See ConsumerClassWithoutMediator.cs for more details.
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.
Product | Versions 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. |
-
net6.0
- Microsoft.Extensions.DependencyInjection (>= 6.0.1)
-
net7.0
- Microsoft.Extensions.DependencyInjection (>= 7.0.0)
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
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.