rebus-org / Rebus.StructureMap

:x: DEPRECATED :bus: StructureMap container adapter for Rebus
https://mookid.dk/category/rebus
Other
3 stars 2 forks source link

Polymorphic dispatch misbehaves #1

Closed mookid8000 closed 4 years ago

mookid8000 commented 7 years ago

SM seems to resolve only the first matching instance when calling GetAllInstances on IHandleMessages<TMessage> (which is contravariant).

Variance seems to be respected allright, it's just returning one single instance always, even though multiple matches are registered in the container.

Original discussion here

mitchmchenry commented 7 years ago

I've been playing with the new code and it now seems to find all the polymorphic handlers. Very nice!

However, it's adding the same handler multiple times. In my original example, the handler that implements IHandleMessages<ISomeInterface> is getting called 4 times for the same message. I'm guessing it has something to do with the inheritance going on with the handlers in my project.

In StructureMapContainerAdapter.GetHandlers() in the SelectMany() loop, 4 instances of the same handler end up getting added to the result. It looks like the code tries to account for this with a Distinct() at the very end, but with the default comparer, the 4 instances are distinct. I used a custom EqualityComparer to match on GetType().FullName instead and that seemed to do the trick.

I didn't actually write a comparer myself. I just pasted this in and changed the Distinct() to .Distinct(handler => handler.GetType().FullName) and it worked - one instance of each handler type.

mookid8000 commented 7 years ago

I have changed the StructureMap container adapter implementation to expect StructureMap to work the way it is advertised.

However, it still returns only one single handler in the contract test that expects two handlers to be returned.

Having looked at the StructureMap codebase (specifically having looked at the GenericVarianceResolution test) it seems like it is possible to get it to work as it should by relying on SM's assembly scanning and auto-wiring capabilities.

I don't know enough about SM though to be able to determine whether it's simply a matter of registering Rebus handlers in the right way.

mitchmchenry commented 7 years ago

I did some more digging and it seems like this gets us really close: var instances = _container.Model.GetAllPossible<IHandleMessages<TMessage>>().ToList();

That will find both handlers we're expecting, but for some reason both are included twice in the results (two instances of each handler). I suppose the .Distinct(handler => handler.GetType().FullName) hack would work here too, but it sure would be nice to understand why it's needed.

mookid8000 commented 7 years ago

for some reason both are included twice in the results

huh? that's weird!

mitchmchenry commented 7 years ago

Yeah, it certainly seems like an incorrect behavior, but I'm definitely not an expert on the deeper guts of SM. I assume it has something to do with the several levels of inheritance and interfaces used by the handlers in question, but that's a total guess.

Did you try replacing _container.GetAllInstances<IHandleMessages<TMessage>>() with _container.Model.GetAllPossible<IHandleMessages<TMessage>>() in StructureMapContainerAdapter.GetHandlers()? Just curious what your results were.

mookid8000 commented 4 years ago

For anyone who happens to come by this issue: It's solved in Rebus.StructureMap 5.0.1, which is available on NuGet.org now. 🙂

Also: Wow, @mitchmchenry , your suggestion seems to have solved the problem!