All Projects → mayuanyang → Mediator.net

mayuanyang / Mediator.net

Licence: apache-2.0
A simple mediator for .Net for sending command, publishing event and request response with pipelines supported

Programming Languages

csharp
926 projects

Projects that are alternatives of or similar to Mediator.net

Event Sourcing Castanha
An Event Sourcing service template with DDD, TDD and SOLID. It has High Cohesion and Loose Coupling, it's a good start for your next Microservice application.
Stars: ✭ 68 (-71.31%)
Mutual labels:  dotnetcore, ddd, cqrs
Modular Monolith With Ddd
Full Modular Monolith application with Domain-Driven Design approach.
Stars: ✭ 6,210 (+2520.25%)
Mutual labels:  dotnetcore, ddd, cqrs
Quiz
Example real time quiz application with .NET Core, React, DDD, Event Sourcing, Docker and built-in infrastructure for CI/CD with k8s, jenkins and helm
Stars: ✭ 100 (-57.81%)
Mutual labels:  dotnetcore, ddd, cqrs
Weapsy
ASP.NET Core CMS
Stars: ✭ 748 (+215.61%)
Mutual labels:  dotnetcore, ddd, cqrs
Eventflow.example
DDD+CQRS+Event-sourcing examples using EventFlow following CQRS-ES architecture. It is configured with RabbitMQ, MongoDB(Snapshot store), PostgreSQL(Read store), EventStore(GES). It's targeted to .Net Core 2.2 and include docker compose file.
Stars: ✭ 131 (-44.73%)
Mutual labels:  dotnetcore, ddd, cqrs
Php Ddd Skeleton
🐘🚀 PHP DDD Skeleton: Bootstrap your new projects or be inspired by this example project
Stars: ✭ 152 (-35.86%)
Mutual labels:  ddd, cqrs
Event Sourcing Jambo
An Hexagonal Architecture with DDD + Aggregates + Event Sourcing using .NET Core, Kafka e MongoDB (Blog Engine)
Stars: ✭ 159 (-32.91%)
Mutual labels:  ddd, cqrs
Qframework
Unity3D System Design Architecture
Stars: ✭ 2,326 (+881.43%)
Mutual labels:  cqrs, ddd
Spring Boot Axon Sample
Sample application using Spring Boot, Axon, AngularJS and Websockets
Stars: ✭ 169 (-28.69%)
Mutual labels:  ddd, cqrs
Goes
Go Event Sourcing made easy
Stars: ✭ 144 (-39.24%)
Mutual labels:  ddd, cqrs
Revo
Event Sourcing, CQRS and DDD framework for C#/.NET Core.
Stars: ✭ 162 (-31.65%)
Mutual labels:  ddd, cqrs
Ddd Laravel Sample
A Laravel DDD sample application using CQRS and persisting entities serialized without ORM
Stars: ✭ 172 (-27.43%)
Mutual labels:  ddd, cqrs
Bicing Api
Get statistics and locations of bicycle stations through REST API
Stars: ✭ 149 (-37.13%)
Mutual labels:  ddd, cqrs
Eventflow
Async/await first CQRS+ES and DDD framework for .NET
Stars: ✭ 1,932 (+715.19%)
Mutual labels:  ddd, cqrs
Stove
Domain Driven Design oriented application framework, meets CRUD needs
Stars: ✭ 160 (-32.49%)
Mutual labels:  ddd, cqrs
Kotlin Ddd Sample
A sample DDD/CQRS project using KOTLIN 🍺
Stars: ✭ 145 (-38.82%)
Mutual labels:  ddd, cqrs
Architecture
.NET 6, ASP.NET Core 6, Entity Framework Core 6, C# 10, Angular 13, Clean Code, SOLID, DDD.
Stars: ✭ 2,285 (+864.14%)
Mutual labels:  dotnetcore, ddd
Enexure.microbus
MicroBus is a simple in process Mediator for .NET
Stars: ✭ 197 (-16.88%)
Mutual labels:  dotnetcore, cqrs
Messagebus
A MessageBus (CommandBus, EventBus and QueryBus) implementation in PHP7
Stars: ✭ 178 (-24.89%)
Mutual labels:  ddd, cqrs
Digital Restaurant
DDD. Event sourcing. CQRS. REST. Modular. Microservices. Kotlin. Spring. Axon platform. Apache Kafka. RabbitMQ
Stars: ✭ 222 (-6.33%)
Mutual labels:  ddd, cqrs

