Giter VIP home page Giter VIP logo

enexure.microbus's Introduction

👋 Hi, I'm Daniel.

I'm a Tech Lead based in Australia. I enjoy Crafting Culture, Type Safety, Functional Programming and Distributed Systems. People first.


📙 Blog Posts

Ignoring return values can often be dangerous in subtle ways but you may be so used to doing it that you don't even notice anymore. It's…

Hypermedia Controls in REST provide links and actions with each response pointing to related resources. This concept is a powerful tool that…

A lot has been written about REST but less so when it comes to Hypermedia Controls. I haven't seen too many Hypermedia based APIs out in the…

Recently I had the opportunity to write a Custom Connector for Power BI and come across something I didn't expect. To build a Connector you…

Let's look at some questions: How do you specify which API to use for an environment? How do you configure the environment settings of…

I've long been an advocate of Continuous Deployment, but it's always felt somewhat out of reach. I've come close with projects that have had…

Expecto is a fantastic test framework and test runner for FSharp. But contrary to the name, the thing I like most about Expecto is that it…

When working with a traditional database inside of a monolith application, we don't usually need to think too much about how transactions…

You might have heard the phrase "there's no such thing as reliable messaging". It's an interesting statement, but aside from being…

Model State Validation for a JSON API isn't too hard because you only need to send back validation errors, especially with the attribute…

enexure.microbus's People

Contributors

daniellittledev avatar jafin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

enexure.microbus's Issues

ObjectDisposedException with Carter + MicroBus

Hi there!

I've recently started using a Nancy-esque library called Carter for Web API's instead of plain MVC, and I've hit a bit of a snag when using the bus from its modules. I'm not quite sure what the problem is, but the symptom is that the IDepenencyScope that the bus uses to start a new scope to resolve handlers is already disposed. I saw there was another issue around multiple handlers, but this one has just a single event and single handler.

I've created a working reproduction here https://github.com/gkinsman/MicroBusRepro.

Any thoughts would be welcome!

Events do not support multicast

Events are usually subscribed to by multiple parties all interested in the one event. Events in MicroBus should support registering multiple handlers to them.

Saga duplicates task

When using a Saga to kick off a command that will, in turn, generate an event to finish the saga, the generated event happens twice.

image

I'm not sure if that's because I'm "doing it wrong", or if there's a problem in the way the sagas are run.

I created a fork (see reference below) with a unit test (CompleteCommandingSagaTests.cs) to demonstrate the problem. Specifically, in the TestCommandingSaga.cs file, I have two classes - the Saga and the Command Handler. I expect the SagaEndingEvent only once, but it happens twice.

public class TestCommandingSaga : ISaga,
        ISagaStartedBy<SagaStartingAEvent>,
        IEventHandler<SagaEndingEvent>
    {
        public Guid Id { get; protected set; }
        public bool IsCompleted { get; protected set; }
        public static string Status { get; protected set; }

        private readonly IMicroBus Bus;
        public TestCommandingSaga(IMicroBus bus)
        {
            Bus = bus;
        }

        public async Task Handle(SagaStartingAEvent @event)
        {
            Id = @event.CorrelationId;
            Status = "Started, ";
            await Bus.SendAsync(new EndSaga { CorrelationId = Id });
        }

        public async Task Handle(SagaEndingEvent @event)
        {
            Status += "Finished.";
            IsCompleted = true;
        }
    }

    public class EndSagaCommandHandler : ICommandHandler<EndSaga>
    {
        private readonly IMicroBus Bus;
        public EndSagaCommandHandler(IMicroBus bus)
        {
            Bus = bus;
        }

        public Task Handle(EndSaga command)
        {
            Bus.PublishAsync(new SagaEndingEvent { CorrelationId = command.CorrelationId });
            return Task.CompletedTask;
        }
    }

Thoughts?

InvalidDuplicateRegistrationsException on Handler interface

Hello,
first of not sure if this expected or not, I was moving across some CommandHandlers from another lib to MicroBus.

I intially had code such as this:

public interface IFooHandler : Enexure.MicroBus.ICommandHandler<FooCommand> {} 
public class Foo : IFooHandler {}

which gives the InvalidDuplicateRegistrationsException in the Autofac buildup for FooCommand.
There is only one class that implements the interface.

Changing to below fixes it:

public class Foo : Enexure.MicroBus.ICommandHandler<FooCommand> {}

Should the duplicate registrationError occur for this?

Vulnerability in [email protected] dependency

[email protected] has dependency to [email protected] which has vulnerability: LINK. Please update it to newer version if possible.

Update:
It's because .net standard that is used in this project references [email protected]. At the end of the day, application will use System.Text.RegularExpressions provided by .net SDK installed on the machine. It means that as long as SDK is in newest version there should be no problem, but it would be nice to have this package targeted for the newest LTS .net.

Add interface for a command with result (ICommand<TResult>)

