routemeister icon indicating copy to clipboard operation
routemeister copied to clipboard

Null returned from message creator is not handled

Open cpx86 opened this issue 7 years ago • 4 comments

If a message creator returns a null value, Routemeister will still invoke the handler method but with a null reference for the handler instance. This is technically allowed by reflection, but not correct and leads to some unexpected behaviors. A realistic case where this might happen is if you plugin a container that returns default values instead of throwing exceptions when it can't resolve a type.

I've gone through the code and adding a simple null-check seems to be trivial and should hardly have any performance impact. Would you be interested in a PR?

Here's a simple repro:

void Main()
{
    var factory = new MessageRouteFactory();
    var routes = new MessageRoutes
    {
        factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IHandle<>))
    };
    var router = new SequentialAsyncRouter((t, e) => null, routes);

    router.RouteAsync("hello");
}

interface IHandle<T>
{
    Task HandleAsync(T message);
}

public class StringHandler : IHandle<string>
{
    public Task HandleAsync(string message)
    {
        Console.WriteLine(this.ToString()); // this is null
        return Task.CompletedTask;
    }
}

cpx86 avatar Oct 17 '17 12:10 cpx86

That sounds fair. I'll gladly accept "something" preventing it from accepting null handlers being resolved.

On 17 Oct 2017 14:11, "Christian Palmstierna" [email protected] wrote:

If a message creator returns a null value, Routemeister will still invoke the handler method but with a null reference for the handler instance. This is technically allowed by reflection, but not correct and leads to some unexpected behaviors. A realistic case where this might happen is if you plugin a container that returns default values instead of throwing exceptions when it can't resolve a type.

I've gone through the code and adding a simple null-check seems to be trivial and should hardly have any performance impact. Would you be interested in a PR?

Here's a simple repro:

void Main() { var factory = new MessageRouteFactory(); var routes = new MessageRoutes { factory.Create(new[] {GetType().GetTypeInfo().Assembly}, typeof (IHandle<>)) }; var router = new SequentialAsyncRouter((t, e) => null, routes);

router.RouteAsync("hello"); } interface IHandle<T> { Task HandleAsync(T message); } public class StringHandler : IHandle { public Task HandleAsync(string message) { Console.WriteLine(this.ToString()); // this is null here return Task.CompletedTask; } }

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/danielwertheim/routemeister/issues/8, or mute the thread https://github.com/notifications/unsubscribe-auth/AAL9zCqgctDWOMQ-Q0yo29RtPBko-LsFks5stJmAgaJpZM4P8C_J .

danielwertheim avatar Oct 17 '17 14:10 danielwertheim

I was thinking to throw InvalidOperationException if the handler is null. Sound good?

One question about the publish methods - should it resolve all handlers first and validate them before attempting to execute them? Also, slightly off topic, but currently if one handler throws an exception then subsequent handlers will not be executed. Is that by design?

cpx86 avatar Oct 18 '17 09:10 cpx86

Regarding the subsequent handlers, yes, the router and dispatchers are pretty dumb by intention. The idea would be to either create a more advanced using the Routes and contribute if it makes sense. And just to be an in-memory routing/dispatching solution.

Regarding InvalidOperationException, sounds fair.

The pre-resolving sounds nice, but not sure if they should be re-used. Thinking the strategy of lifetime of a handler is up to the creator, but I guess it's fair to think "per-message".

Now to a bit of.... The same goes for Dispatcher(s) which doesn't use the router under the hood. This should probably be taken care of in a separate PR/Issue.

danielwertheim avatar Oct 18 '17 19:10 danielwertheim

No, it's probably better not to re-use them. Was just thinking that it could make sense to first ensure all handlers can actually be resolved before executing any of them.

I'll prepare a PR for this issue now then.

cpx86 avatar Oct 20 '17 11:10 cpx86