Build status Mediator.Net on Stack Overflow

Mediator.Net

A mediator project for .NET

logo_sm

Get Packages

You can get Mediator.Net by grabbing the latest NuGet packages.

Get Started

Install the nuget package Mediator.Net

Install-Package Mediator.Net

Simple usage

// Setup a mediator builder
var mediaBuilder = new MediatorBuilder();
var mediator = mediaBuilder.RegisterHandlers(typeof(this).Assembly).Build();     

Sending a command, publishing event and sending request and getting response

await _mediator.SendAsync(new TestBaseCommand(Guid.NewGuid()));
await _mediator.PublishAsync(new TestEvent(Guid.NewGuid()));
var result = await _mediator.RequestAsync<GetGuidRequest, GetGuidResponse>(new GetGuidRequest(_guid));

Handling message from handler

Once a message is sent, it will reach its handlers, you can only have one handler for ICommand and IRequest and can have multi handlers for IEvent. ReceiveContext will be delivered to the handler.

class TestBaseCommandHandler : ICommandHandler<TestBaseCommand>
{
    public Task Handle(ReceiveContext<TestBaseCommand> context)
    {
        Console.WriteLine(context.Message.Id);
        return Task.FromResult(0);
    }
}
	
// Or in async 
class AsyncTestBaseCommandHandler : ICommandHandler<TestBaseCommand>
{
    public async Task Handle(ReceiveContext<TestBaseCommand> context)
    {
        Console.WriteLine(context.Message.Id);
        await Task.FromResult(0);
    }
}

Handler Registration

Handlers explicit registration

var mediator = builder.RegisterHandlers(() =>
{
    var binding = new List<MessageBinding>
    {
        new MessageBinding(typeof(TestBaseCommand), typeof(TestBaseCommandHandler)),
        new MessageBinding(typeof(DerivedTestBaseCommand), typeof(DerivedTestBaseCommandHandler))
    };
    return binding;
}).Build();          

Scan registration

var mediaBuilder = new MediatorBuilder();
var mediator = mediaBuilder.RegisterHandlers(typeof(this).Assembly).Build();

Using pipelines

There are 5 different type of pipelines you can use image

GlobalReceivePipeline

This pipeline will be triggered whenever a message is sent, published or requested before it reaches the next pipeline and handler

CommandReceivePipeline

This pipeline will be triggered just after the GlobalReceivePipeline and before it reaches its command handler, this pipeline will only be used for ICommand

EventReceivePipeline

This pipeline will be triggered just after the GlobalReceivePipeline and before it reaches its event handler/handlers, this pipeline will only be used for IEvent

RequestReceivePipeline

This pipeline will be triggered just after the GlobalReceivePipeline and before it reaches its request handler, this pipeline will only be used for IRequest

PublishPipeline

This pipeline will be triggered when an IEvent is published inside your handler, this pipeline will only be used for IEvent and is usually being used as outgoing interceptor

Setting up middlewares

The most powerful thing for the pipelines above is you can add as many middlewares as you want. Follow the following steps to setup a middlewaree

  • Add a static class for your middleware
  • Add a public static extension method in that class you just added, usually follow the UseXxxx naming convention
  • Add another class for your middleware's specification, note that this is the implementation of your middleware

You might need some dependencies in your middleware, there are two ways to do it

  • Pass them in explicitly
  • Let the IoC container to resolve it for you (if you are using IoC)

Here is a sample middleware

Middleware class

public static class SerilogMiddleware
{
    public static void UseSerilog<TContext>(this IPipeConfigurator<TContext> configurator, LogEventLevel logAsLevel, ILogger logger = null)
        where TContext : IContext<IMessage>
    {
        if (logger == null && configurator.DependencyScope == null)
        {
            throw new DependencyScopeNotConfiguredException($"{nameof(ILogger)} is not provided and IDependencyScope is not configured, Please ensure {nameof(ILogger)} is registered properly if you are using IoC container, otherwise please pass {nameof(ILogger)} as parameter");
        }
        logger = logger ?? configurator.DependencyScope.Resolve<ILogger>();
            
        configurator.AddPipeSpecification(new SerilogMiddlewareSpecification<TContext>(logger, logAsLevel));
    }
}