The library has IQuery<in TQuery, out TResult> interface.

There should be a similar version for commands that will allow for a result object ICommand<in TCommand, out TResult>. It should work in similar way as query does.

Purists will argue that commands must not return anything, but there are several good reasons for that:

  • it reduces complexity and simplifies your application, especially when you're not using eventual consistency nor client-generated ids.
  • This information will dramatically improve the user experience of your system, because you don’t have to poll an external source for command execution result, you have it right away. It becomes trivial to validate commands, and to return error messages.
  • If you want to refresh the displayed data, you can use the aggregate’s new version to determine whether the view model reflects the executed command or not. No more displaying stale data.

Example use cases:

  • Return information if record was deleted or not: public class DeleteFoo : ICommand<DeleteFoo, bool>
  • Return number of affected rows: public class DeleteFoos : ICommand<DeleteFoos, int>
  • Return new version number of your aggredate public class ChangeFoo : ICommand<ChangeFoo, int>
  • Return object containing more-verbose result of the operation: public class PerformComplexOperation: ICommand<PerformComplexOperation, OperationResult>
  • Return ID of created object in relational databases: public class CreateFoo: ICommand<CreateFoo, int>

See also: https://vladikk.com/2017/03/20/tackling-complexity-in-cqrs/

How to use with StructureMap

I'm leaning towards Microbus over Mediatr.
The problem is we prefer to use StructureMap and I can't find what I need to make it work with it as all your tutorials speak to Autofac.

I'd appreciate any help getting this work.

Global Handler - with restrictions

Hi Daniel,

I have just taken a look at mediatr and this. Good work btw, your implementation performs really well. It would be useful to be able to define a global handler that is restrictable to specific types, similar to mediatr implementation in their PipelineBehavior.

IPipelineBehavior<ChangeUserAddressData, UserAddressData>), typeof(LoggingBehavior<ChangeUserAddressData, UserAddressData>));

Additionally it would be useful to be able to add an interface on the message handlers, omit or include list of GlobalHandlers that could be passed when registering the handler.

Best,

Ian.

.NET Core 2.1 Exception

In ReflectionExtensions.GetTaskResult typeInfo.GetDeclaredProperty("Result") is returning null causing an exception. This is throwing in the unit tests when targeting netcoreapp2.1 as well.

