Skip to content

Class DistributedEventsDiscovery

Namespace: Momentum.ServiceDefaults.Messaging
Assembly: Momentum.ServiceDefaults.dll

csharp
public static class DistributedEventsDiscovery

Inheritance

objectDistributedEventsDiscovery

Inherited Members

object.GetType(), object.MemberwiseClone(), object.ToString(), object.Equals(object?), object.Equals(object?, object?), object.ReferenceEquals(object?, object?), object.GetHashCode()

Methods

GetIntegrationEventTypes()

Discovers and retrieves types that represent integration event types within the application's domain assemblies.

csharp
public static IEnumerable<Type> GetIntegrationEventTypes()

Returns

IEnumerable<Type>

Remarks

Distributed Events Discovery

Local Domain Discovery

This only applies to "local" domain assemblies

The discovery process identifies integration event types within application domain assemblies by:

  1. Assembly Selection: Gathering domain assemblies and the entry assembly
  2. Namespace Filtering: Looking for types in namespaces ending with .IntegrationEvents
  3. Domain Prefix Matching: Ensuring events belong to the same domain context

Assembly Resolution Process

csharp
Assembly[] appAssemblies = [.. DomainAssemblyAttribute.GetDomainAssemblies(), ServiceDefaultsExtensions.EntryAssembly];

var domainPrefixes = appAssemblies
    .Select(a => a.GetName().Name)
    .Where(assemblyName => assemblyName is not null)
    .Select(assemblyName =>
    {
        var mainNamespaceIndex = assemblyName!.IndexOf('.');
        return mainNamespaceIndex >= 0 ? assemblyName[..mainNamespaceIndex] : assemblyName;
    })
    .ToHashSet();

Domain-Scoped Discovery

The method filters assemblies to only include those belonging to the same domain:

csharp
var domainAssemblies = AppDomain.CurrentDomain.GetAssemblies()
    .Where(assembly =>
    {
        var name = assembly.GetName().Name;
        return name is not null && domainPrefixes.Any(prefix => name.StartsWith(prefix));
    })
    .ToArray();

Handler-Associated Events Discovery

This method identifies distributed events by analyzing handler method parameters and ensures that only events with corresponding handlers are included.

Handler Method Discovery

The discovery process examines all handler methods across domain assemblies:

csharp
Assembly[] handlerAssemblies = [.. DomainAssemblyAttribute.GetDomainAssemblies(), ServiceDefaultsExtensions.EntryAssembly];

var candidateHandlers = handlerAssemblies
    .SelectMany(assembly => assembly.GetTypes())
    .Where(type => type is { IsClass: true })
    .SelectMany(type => type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static));

Handler Method Identification

Methods are identified as handlers based on naming conventions:

  • Handle, HandleAsync
  • Handles, HandlesAsync
  • Consume, ConsumeAsync
  • Consumes, ConsumesAsync
csharp
private static readonly HashSet<string> HandlerMethodNames = new(StringComparer.OrdinalIgnoreCase)
{
    HandlerChain.Handle,
    HandlerChain.Handle + Async,
    HandlerChain.Handles,
    HandlerChain.Handles + Async,
    HandlerChain.Consume,
    HandlerChain.Consume + Async,
    HandlerChain.Consumes,
    HandlerChain.Consumes + Async
};

Parameter Analysis

For each valid handler method, parameters are analyzed to extract integration event types:

csharp
var integrationEvents = handlerMethods.SelectMany(method =>
    method.GetParameters()
        .Select(parameter => parameter.ParameterType)
        .Where(IsIntegrationEventType)
).ToHashSet();

Integration Event Type Identification

Namespace-Based Detection

Integration events are identified by their namespace pattern:

csharp
private static bool IsIntegrationEventType(Type messageType) => 
    messageType.Namespace?.EndsWith(IntegrationEventsNamespace) == true;

Where IntegrationEventsNamespace is .IntegrationEvents.

Domain Boundary Enforcement

This approach ensures that:

  • Local Events Only: Only events from the same domain are discovered
  • Handler Coupling: Events are only included if they have corresponding handlers
  • Namespace Convention: Enforces consistent namespace organization
  • Type Safety: Compile-time validation of event-handler relationships

Future Improvements

Source Generation

The discovery process could be optimized using source generation:

csharp
// TODO: Use source generation in the future for this
private static IEnumerable<MethodInfo> GetHandlerMethods()

