Skip to content

Commit dbe4880

Browse files
Jeremy D. MillerJeremy D. Miller
authored andcommitted
decent textual representation of handler discovery rules in describe output. Closes GH-236
1 parent 81bbb45 commit dbe4880

File tree

4 files changed

+93
-38
lines changed

4 files changed

+93
-38
lines changed

src/Samples/OrderSagaSample/OrderSagaSample.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@
66
</PropertyGroup>
77

88
<ItemGroup>
9-
<ProjectReference Include="..\..\Persistence\Wolverine.Marten\Wolverine.Marten.csproj"/>
10-
<PackageReference Include="LamarCodeGeneration.Commands" Version="6.2.0"/>
11-
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3"/>
9+
<ProjectReference Include="..\..\Persistence\Wolverine.Marten\Wolverine.Marten.csproj" />
10+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
1211
</ItemGroup>
1312

1413
</Project>

src/Wolverine/Configuration/HandlerDiscovery.Diagnostics.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ internal string DescribeHandlerMatch(WolverineOptions options, Type candidateTyp
2929
}
3030

3131
bool typeNotFound = false;
32-
if (!_handlerQuery.Includes.Matches(candidateType))
32+
if (!HandlerQuery.Includes.Matches(candidateType))
3333
{
3434
writeTypeIncludeMiss(candidateType, writer);
3535
typeNotFound = true;
3636
}
3737

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

60-
foreach (var filter in _methodIncludes)
60+
foreach (var filter in MethodIncludes)
6161
{
6262
if (filter.Matches(method))
6363
{
@@ -69,7 +69,7 @@ internal string DescribeHandlerMatch(WolverineOptions options, Type candidateTyp
6969
}
7070
}
7171

72-
foreach (var filter in _methodExcludes)
72+
foreach (var filter in MethodExcludes)
7373
{
7474
if (filter.Matches(method))
7575
{
@@ -90,7 +90,7 @@ internal string DescribeHandlerMatch(WolverineOptions options, Type candidateTyp
9090

9191
private void writeTypeExcludeMatch(Type candidateType, StringWriter writer)
9292
{
93-
foreach (var filter in _handlerQuery.Excludes)
93+
foreach (var filter in HandlerQuery.Excludes)
9494
{
9595
if (filter.Matches(candidateType))
9696
{
@@ -105,7 +105,7 @@ private void writeTypeExcludeMatch(Type candidateType, StringWriter writer)
105105

106106
private void writeTypeIncludeMiss(Type candidateType, StringWriter writer)
107107
{
108-
foreach (var filter in _handlerQuery.Includes)
108+
foreach (var filter in HandlerQuery.Includes)
109109
{
110110
if (filter.Matches(candidateType))
111111
{

src/Wolverine/Configuration/HandlerDiscovery.cs

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ public sealed partial class HandlerDiscovery
1313
{
1414
private readonly IList<Type> _explicitTypes = new List<Type>();
1515

16-
private readonly CompositeFilter<MethodInfo> _methodIncludes = new();
17-
private readonly CompositeFilter<MethodInfo> _methodExcludes = new();
18-
1916
private readonly string[] _validMethods =
2017
{
2118
HandlerChain.Handle, HandlerChain.Handles, HandlerChain.Consume, HandlerChain.Consumes, SagaChain.Orchestrate,
@@ -25,7 +22,6 @@ public sealed partial class HandlerDiscovery
2522

2623
private bool _conventionalDiscoveryDisabled;
2724

28-
private readonly TypeQuery _handlerQuery = new(TypeClassification.Concretes | TypeClassification.Closed);
2925
private readonly TypeQuery _messageQuery = new(TypeClassification.Concretes | TypeClassification.Closed);
3026

3127
public HandlerDiscovery()
@@ -40,48 +36,54 @@ public HandlerDiscovery()
4036
_messageQuery.Excludes.IsNotPublic();
4137
}
4238

39+
internal CompositeFilter<MethodInfo> MethodIncludes { get; } = new();
40+
41+
internal CompositeFilter<MethodInfo> MethodExcludes { get; } = new();
42+
4343
private void specifyHandlerMethodRules()
4444
{
4545
foreach (var methodName in _validMethods)
4646
{
47-
_methodIncludes.WithCondition($"Method name is '{methodName}' (case sensitive)", m => m.Name == methodName);
47+
MethodIncludes.WithCondition($"Method name is '{methodName}' (case sensitive)", m => m.Name == methodName);
4848

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

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

55-
_methodExcludes.WithCondition("Method is declared by object", method => method.DeclaringType == typeof(object));
56-
_methodExcludes.WithCondition("IDisposable.Dispose()", method => method.Name == nameof(IDisposable.Dispose));
57-
_methodExcludes.WithCondition("IAsyncDisposable.DisposeAsync()",
55+
MethodExcludes.WithCondition("Method is declared by object", method => method.DeclaringType == typeof(object));
56+
MethodExcludes.WithCondition("IDisposable.Dispose()", method => method.Name == nameof(IDisposable.Dispose));
57+
MethodExcludes.WithCondition("IAsyncDisposable.DisposeAsync()",
5858
method => method.Name == nameof(IAsyncDisposable.DisposeAsync));
59-
_methodExcludes.WithCondition("Contains Generic Parameters", method => method.ContainsGenericParameters);
60-
_methodExcludes.WithCondition("Special Name", method => method.IsSpecialName);
61-
_methodExcludes.WithCondition("Has attribute [WolverineIgnore]",
59+
MethodExcludes.WithCondition("Contains Generic Parameters", method => method.ContainsGenericParameters);
60+
MethodExcludes.WithCondition("Special Name", method => method.IsSpecialName);
61+
MethodExcludes.WithCondition("Has attribute [WolverineIgnore]",
6262
method => method.HasAttribute<WolverineIgnoreAttribute>());
6363

6464

6565

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

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

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

7373
private void specifyHandlerDiscovery()
7474
{
75-
_handlerQuery.Includes.WithNameSuffix(HandlerChain.HandlerSuffix);
76-
_handlerQuery.Includes.WithNameSuffix(HandlerChain.ConsumerSuffix);
77-
_handlerQuery.Includes.Implements<Saga>();
78-
_handlerQuery.Includes.Implements<IWolverineHandler>();
79-
_handlerQuery.Includes.WithAttribute<WolverineHandlerAttribute>();
80-
81-
_handlerQuery.Excludes.WithCondition("Is not a public type", t => isNotPublicType(t));
82-
_handlerQuery.Excludes.WithAttribute<WolverineIgnoreAttribute>();
75+
HandlerQuery.Includes.WithNameSuffix(HandlerChain.HandlerSuffix);
76+
HandlerQuery.Includes.WithNameSuffix(HandlerChain.ConsumerSuffix);
77+
HandlerQuery.Includes.Implements<Saga>();
78+
HandlerQuery.Includes.Implements<IWolverineHandler>();
79+
HandlerQuery.Includes.WithAttribute<WolverineHandlerAttribute>();
80+
81+
HandlerQuery.Excludes.WithCondition("Is not a public type", t => isNotPublicType(t));
82+
HandlerQuery.Excludes.WithAttribute<WolverineIgnoreAttribute>();
8383
}
8484

85+
internal TypeQuery HandlerQuery { get; } = new(TypeClassification.Concretes | TypeClassification.Closed);
86+
8587
private static bool isNotPublicType(Type type)
8688
{
8789
if (type.IsPublic) return false;
@@ -106,7 +108,7 @@ public HandlerDiscovery CustomizeHandlerDiscovery(Action<TypeQuery> configure)
106108
throw new ArgumentNullException(nameof(configure));
107109
}
108110

109-
configure(_handlerQuery);
111+
configure(HandlerQuery);
110112
return this;
111113
}
112114

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

159-
return _handlerQuery.Find(Assemblies)
161+
return HandlerQuery.Find(Assemblies)
160162
.Concat(_explicitTypes)
161163
.Distinct()
162164
.SelectMany(actionsFromType).ToArray();
@@ -166,7 +168,7 @@ internal IEnumerable<Type> findAllMessages(HandlerGraph handlers)
166168
{
167169
return type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static)
168170
.Where(x => x.DeclaringType != typeof(object)).ToArray()
169-
.Where(m => _methodIncludes.Matches(m) && !_methodExcludes.Matches(m))
171+
.Where(m => MethodIncludes.Matches(m) && !MethodExcludes.Matches(m))
170172
.Select(m => (type, m));
171173
}
172174

src/Wolverine/Runtime/Handlers/HandlerGraph.ISystemDescribedPart.cs

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,29 @@ await writer.WriteLineAsync(
2727
string IDescribedSystemPart.Title => "Wolverine Handlers";
2828

2929
Task IWriteToConsole.WriteToConsole()
30+
{
31+
writeHandlerDiscoveryRules();
32+
33+
if (Chains.Any())
34+
{
35+
writeHandlerTable();
36+
}
37+
else
38+
{
39+
AnsiConsole.Write("[yellow]No message handlers were discovered, you may want to review the discovery rules above.[/]");
40+
}
41+
42+
return Task.CompletedTask;
43+
}
44+
45+
private void writeHandlerTable()
3046
{
3147
var table = new Table();
3248
table.AddColumn("Message Name");
3349
table.AddColumn("[bold]Message Type[/]\n [dim]namespace[/]", c => c.NoWrap = true);
3450
table.AddColumn("[bold]Handler.Method()[/]\n [dim]namespace[/]", c => c.NoWrap = true);
3551
table.AddColumn("Generated Type Name");
36-
52+
3753
foreach (var chain in Chains)
3854
{
3955
var messageType = $"[bold]{chain.MessageType.NameInCode()}[/]\n [dim]{chain.MessageType.Namespace}[/]";
@@ -46,7 +62,45 @@ Task IWriteToConsole.WriteToConsole()
4662
}
4763

4864
AnsiConsole.Render(table);
65+
}
4966

50-
return Task.CompletedTask;
67+
private void writeHandlerDiscoveryRules()
68+
{
69+
var tree = new Tree("Handler Discovery Rules");
70+
var assemblies = tree.AddNode("Assemblies");
71+
foreach (var assembly in Discovery.Assemblies)
72+
{
73+
assemblies.AddNode(assembly.GetName().Name.EscapeMarkup());
74+
}
75+
76+
var typeRules = tree.AddNode("Handler Type Rules");
77+
var includedNode = typeRules.AddNode("Include:");
78+
foreach (var filter in Discovery.HandlerQuery.Includes)
79+
{
80+
includedNode.AddNode(filter.Description.EscapeMarkup());
81+
}
82+
83+
var excludedNode = typeRules.AddNode("Exclude:");
84+
foreach (var exclude in Discovery.HandlerQuery.Excludes)
85+
{
86+
excludedNode.AddNode(exclude.Description.EscapeMarkup());
87+
}
88+
89+
var methodRules = tree.AddNode("Handler Method Rules");
90+
var includedMethods = methodRules.AddNode("Include:");
91+
foreach (var include in Discovery.MethodIncludes)
92+
{
93+
includedMethods.AddNode(include.Description.EscapeMarkup());
94+
}
95+
96+
var excludedMethods = methodRules.AddNode("Exclude:");
97+
foreach (var filter in Discovery.MethodExcludes)
98+
{
99+
excludedMethods.AddNode(filter.Description.EscapeMarkup());
100+
}
101+
102+
AnsiConsole.Write(tree);
103+
104+
AnsiConsole.WriteLine();
51105
}
52106
}

0 commit comments

Comments
 (0)