Specification class

class SerilogMiddlewareSpecification<TContext> : IPipeSpecification<TContext> where TContext : IContext<IMessage>
    {
        private readonly ILogger _logger;
        private readonly Func<bool> _shouldExcute;
        private readonly LogEventLevel _level;

        public SerilogMiddlewareSpecification(ILogger logger, LogEventLevel level, Func<bool> shouldExcute )
        {
            _logger = logger;
            _level = level;
            _shouldExcute = shouldExcute;
        }
        public bool ShouldExecute(TContext context, CancellationToken cancellationToken)
        {
            if (_shouldExcute == null)
            {
                return true;
            }
            return _shouldExcute.Invoke();
        }

        public Task BeforeExecute(TContext context, CancellationToken cancellationToken)
        {
            return Task.FromResult(0);
        }

        public Task Execute(TContext context, CancellationToken cancellationToken)
        {
            if (ShouldExecute(context, cancellationToken))
            {
                switch (_level)
                {
                    case LogEventLevel.Error:
                        _logger.Error("Receive message {@Message}", context.Message);
                        break;
                    case LogEventLevel.Debug:
                        _logger.Debug("Receive message {@Message}", context.Message);
                        break;
                    case LogEventLevel.Fatal:
                        _logger.Fatal("Receive message {@Message}", context.Message);
                        break;
                    case LogEventLevel.Information:
                        _logger.Information("Receive message {@Message}", context.Message);
                        break;
                    case LogEventLevel.Verbose:
                        _logger.Verbose("Receive message {@Message}", context.Message);
                        break;
                    case LogEventLevel.Warning:
                        _logger.Verbose("Receive message {@Message}", context.Message);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
            return Task.FromResult(0);
        }

        public Task AfterExecute(TContext context, CancellationToken cancellationToken)
        {
            return Task.FromResult(0);
        }

        public void OnException(Exception ex, TContext context)
        {
            throw ex;
        }
    }

To hook up middlewares into pipelines

var builder = new MediatorBuilder();
_mediator = builder.RegisterHandlers(() =>
    {
        return new List<MessageBinding>()
        {
            new MessageBinding(typeof(TestBaseCommand), typeof(TestBaseCommandHandlerRaiseEvent)),
            new MessageBinding(typeof(TestEvent), typeof(TestEventHandler)),
            new MessageBinding(typeof(GetGuidRequest), typeof(GetGuidRequestHandler))
        };
    })
    .ConfigureGlobalReceivePipe(x =>
    {
        x.UseDummySave();
    })
    .ConfigureCommandReceivePipe(x =>
    {
        x.UseConsoleLogger1();
    })
    .ConfigureEventReceivePipe(x =>
    {
        x.UseConsoleLogger2();
    })
    .ConfigureRequestPipe(x =>
    {
        x.UseConsoleLogger3();
    })
    .ConfigurePublishPipe(x =>
    {
        x.UseConsoleLogger4();
    })
.Build();

ReceiveContext in Handlers

As you might already noticed, mediator will deliver ReceiveContext to the handler and it has a property Message which is the original message sent, in some cases you might have one event being handled in multiple handlers and you might want to share something between, ReceiveContext would is good place that to register your service or instance. For example you can make a middleware and register the service from there.

Register DummyTransaction from middleware

public class SimpleMiddlewareSpecification<TContext> : IPipeSpecification<TContext>
    where TContext : IContext<IMessage>
{
    public bool ShouldExecute(TContext context)
    {
        return true;
    }

    public Task BeforeExecute(TContext context)
    {
        return Task.FromResult(0);
    }

    public Task Execute(TContext context)
    {
        if (ShouldExecute(context))
        {
            context.RegisterService(new DummyTransaction());
        }
        return Task.FromResult(0);
    }

    public Task AfterExecute(TContext context)
    {
        return Task.FromResult(0);
    }
}

Get the DummyTransaction registered in the middleware from the handler

public Task Handle(ReceiveContext<SimpleCommand> context)
{
    _simpleService.DoWork();
    if (context.TryGetService(out DummyTransaction transaction))
    {
        transaction.Commit();
    }
    return Task.FromResult(0);
}

Using dependency injection(IoC) frameworks

Autofac

Install the nuget package Mediator.Net.Autofac

Install-Package Mediator.Net.Autofac

An extension method RegisterMediator for ContainerBuilder from Autofac is used to register the builder

The super simple use case

var mediaBuilder = new MediatorBuilder();
mediaBuilder.RegisterHandlers(typeof(TestContainer).Assembly);
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterMediator(mediaBuilder);
 _container = containerBuilder.Build();  

You can also setup middlewares for each pipe before register it

var mediaBuilder = new MediatorBuilder();
mediaBuilder.RegisterHandlers(typeof(TestContainer).Assembly)
    .ConfigureCommandReceivePipe(x =>
    {
        x.UseSimpleMiddleware();
    });
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterMediator(mediaBuilder);
_container = containerBuilder.Build();  

StructureMap

Install-Package Mediator.Net.StructureMap

Setup an IContainer and do your normal registration, then pass it along with the MediatorBuilder to the StructureMapExtensions class to register Mediator.Net

var mediaBuilder = new MediatorBuilder();
mediaBuilder.RegisterHandlers(TestUtilAssembly.Assembly)
    .ConfigureCommandReceivePipe(x =>
    {
        x.UseSimpleMiddleware();
    });
_container = new Container();
_container.Configure(x =>
{
    // Do your thing
});
StructureMapExtensions.Configure(mediaBuilder, _container);

Unity

Install-Package Mediator.Net.Unity

Setup an IUnityContainer and do your normal registration, then pass it along with the MediatorBuilder to the UnityExtensions class to register Mediator.Net

var mediaBuilder = new MediatorBuilder();
var mediaBuilder = new MediatorBuilder();
mediaBuilder.RegisterHandlers(TestUtilAssembly.Assembly)
    .ConfigureCommandReceivePipe(x =>
    {
        x.UseSimpleMiddleware();
    });
_container = new UnityContainer();
_container.RegisterType<SimpleService>();
_container.RegisterType<AnotherSimpleService>();

UnityExtensioins.Configure(mediaBuilder, _container);

SimpleInjector

Install-Package Mediator.Net.SimpleInjector

We have created a helper class InjectHelper to register all necessary components for Mediator.Net

var mediaBuilder = new MediatorBuilder();
mediaBuilder.RegisterHandlers(TestUtilAssembly.Assembly)
    .ConfigureCommandReceivePipe(x =>
    {
        x.UseSimpleMiddleware();
    });
_container = new Container();
_container.Options.DefaultScopedLifestyle = new LifetimeScopeLifestyle();
_container.Register<SimpleService>();
_container.Register<AnotherSimpleService>();
    
InjectHelper.RegisterMediator(_container, mediaBuilder);

Thought that you can have transient registration for IMediator, but we recommend to use lifetime scope, you can do constructor injection as well as the following

using (var scope = _container.BeginLifetimeScope())
{
    _mediator = scope.GetInstance<IMediator>();
    _task = _mediator.RequestAsync<SimpleRequest, SimpleResponse>(new SimpleRequest());
}

Middlewares

One of the key feature for Mediator.Net is you can plug as many middlewares as you like, we have implemented some common one as below

Mediator.Net.Middlewares.UnitOfWork

Install-Package Mediator.Net.Middlewares.UnitOfWork

This middleware provide a CommittableTransaction inside the context, handlers can enlist the transaction if it requires UnitOfWork Mediator.Net.Middlewares.UnitOfWork - Middleware for Mediator.Net to support unit of work.

Mediator.Net.Middlewares.Serilog

Install-Package Mediator.Net.Middlewares.Serilog

This middleware logs every message by using Serilog

Mediator.Net.Middlewares.EventStore

Install-Package Mediator.Net.Middlewares.EventStore

Middleware for Mediator.Net to write event to GetEventStore, it is a Middleware for Mediator.Net that plugs intothe publish pipeline Mediator.Net.Middlewares.UnitOfWork - Middleware for Mediator.Net to persist event to EventStore.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].