Source generation would provide:

  • Compile-time Discovery: Pre-computed event-handler mappings
  • Performance Optimization: Elimination of runtime reflection
  • Build-time Validation: Early detection of missing handlers
  • Code Generation: Automatic registration of discovered types

GetIntegrationEventTypesWithHandlers()

Discovers and retrieves types that represent integration event types, focusing specifically on those that have associated handlers.

csharp
public static IEnumerable<Type> GetIntegrationEventTypesWithHandlers()

Returns

IEnumerable<Type>

Remarks

Distributed Events Discovery

Local Domain Discovery

This only applies to "local" domain assemblies

The discovery process identifies integration event types within application domain assemblies by:

  1. Assembly Selection: Gathering domain assemblies and the entry assembly
  2. Namespace Filtering: Looking for types in namespaces ending with .IntegrationEvents
  3. Domain Prefix Matching: Ensuring events belong to the same domain context

Assembly Resolution Process

csharp
Assembly[] appAssemblies = [.. DomainAssemblyAttribute.GetDomainAssemblies(), ServiceDefaultsExtensions.EntryAssembly];

var domainPrefixes = appAssemblies
    .Select(a => a.GetName().Name)
    .Where(assemblyName => assemblyName is not null)
    .Select(assemblyName =>
    {
        var mainNamespaceIndex = assemblyName!.IndexOf('.');
        return mainNamespaceIndex >= 0 ? assemblyName[..mainNamespaceIndex] : assemblyName;
    })
    .ToHashSet();

Domain-Scoped Discovery

The method filters assemblies to only include those belonging to the same domain:

csharp
var domainAssemblies = AppDomain.CurrentDomain.GetAssemblies()
    .Where(assembly =>
    {
        var name = assembly.GetName().Name;
        return name is not null && domainPrefixes.Any(prefix => name.StartsWith(prefix));
    })
    .ToArray();

Handler-Associated Events Discovery

This method identifies distributed events by analyzing handler method parameters and ensures that only events with corresponding handlers are included.

Handler Method Discovery

The discovery process examines all handler methods across domain assemblies:

csharp
Assembly[] handlerAssemblies = [.. DomainAssemblyAttribute.GetDomainAssemblies(), ServiceDefaultsExtensions.EntryAssembly];

var candidateHandlers = handlerAssemblies
    .SelectMany(assembly => assembly.GetTypes())
    .Where(type => type is { IsClass: true })
    .SelectMany(type => type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static));

Handler Method Identification

Methods are identified as handlers based on naming conventions:

  • Handle, HandleAsync
  • Handles, HandlesAsync
  • Consume, ConsumeAsync
  • Consumes, ConsumesAsync
csharp
private static readonly HashSet<string> HandlerMethodNames = new(StringComparer.OrdinalIgnoreCase)
{
    HandlerChain.Handle,
    HandlerChain.Handle + Async,
    HandlerChain.Handles,
    HandlerChain.Handles + Async,
    HandlerChain.Consume,
    HandlerChain.Consume + Async,
    HandlerChain.Consumes,
    HandlerChain.Consumes + Async
};

Parameter Analysis

For each valid handler method, parameters are analyzed to extract integration event types:

csharp
var integrationEvents = handlerMethods.SelectMany(method =>
    method.GetParameters()
        .Select(parameter => parameter.ParameterType)
        .Where(IsIntegrationEventType)
).ToHashSet();

Integration Event Type Identification

Namespace-Based Detection

Integration events are identified by their namespace pattern:

csharp
private static bool IsIntegrationEventType(Type messageType) => 
    messageType.Namespace?.EndsWith(IntegrationEventsNamespace) == true;

Where IntegrationEventsNamespace is .IntegrationEvents.

Domain Boundary Enforcement

This approach ensures that:

  • Local Events Only: Only events from the same domain are discovered
  • Handler Coupling: Events are only included if they have corresponding handlers
  • Namespace Convention: Enforces consistent namespace organization
  • Type Safety: Compile-time validation of event-handler relationships

Future Improvements

Source Generation

The discovery process could be optimized using source generation:

csharp
// TODO: Use source generation in the future for this
private static IEnumerable<MethodInfo> GetHandlerMethods()

Source generation would provide:

  • Compile-time Discovery: Pre-computed event-handler mappings
  • Performance Optimization: Elimination of runtime reflection
  • Build-time Validation: Early detection of missing handlers
  • Code Generation: Automatic registration of discovered types