Skip to content

Instantly share code, notes, and snippets.

@jdaigle
Created March 5, 2012 16:39
Show Gist options
  • Save jdaigle/1979180 to your computer and use it in GitHub Desktop.
Save jdaigle/1979180 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Clearwave.ServiceBus {
public class MessageHandlerCollection {
private readonly static Type messageHandlerOpenGenericType = typeof(IMessageHandler<>);
private IDictionary<Type, ISet<DispatchInfo>> messageHandlers = new Dictionary<Type, ISet<DispatchInfo>>();
public static IList<Type> FindAllMessageTypes(IEnumerable<Assembly> messageHandlerAssemblies) {
// Get all types that are used to close the generic type IMessageHandler<>
var types = new List<Type>();
foreach (var assembly in messageHandlerAssemblies) {
types.AddRange(assembly.GetTypes()
.WhereMessageHandlerType()
.SelectMany(x => x.GetInterfaces().Where(i => i.IsGenericType &&
i.GetGenericTypeDefinition() == messageHandlerOpenGenericType)
.Select(i => i.GetGenericArguments().FirstOrDefault())));
}
return types.Distinct().ToList();
}
public static IList<Type> FindMessageHandlers(Type messageType, IEnumerable<Assembly> messageHandlerAssemblies) {
// Find every message handler type
var messageHandlerTypes = messageHandlerAssemblies
.SelectMany(a => a.GetTypes()
.WhereMessageHandlerType()
.Where(t => t.GetInterfaces().Any(i => i.IsGenericType &&
i.GetGenericTypeDefinition() == messageHandlerOpenGenericType &&
i.GetGenericArguments().FirstOrDefault().IsAssignableFrom(messageType))));
return messageHandlerTypes.ToList();
}
public void ExecuteTheseHandlersFirst(params Type[] handlerTypes) {
foreach (var messageType in messageHandlers.Keys.ToList()) {
var handlers = messageHandlers[messageType];
var firstOrderedHandlers = new HashSet<DispatchInfo>();
foreach (var handler in handlerTypes) {
var firstOrderedHandler = handlers.FirstOrDefault(x => handler.IsAssignableFrom(x.InstanceType));
if (firstOrderedHandler != null && !firstOrderedHandlers.Contains(firstOrderedHandler)) {
firstOrderedHandlers.Add(firstOrderedHandler);
}
}
messageHandlers[messageType] = new HashSet<DispatchInfo>(firstOrderedHandlers.Concat(handlers.Except(firstOrderedHandlers)));
}
}
public void RegisterDispatchHandler(Type messageType, IEnumerable<Assembly> messageHandlerAssemblies) {
// Find every message handler type
var messageHandlerTypes = FindMessageHandlers(messageType, messageHandlerAssemblies);
// Add the dispatch info for each message handler
foreach (var instanceType in messageHandlerTypes) {
if (!messageHandlers.ContainsKey(messageType)) messageHandlers.Add(messageType, new HashSet<DispatchInfo>());
foreach (var methodInfo in instanceType.GetMethods().Where(x => x.GetParameters().Count() == 1 &&
x.GetParameters().Single().ParameterType.IsAssignableFrom(messageType))) {
if (messageHandlers[messageType].Any(x => x.MessageType == messageType && x.InstanceType == instanceType && x.MethodInfo == methodInfo)) continue;
messageHandlers[messageType].Add(new DispatchInfo(messageType, instanceType, methodInfo));
}
}
}
public void RegisterDispatchHandler(IEnumerable<Type> messageTypes, IEnumerable<Assembly> messageHandlerAssemblies) {
foreach (var messageType in messageTypes) {
RegisterDispatchHandler(messageType, messageHandlerAssemblies);
}
}
public void RegisterDispatchHandler(IEnumerable<Assembly> messageHandlerAssemblies) {
RegisterDispatchHandler(FindAllMessageTypes(messageHandlerAssemblies), messageHandlerAssemblies);
}
public void RegisterDispatchHandler(params Assembly[] messageHandlerAssemblies) {
RegisterDispatchHandler((IEnumerable<Assembly>)messageHandlerAssemblies);
}
public void RegisterDispatchHandler(Assembly messageHandlerAssembly) {
RegisterDispatchHandler(new[] { messageHandlerAssembly });
}
public IEnumerable<Type> AllTypes() {
return messageHandlers.Keys;
}
public IEnumerable<DispatchInfo> OrderedHandlersFor(Type messageType) {
if (messageHandlers.ContainsKey(messageType)) {
return messageHandlers[messageType];
} else {
return new DispatchInfo[0];
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment