You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

118 lines
4.3 KiB

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using DotNetCore.CAP.Internal;
  6. using Microsoft.Extensions.DependencyInjection;
  7. using Microsoft.Extensions.Options;
  8. namespace DotNetCore.CAP.Test
  9. {
  10. /// <summary>
  11. /// Allows caller to supply subscribe interface and attribute when adding services.
  12. /// </summary>
  13. /// <typeparam name="TSubscriber"></typeparam>
  14. /// <typeparam name="TSubscriptionAttribute"></typeparam>
  15. public class GenericConsumerServiceSelector<TSubscriber, TSubscriptionAttribute> : ConsumerServiceSelector
  16. where TSubscriptionAttribute : Attribute, INamedGroup
  17. {
  18. private readonly CapOptions _capOptions;
  19. public GenericConsumerServiceSelector(IServiceProvider serviceProvider)
  20. : base(serviceProvider)
  21. {
  22. _capOptions = serviceProvider.GetRequiredService<IOptions<CapOptions>>().Value;
  23. }
  24. /// <inheritdoc cref="ConsumerServiceSelector"/>
  25. protected override IEnumerable<ConsumerExecutorDescriptor> FindConsumersFromInterfaceTypes(IServiceProvider provider)
  26. {
  27. var executorDescriptorList = new List<ConsumerExecutorDescriptor>();
  28. using (var scoped = provider.CreateScope())
  29. {
  30. var scopedProvider = scoped.ServiceProvider;
  31. var subscribers = scopedProvider.GetServices<TSubscriber>();
  32. var subscriberTypeInfo = typeof(TSubscriber).GetTypeInfo();
  33. foreach (var service in subscribers)
  34. {
  35. var serviceTypeInfo = service?.GetType().GetTypeInfo();
  36. if (serviceTypeInfo == null || !subscriberTypeInfo.IsAssignableFrom(serviceTypeInfo))
  37. {
  38. continue;
  39. }
  40. var descriptors = _GetDescriptors(serviceTypeInfo);
  41. executorDescriptorList.AddRange(descriptors);
  42. }
  43. return executorDescriptorList;
  44. }
  45. }
  46. private IEnumerable<ConsumerExecutorDescriptor> _GetDescriptors(TypeInfo typeInfo)
  47. {
  48. foreach (var method in typeInfo.DeclaredMethods)
  49. {
  50. var topicAttr = method.GetCustomAttributes<TSubscriptionAttribute>(true);
  51. var topicAttributes = topicAttr as IList<TSubscriptionAttribute> ?? topicAttr.ToList();
  52. if (!topicAttributes.Any())
  53. {
  54. continue;
  55. }
  56. foreach (var attr in topicAttributes)
  57. {
  58. _SetAttributeGroup(attr);
  59. yield return new ConsumerExecutorDescriptor
  60. {
  61. Attribute = new CapSubscribeAttribute(attr.Name)
  62. {
  63. Group = attr.Group
  64. },
  65. MethodInfo = method,
  66. ImplTypeInfo = typeInfo,
  67. TopicNamePrefix = _capOptions.TopicNamePrefix,
  68. Parameters = _GetParameterDescriptors(method)
  69. };
  70. }
  71. }
  72. }
  73. private void _SetAttributeGroup(TSubscriptionAttribute attr)
  74. {
  75. if (attr.Group == null)
  76. {
  77. attr.Group = _capOptions.DefaultGroupName + "." + _capOptions.Version;
  78. }
  79. else
  80. {
  81. attr.Group = attr.Group + "." + _capOptions.Version;
  82. }
  83. if (!string.IsNullOrEmpty(_capOptions.GroupNamePrefix))
  84. {
  85. attr.Group = $"{_capOptions.GroupNamePrefix}.{attr.Group}";
  86. }
  87. }
  88. private IList<ParameterDescriptor> _GetParameterDescriptors(MethodInfo method)
  89. {
  90. var descriptors = method.GetParameters().Select(p => new ParameterDescriptor()
  91. {Name = p.Name, ParameterType = p.ParameterType, IsFromCap = p.GetCustomAttributes<FromCapAttribute>().Any()});
  92. return new List<ParameterDescriptor>(descriptors.ToArray());
  93. }
  94. }
  95. /// <summary>
  96. /// Implementers have a name and a group.
  97. /// </summary>
  98. public interface INamedGroup
  99. {
  100. string Name { get; }
  101. string Group { get; set; }
  102. }
  103. }