RequestHandlerModule.cs 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. using System.Reflection;
  2. namespace RunnersMeet.Server;
  3. public class RequestHandlerModule : IAppConfigurationModule
  4. {
  5. public void ConfigureServices(IServiceCollection services, IConfigurationRoot config)
  6. {
  7. services.AddScoped<IRequestRouter, RequestRouter>();
  8. Register(services, new List<HandlerMatcher>
  9. {
  10. // More specific first, then fall back to more general
  11. new HandlerMatcher(typeof(IRequestHandler<,,>)),
  12. new HandlerMatcher(typeof(IRequestHandler<,>)),
  13. });
  14. }
  15. public void ConfigureApplication(WebApplication app)
  16. {
  17. }
  18. private void Register(IServiceCollection services, IList<HandlerMatcher> matchers)
  19. {
  20. foreach (var candidate in Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsClass))
  21. {
  22. var matcher = matchers.FirstOrDefault(m => m.IsMatch(candidate));
  23. if (matcher != null)
  24. {
  25. foreach (var handlerInterface in matcher.GetHandlerInterfaces(candidate))
  26. {
  27. services.AddScoped(handlerInterface, candidate);
  28. }
  29. }
  30. }
  31. }
  32. private sealed class HandlerMatcher
  33. {
  34. private readonly Type _genericInterfaceType;
  35. public HandlerMatcher(Type genericInterfaceType)
  36. {
  37. _genericInterfaceType = genericInterfaceType;
  38. }
  39. public bool IsMatch(Type t) => t.GetInterfaces().Any(i => ImplementsExactly(i, _genericInterfaceType));
  40. public IEnumerable<Type> GetHandlerInterfaces(Type t) => t.GetInterfaces().Where(i => ImplementsExactly(i, _genericInterfaceType));
  41. private static bool ImplementsExactly(Type candidate, Type genericInterface)
  42. {
  43. if (!candidate.IsGenericType)
  44. {
  45. return false;
  46. }
  47. var genericTypeDefinition = candidate.GetGenericTypeDefinition();
  48. return /*genericTypeDefinition.GenericTypeArguments.Length == genericInterface.GenericTypeArguments.Length
  49. &&*/ genericTypeDefinition == genericInterface;
  50. }
  51. }
  52. }