System.NullReferenceException : Object reference not set to an instance of an object.
   at Enexure.MicroBus.ReflectionExtensions.GetTaskResult(Task task) in C:\Users\andrewm\Downloads\Enexure.MicroBus-master\Enexure.MicroBus-master\src\Enexure.MicroBus\Implementation\ReflectionExtensions.cs:line 57
   at Enexure.MicroBus.PipelineRunBuilder.RunHandlers(IReadOnlyCollection`1 leafHandlerTypes, Object message, CancellationToken cancellation) in C:\Users\andrewm\Downloads\Enexure.MicroBus-master\Enexure.MicroBus-master\src\Enexure.MicroBus\Implementation\PipelineRunBuilder.cs:line 128
   at Enexure.MicroBus.PipelineRunBuilder.<>c__DisplayClass7_0.<<BuildNextHandler>b__0>d.MoveNext() in C:\Users\andrewm\Downloads\Enexure.MicroBus-master\Enexure.MicroBus-master\src\Enexure.MicroBus\Implementation\PipelineRunBuilder.cs:line 84
--- End of stack trace from previous location where exception was thrown ---
   at Enexure.MicroBus.MicroBus.RunPipelineAsync(Object message, CancellationToken cancellation) in C:\Users\andrewm\Downloads\Enexure.MicroBus-master\Enexure.MicroBus-master\src\Enexure.MicroBus\Implementation\MicroBus.cs:line 63
   at Enexure.MicroBus.Autofac.Tests.ScopesAndDisposeTests.InTheDefaultAutofacScopeCommandHandlersShouldFinishBeforeTheScopeIsDisposed() in C:\Users\andrewm\Downloads\Enexure.MicroBus-master\Enexure.MicroBus-master\src\Enexure.MicroBus.Autofac.Tests\ScopesAndDisposeTests.cs:line 101
--- End of stack trace from previous location where exception was thrown ---

Support for .Net 4.5

The update for infrastructure contracts has increase the .net dependency from 4.5 to 4.5.1. Can the support for 4.5 please be re-added, at least to the contracts?

dll unsigned

When I try to download the solution from nuget the assembly is not signed and therefore I get an error when compiling.

Enable Nullable compiler option for safe null checks

Enable Nullable types compiler option allowing code that uses MicroBus to benefit from better static analysis regarding null checks.

This also has the side affect of highlighting any null related issues within MicroBus itself.

ObjectDisposedException when there are two event handlers for the same event and one of them does a send

The code below causes an ObjectDisposedException to be thrown with the message "Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed."

async Task Main()
{
	var builder = new Autofac.ContainerBuilder();
	var busBuilder = new BusBuilder()
		.RegisterHandlers(this.GetType().Assembly);

	builder.RegisterMicroBus(busBuilder);
	using (var container = builder.Build())
	{
		var bus = container.Resolve<IMicroBus>();
		await bus.SendAsync(new TestCommand());
	}
}

class TestCommand : ICommand { }
class TestEvent : IEvent { }
class TestNestedCommand : ICommand { }

class TestCommandHandler : ICommandHandler<TestCommand>
{
	private readonly IMicroBus _bus;
	public TestCommandHandler(IMicroBus bus)
	{
		_bus = bus;
	}
	public async Task Handle(TestCommand command)
	{
		Console.WriteLine("Test command handler");
		await _bus.PublishAsync(new TestEvent());
	}
}

class TestEventHandler : IEventHandler<TestEvent>
{
	private readonly IMicroBus _bus;
	public TestEventHandler(IMicroBus bus)
	{
		_bus = bus;
	}
	public async Task Handle(TestEvent @event)
	{
		Console.WriteLine("Test event handler");
		await _bus.SendAsync(new TestNestedCommand());
	}
}

class TestOtherEventHandler : IEventHandler<TestEvent>
{
	private readonly IMicroBus _bus;
	public TestOtherEventHandler(IMicroBus bus)
	{
		_bus = bus;
	}
	public async Task Handle(TestEvent @event)
	{
		await Task.CompletedTask;
		Console.WriteLine("Test other event handler");
	}
}

class TestNestedCommandHandler : ICommandHandler<TestNestedCommand>
{
	private readonly IMicroBus _bus;
	public TestNestedCommandHandler(IMicroBus bus)
	{
		_bus = bus;
	}
	public async Task Handle(TestNestedCommand command)
	{
		await Task.CompletedTask;
		Console.WriteLine("Test nested command handler");
	}
}

Add support for function based handlers

Registering a handler currently requires you to define a class which implements a handler interface such as ICommandHandler. I would also be useful to register functions and delegates as handlers as well.

var busBuilder = new BusBuilder()
        .RegisterHandler<MessageReceived>(event => { ... });

Retry Logic Documentation

Is there any built-in retry logic?
I am looking for simple mediators where I can publish an event and have multiple subscribers consuming it, and MicroBus seems like a perfect fit for it, so thank you.

But I am exploring scenarios where it would be good to have some kind of retry logic. For example if I have one event A that is supposed to arrive after another event B but for whatever reason in microbus the event B is placed before event A, therefore I could throw an exception when handling event B (because A hasn't been processed yet) and hope to have some retry logic built in with MicroBus so that in the next attempts it eventually succeeds.

If this is a scenario where I could use MicroBus, could you please point me to the right place to explore it? Thanks

Add support for LightInject

Hi Daniel,

I have recently been testing both Microbus and Mediatr in a UWP app, I have only managed to get yours to work...

The UWP app utilizes MvvmLight

It would be good to add LightInject, I have it working with Autofac ok.

Ian

More Examples

First of all, thanks for the project! I like it.

Request though: I'm figuring it out myself and it's well designed -- but more examples would be nice.

Add support type Handler type scanning registration

Currently you have to register each message and handler explicitly. Sometimes it would be nice to auto discover and register handlers in an assembly. Syntax would look something like this.

handlerRegister.RegisterTypes(
    type => type.FullName.Contains("NameSpaceToInclude"),
    somePipeline, 
    someAssembly)

How to register a MicroBus pre-instantiated Handler

Hi.

I'd like to run something like:

            _myPreinitializedService=new UsefulCommandHandler("my default value");
            _myPreinitializedService.DoLongInitialization().Wait();

            // AUTOFAC REGISTRATIONS
            _containerBuilder = new ContainerBuilder();
            _containerBuilder.RegisterInstance(_myPreinitializedService).As<UsefulCommandHandler>();

            // BUS
            var busBuilder = new BusBuilder()
                .RegisterCommandHandler<UsefulCommand, UsefulCommandHandler>();

            var container = _containerBuilder.RegisterMicroBus(busBuilder).Build();

            _bus = container.Resolve<IMicroBus>();

but, since UsefulCommandHandler has only a non default ctor (taking a string MyParameter parameter) whenever I call

_bus.SendAsync(new UsefulCommand());

...I get a:

None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'UsefulCommandHandler' can be invoked with the available services and parameters:
Cannot resolve parameter 'System.String MyParameter' of constructor 'Void .ctor(System.String)'.

Same type resolution before calling:

            // BUS
            var busBuilder = new BusBuilder()
                .RegisterCommandHandler<PingParadoxHostCommand, ParadoxServiceProvider>();

            var container = _containerBuilder.RegisterMicroBus(busBuilder).Build();

            _bus = container.Resolve<IMicroBus>();

...works as expected (i.e. autofac correctly resolves type with my preinitialized instance).

What is the proper way to do it?

Thanks!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.