Skip to content

Commit

Permalink
decent textual representation of handler discovery rules in describe …
Browse files Browse the repository at this point in the history
…output. Closes GH-236
  • Loading branch information
Jeremy D. Miller authored and Jeremy D. Miller committed Mar 17, 2023
1 parent 81bbb45 commit dbe4880
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 38 deletions.
5 changes: 2 additions & 3 deletions src/Samples/OrderSagaSample/OrderSagaSample.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Persistence\Wolverine.Marten\Wolverine.Marten.csproj"/>
<PackageReference Include="LamarCodeGeneration.Commands" Version="6.2.0"/>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3"/>
<ProjectReference Include="..\..\Persistence\Wolverine.Marten\Wolverine.Marten.csproj" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>

</Project>
12 changes: 6 additions & 6 deletions src/Wolverine/Configuration/HandlerDiscovery.Diagnostics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ internal string DescribeHandlerMatch(WolverineOptions options, Type candidateTyp
}

bool typeNotFound = false;
if (!_handlerQuery.Includes.Matches(candidateType))
if (!HandlerQuery.Includes.Matches(candidateType))
{
writeTypeIncludeMiss(candidateType, writer);
typeNotFound = true;
}

if (_handlerQuery.Excludes.Matches(candidateType))
if (HandlerQuery.Excludes.Matches(candidateType))
{
writeTypeExcludeMatch(candidateType, writer);
typeNotFound = true;
Expand All @@ -57,7 +57,7 @@ internal string DescribeHandlerMatch(WolverineOptions options, Type candidateTyp
{
writer.WriteLine($"Method: {method.Name}({method.GetParameters().Select(x => x.ParameterType.ShortNameInCode()).Join(", ")})" );

foreach (var filter in _methodIncludes)
foreach (var filter in MethodIncludes)
{
if (filter.Matches(method))
{
Expand All @@ -69,7 +69,7 @@ internal string DescribeHandlerMatch(WolverineOptions options, Type candidateTyp
}
}

foreach (var filter in _methodExcludes)
foreach (var filter in MethodExcludes)
{
if (filter.Matches(method))
{
Expand All @@ -90,7 +90,7 @@ internal string DescribeHandlerMatch(WolverineOptions options, Type candidateTyp

private void writeTypeExcludeMatch(Type candidateType, StringWriter writer)
{
foreach (var filter in _handlerQuery.Excludes)
foreach (var filter in HandlerQuery.Excludes)
{
if (filter.Matches(candidateType))
{
Expand All @@ -105,7 +105,7 @@ private void writeTypeExcludeMatch(Type candidateType, StringWriter writer)

private void writeTypeIncludeMiss(Type candidateType, StringWriter writer)
{
foreach (var filter in _handlerQuery.Includes)
foreach (var filter in HandlerQuery.Includes)
{
if (filter.Matches(candidateType))
{
Expand Down
56 changes: 29 additions & 27 deletions src/Wolverine/Configuration/HandlerDiscovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ public sealed partial class HandlerDiscovery
{
private readonly IList<Type> _explicitTypes = new List<Type>();

private readonly CompositeFilter<MethodInfo> _methodIncludes = new();
private readonly CompositeFilter<MethodInfo> _methodExcludes = new();

private readonly string[] _validMethods =
{
HandlerChain.Handle, HandlerChain.Handles, HandlerChain.Consume, HandlerChain.Consumes, SagaChain.Orchestrate,
Expand All @@ -25,7 +22,6 @@ public sealed partial class HandlerDiscovery

private bool _conventionalDiscoveryDisabled;

private readonly TypeQuery _handlerQuery = new(TypeClassification.Concretes | TypeClassification.Closed);
private readonly TypeQuery _messageQuery = new(TypeClassification.Concretes | TypeClassification.Closed);

public HandlerDiscovery()
Expand All @@ -40,48 +36,54 @@ public HandlerDiscovery()
_messageQuery.Excludes.IsNotPublic();
}

internal CompositeFilter<MethodInfo> MethodIncludes { get; } = new();

internal CompositeFilter<MethodInfo> MethodExcludes { get; } = new();

private void specifyHandlerMethodRules()
{
foreach (var methodName in _validMethods)
{
_methodIncludes.WithCondition($"Method name is '{methodName}' (case sensitive)", m => m.Name == methodName);
MethodIncludes.WithCondition($"Method name is '{methodName}' (case sensitive)", m => m.Name == methodName);

var asyncName = methodName + "Async";
_methodIncludes.WithCondition($"Method name is '{asyncName}' (case sensitive)", m => m.Name == asyncName);
MethodIncludes.WithCondition($"Method name is '{asyncName}' (case sensitive)", m => m.Name == asyncName);
}

_methodIncludes.WithCondition("Has attribute [WolverineHandler]", m => m.HasAttribute<WolverineHandlerAttribute>());
MethodIncludes.WithCondition("Has attribute [WolverineHandler]", m => m.HasAttribute<WolverineHandlerAttribute>());

_methodExcludes.WithCondition("Method is declared by object", method => method.DeclaringType == typeof(object));
_methodExcludes.WithCondition("IDisposable.Dispose()", method => method.Name == nameof(IDisposable.Dispose));
_methodExcludes.WithCondition("IAsyncDisposable.DisposeAsync()",
MethodExcludes.WithCondition("Method is declared by object", method => method.DeclaringType == typeof(object));
MethodExcludes.WithCondition("IDisposable.Dispose()", method => method.Name == nameof(IDisposable.Dispose));
MethodExcludes.WithCondition("IAsyncDisposable.DisposeAsync()",
method => method.Name == nameof(IAsyncDisposable.DisposeAsync));
_methodExcludes.WithCondition("Contains Generic Parameters", method => method.ContainsGenericParameters);
_methodExcludes.WithCondition("Special Name", method => method.IsSpecialName);
_methodExcludes.WithCondition("Has attribute [WolverineIgnore]",
MethodExcludes.WithCondition("Contains Generic Parameters", method => method.ContainsGenericParameters);
MethodExcludes.WithCondition("Special Name", method => method.IsSpecialName);
MethodExcludes.WithCondition("Has attribute [WolverineIgnore]",
method => method.HasAttribute<WolverineIgnoreAttribute>());



_methodExcludes.WithCondition("Has no arguments", m => !m.GetParameters().Any());
MethodExcludes.WithCondition("Has no arguments", m => !m.GetParameters().Any());

_methodExcludes.WithCondition("Cannot determine a valid message type",m => m.MessageType() == null);
MethodExcludes.WithCondition("Cannot determine a valid message type",m => m.MessageType() == null);

_methodExcludes.WithCondition("Returns a primitive type", m => m.ReturnType != typeof(void) && m.ReturnType.IsPrimitive);
MethodExcludes.WithCondition("Returns a primitive type", m => m.ReturnType != typeof(void) && m.ReturnType.IsPrimitive);
}

private void specifyHandlerDiscovery()
{
_handlerQuery.Includes.WithNameSuffix(HandlerChain.HandlerSuffix);
_handlerQuery.Includes.WithNameSuffix(HandlerChain.ConsumerSuffix);
_handlerQuery.Includes.Implements<Saga>();
_handlerQuery.Includes.Implements<IWolverineHandler>();
_handlerQuery.Includes.WithAttribute<WolverineHandlerAttribute>();

_handlerQuery.Excludes.WithCondition("Is not a public type", t => isNotPublicType(t));
_handlerQuery.Excludes.WithAttribute<WolverineIgnoreAttribute>();
HandlerQuery.Includes.WithNameSuffix(HandlerChain.HandlerSuffix);
HandlerQuery.Includes.WithNameSuffix(HandlerChain.ConsumerSuffix);
HandlerQuery.Includes.Implements<Saga>();
HandlerQuery.Includes.Implements<IWolverineHandler>();
HandlerQuery.Includes.WithAttribute<WolverineHandlerAttribute>();

HandlerQuery.Excludes.WithCondition("Is not a public type", t => isNotPublicType(t));
HandlerQuery.Excludes.WithAttribute<WolverineIgnoreAttribute>();
}

internal TypeQuery HandlerQuery { get; } = new(TypeClassification.Concretes | TypeClassification.Closed);

private static bool isNotPublicType(Type type)
{
if (type.IsPublic) return false;
Expand All @@ -106,7 +108,7 @@ public HandlerDiscovery CustomizeHandlerDiscovery(Action<TypeQuery> configure)
throw new ArgumentNullException(nameof(configure));
}

configure(_handlerQuery);
configure(HandlerQuery);
return this;
}

Expand Down Expand Up @@ -156,7 +158,7 @@ internal IEnumerable<Type> findAllMessages(HandlerGraph handlers)
Assemblies.Fill(options.ApplicationAssembly);
}

return _handlerQuery.Find(Assemblies)
return HandlerQuery.Find(Assemblies)
.Concat(_explicitTypes)
.Distinct()
.SelectMany(actionsFromType).ToArray();
Expand All @@ -166,7 +168,7 @@ internal IEnumerable<Type> findAllMessages(HandlerGraph handlers)
{
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static)
.Where(x => x.DeclaringType != typeof(object)).ToArray()
.Where(m => _methodIncludes.Matches(m) && !_methodExcludes.Matches(m))
.Where(m => MethodIncludes.Matches(m) && !MethodExcludes.Matches(m))
.Select(m => (type, m));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,29 @@ await writer.WriteLineAsync(
string IDescribedSystemPart.Title => "Wolverine Handlers";

Task IWriteToConsole.WriteToConsole()
{
writeHandlerDiscoveryRules();

if (Chains.Any())
{
writeHandlerTable();
}
else
{
AnsiConsole.Write("[yellow]No message handlers were discovered, you may want to review the discovery rules above.[/]");
}

return Task.CompletedTask;
}

private void writeHandlerTable()
{
var table = new Table();
table.AddColumn("Message Name");
table.AddColumn("[bold]Message Type[/]\n [dim]namespace[/]", c => c.NoWrap = true);
table.AddColumn("[bold]Handler.Method()[/]\n [dim]namespace[/]", c => c.NoWrap = true);
table.AddColumn("Generated Type Name");

foreach (var chain in Chains)
{
var messageType = $"[bold]{chain.MessageType.NameInCode()}[/]\n [dim]{chain.MessageType.Namespace}[/]";
Expand All @@ -46,7 +62,45 @@ Task IWriteToConsole.WriteToConsole()
}

AnsiConsole.Render(table);
}

return Task.CompletedTask;
private void writeHandlerDiscoveryRules()
{
var tree = new Tree("Handler Discovery Rules");
var assemblies = tree.AddNode("Assemblies");
foreach (var assembly in Discovery.Assemblies)
{
assemblies.AddNode(assembly.GetName().Name.EscapeMarkup());
}

var typeRules = tree.AddNode("Handler Type Rules");
var includedNode = typeRules.AddNode("Include:");
foreach (var filter in Discovery.HandlerQuery.Includes)
{
includedNode.AddNode(filter.Description.EscapeMarkup());
}

var excludedNode = typeRules.AddNode("Exclude:");
foreach (var exclude in Discovery.HandlerQuery.Excludes)
{
excludedNode.AddNode(exclude.Description.EscapeMarkup());
}

var methodRules = tree.AddNode("Handler Method Rules");
var includedMethods = methodRules.AddNode("Include:");
foreach (var include in Discovery.MethodIncludes)
{
includedMethods.AddNode(include.Description.EscapeMarkup());
}

var excludedMethods = methodRules.AddNode("Exclude:");
foreach (var filter in Discovery.MethodExcludes)
{
excludedMethods.AddNode(filter.Description.EscapeMarkup());
}

AnsiConsole.Write(tree);

AnsiConsole.WriteLine();
}
}

0 comments on commit dbe4880

Please sign in to comment.