Last active
July 22, 2017 13:36
-
-
Save philipmat/abaab9acc8d15867a5d7c80b69011fdc to your computer and use it in GitHub Desktop.
Simple Message Routing: Static vs Dynamic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Query Kind="Program"> | |
<NuGetReference>Autofac</NuGetReference> | |
<Namespace>Autofac</Namespace> | |
</Query> | |
void Main() | |
{ | |
var facker = Configure(); | |
// example 1 | |
var controller1 = facker.Resolve<ControllerOne>(); | |
controller1.DoFoo(); | |
controller1.DoBar(); | |
// example 2 | |
var controller2 = facker.Resolve<ControllerTwo>(); | |
controller2.DoFoo(); | |
controller2.DoBar(); | |
// example 3 | |
var controller3 = facker.Resolve<ControllerThree>(); | |
controller3.DoFoo(); | |
controller3.DoBar(); | |
} | |
// Define other methods and classes here | |
private IContainer Configure() | |
{ | |
var builder = new ContainerBuilder(); | |
builder.RegisterType<FooMessageHandler>() | |
.As<IMessageHandler<FooMessage>>() | |
.As<IMessageHandler<IMessage>>(); | |
builder.RegisterType<BarMessageHandler>() | |
.As<IMessageHandler<BarMessage>>() | |
.As<IMessageHandler<IMessage>>(); | |
builder.RegisterType<DynamicHandler>(); | |
builder.RegisterType<StaticHandler>(); | |
builder.RegisterType<ControllerOne>(); | |
builder.RegisterType<ControllerTwo>(); | |
builder.RegisterType<ControllerThree>(); | |
return builder.Build(); | |
} | |
/// <summary>Gets injected with specific handlers.</summary> | |
public class ControllerOne | |
{ | |
private IMessageHandler<FooMessage> _fooHandler; | |
private IMessageHandler<BarMessage> _barHandler; | |
public ControllerOne(IMessageHandler<FooMessage> fooHandler, IMessageHandler<BarMessage> barHandler) | |
{ | |
_fooHandler = fooHandler; _barHandler = barHandler; | |
} | |
public void DoFoo() | |
{ | |
var foo = new FooMessage { Id = 101 }; | |
_fooHandler.Handle(foo); | |
} | |
public void DoBar() | |
{ | |
var message = new BarMessage { Marker = "fortytwo" }; | |
_barHandler.Handle(message); | |
} | |
} | |
/// <summary>Gets injected with a dynamic handler</summary> | |
public class ControllerTwo | |
{ | |
protected IMessageHandler _handler; | |
public ControllerTwo(DynamicHandler handler) : this((IMessageHandler) handler) {} | |
protected ControllerTwo(IMessageHandler handler) | |
{ | |
_handler = handler; | |
} | |
public void DoFoo() | |
{ | |
var foo = new FooMessage { Id = 101 }; | |
_handler.Handle(foo); | |
} | |
public void DoBar() | |
{ | |
var message = new BarMessage { Marker = "fortytwo" }; | |
_handler.Handle(message); | |
} | |
} | |
/// <summary>Gets injected with a static handler, but otherwise uses C2</summary> | |
public class ControllerThree : ControllerTwo | |
{ | |
public ControllerThree(StaticHandler handler) : base((IMessageHandler) handler) | |
{ | |
_handler = handler; | |
} | |
} | |
public interface IMessage | |
{ | |
string Name { get; } | |
} | |
public class FooMessage : IMessage { | |
public string Name => "Foo"; | |
public long Id { get; set; } | |
} | |
public class BarMessage : IMessage | |
{ | |
public string Name => "Bar"; | |
public string Marker { get; set; } | |
} | |
public interface IMessageHandler | |
{ | |
void Handle(IMessage message); | |
} | |
public interface IMessageHandler<T> : IMessageHandler where T : IMessage { } | |
public abstract class MessageDispatcher<T> : IMessageHandler<T> | |
where T : IMessage | |
{ | |
public void Handle(IMessage message) | |
{ | |
$"Received {message.Name}.".Dump("MessageDispatcher<>"); | |
InnerHandle((T) message); | |
} | |
protected abstract void InnerHandle(T message); | |
} | |
public class FooMessageHandler : MessageDispatcher<FooMessage>, IMessageHandler<IMessage> | |
{ | |
protected override void InnerHandle(FooMessage message) | |
{ | |
$"Got {message.Name}: {message.Id}".Dump(nameof(FooMessageHandler)); | |
} | |
} | |
public class BarMessageHandler : MessageDispatcher<BarMessage>, IMessageHandler<IMessage> | |
{ | |
protected override void InnerHandle(BarMessage message) | |
{ | |
$"Got {message.Name}: {message.Marker}".Dump(nameof(BarMessageHandler)); | |
} | |
} | |
/// <summary>Dynamically constructs handlers based on the underlying message type</summary> | |
public class DynamicHandler : IMessageHandler | |
{ | |
ILifetimeScope _injector; | |
public DynamicHandler(ILifetimeScope injector) | |
{ | |
_injector = injector; | |
} | |
public void Handle(IMessage message) | |
{ | |
$"Dynamically handling: {message.Name}.".Dump(nameof(DynamicHandler)); | |
Type messageType = message.GetType(); // reports actually type, e.g. FooMessage | |
using (var scope = _injector.BeginLifetimeScope()) | |
{ | |
Type handlerType = typeof(IMessageHandler<>).MakeGenericType(messageType); | |
var handler = scope.Resolve(handlerType) as IMessageHandler; | |
handler.Handle(message); | |
} | |
} | |
} | |
/// <summary>Loops through defined message handlers to find one whose underlying type matches the message type.</summary> | |
public class StaticHandler : IMessageHandler | |
{ | |
private IEnumerable<IMessageHandler<IMessage>> _handlers; | |
public StaticHandler(IEnumerable<IMessageHandler<IMessage>> handlers) | |
{ | |
_handlers = handlers; | |
} | |
public void Handle(IMessage message) | |
{ | |
$"Statically handling: {message.Name}.".Dump(nameof(StaticHandler)); | |
Type messageType = message.GetType(); // reports actually type, e.g. FooMessage | |
foreach (var handler in _handlers) | |
{ | |
Type[] handlerInterfaceTypes = handler.GetType().GetInterfaces(); | |
foreach (var interfaceType in handlerInterfaceTypes.Where(it => it.IsGenericType)) | |
{ | |
if (interfaceType.GetGenericArguments().Any(arg => arg == messageType)) | |
{ | |
handler.Handle(message); | |
return; | |
} | |
} | |
} | |
} | |
} |
Updated with a static handler, which is more faster, but clunky-er and consumes a lot more memory as all the handlers are instantiated prior to StaticHandler construction
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Output