refactor(samples): modernise CommandProcessor samples#3998
Conversation
holytshirt
commented
Jan 31, 2026
- Use Host.CreateApplicationBuilder() instead of CreateDefaultBuilder()
- Replace GetService with GetRequiredService for safer DI resolution
- Remove Serilog dependencies in favor of built-in logging
- Use string interpolation in handlers
- Make command classes internal sealed
- HelloWorldInternalBus: switch to async handler, remove custom mapper
Pull Request ReviewSummaryThis PR modernizes the CommandProcessor sample applications by adopting current .NET hosting patterns and simplifying dependencies. The changes align well with modern .NET best practices. Positive Changes1. Modern Hosting Patterns
2. Safer Dependency Injection
3. Dependency Simplification
4. Code Quality Improvements
5. HelloWorldInternalBus Improvements
Minor Observations1. Namespace Inconsistency (samples/CommandProcessor/HelloWorldInternalBus/GreetingCommandHandlerAsync.cs:29) The handler is in namespace 2. tests.http Formatting (samples/WebAPI/WebAPI_Dapper/tests.http) The JSON spacing changes are correct and follow standard JSON formatting, though this file seems unrelated to the CommandProcessor samples modernization. Code Quality AssessmentAdherence to Repository Conventions:
Best Practices:
Performance:
Test CoverageNote: These are sample applications demonstrating usage patterns. They do not require unit tests themselves, but they should successfully compile, run without errors, and demonstrate best practices. Recommendation: Verify that each sample builds and runs successfully in CI. Overall AssessmentThis is a high-quality refactoring PR that:
The changes follow the repository design principles by focusing on structural improvements without altering behavior. Recommendation: Approve with minor namespace consistency suggestion. Review generated following repository CLAUDE.md guidelines and design principles. |
iancooper
left a comment
There was a problem hiding this comment.
Looks good. Thanks for updating these @holytshirt
PR Review: Modernise CommandProcessor SamplesOverall AssessmentThis is a well-executed modernization of the sample applications. The changes align with .NET 8 best practices and improve code quality. ✅ Positive Changes1. Modern Host Builder Pattern ✅
2. Safer Dependency Injection ✅
3. Dependency Cleanup ✅
4. Code Quality Improvements ✅
5. Handler Consistency ✅
6. Architecture Simplification ✅
Issues & Concerns1.
|
Pull Request Review: Modernize Sample Code to .NET 8 PatternsOverall AssessmentThis is a high-quality PR that successfully modernizes 30+ sample applications to use .NET 8 hosting patterns and best practices. The changes are well-executed and remarkably consistent across the codebase. Overall Grade: A- What This PR Does Well
Issues and RecommendationsHigh Priority - Requires Verification:
Medium Priority - Consider Addressing:
Code Quality AnalysisPattern Consistency: 5/5 - Excellent, same pattern across all samples Security and PerformanceSecurity: No concerns. The switch to GetRequiredService improves null safety. Testing Recommendations
Final RecommendationAPPROVE WITH MINOR VERIFICATION This PR is well-executed and ready to merge after verifying HelloWorldInternalBus functions correctly without the message mapper. The modernization brings the samples up to .NET 8 standards and makes them more accessible to developers learning Brighter. Great work on this comprehensive modernization effort! Review performed by Claude Code - Analyzed 1,158 additions and 1,734 deletions across 39 files |
|
@holytshirt Do you want to update, and then we can merge? |
|
Yeah! I try later this evening or over the weekend |
- Use Host.CreateApplicationBuilder() instead of CreateDefaultBuilder() - Replace GetService with GetRequiredService for safer DI resolution - Remove Serilog dependencies in favor of built-in logging - Use string interpolation in handlers - Make command classes internal sealed - HelloWorldInternalBus: switch to async handler, remove custom mapper Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix namespace in HelloWorldInternalBus handler (HelloWorld -> HelloWorldInternalBus) - Rename GreetingCommandRequestHandlerAsync to GreetingCommandHandlerAsync for consistency - Remove ConfigureAwait from samples (application code doesn't need it per Stephen Cleary) - Remove unused using statements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…tionBuilder - KafkaTaskQueue: Update GreetingsReceiverConsole and GreetingsSender - KafkaSchemaRegistry: Update GreetingsReceiverConsole and GreetingsSender - KafkaDynamicEventStream: Update TaskReceiverConsole and TaskStatusSender - MultiBus: Update GreetingsReceiverConsole and GreetingsSender - HelloWorldInternalBus: Fix GetService -> GetRequiredService Replace Host.CreateDefaultBuilder() with Host.CreateApplicationBuilder() for modern .NET 8+ hosting pattern. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…patterns Convert remaining TaskQueue samples from new HostBuilder() pattern to Host.CreateApplicationBuilder(): - RMQTaskQueue/GreetingsReceiverConsole - ASBTaskQueue/GreetingsReceiverConsole - ASBTaskQueue/GreetingsScopedReceiverConsole - AWSTaskQueue/GreetingsReceiverConsole - AWSTaskQueue/GreetingsPumper - PostgresTaskQueue/GreetingsReceiverConsole - RedisTaskQueue/GreetingsSender - RedisTaskQueue/GreetingsReceiver - MsSqlMessagingGateway/GreetingsReceiverConsole - MsSqlMessagingGateway/CompetingSender - MsSqlMessagingGateway/CompetingReceiverConsole - RMQRequestReply/GreetingsServer Changes applied: - Replace new HostBuilder() with Host.CreateApplicationBuilder(args) - Use top-level statements with builder.Services.Xxx() calls - Remove Serilog configuration in favor of built-in logging - Remove .UseConsoleLifetime() and .UseSerilog() - Keep internal sealed classes for IHostedService implementations - Use GetRequiredService instead of GetService where applicable Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Convert JustSaying, MassTransit, and AWS Transformers samples from HostBuilder pattern to Host.CreateApplicationBuilder with top-level statements. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add InMemorySchedulerFactory to all modernised TaskQueue Program.cs files that were missing it after rebasing onto master. Includes comment explaining it can be replaced with Hangfire or Quartz for durable scheduling. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
512925d to
2f48ec1
Compare
PR Review: refactor(samples) - modernise CommandProcessor samplesOverall this is a solid modernisation pass. The changes are consistent, reduce boilerplate, and align the samples with current .NET idioms. Positive changes
Concerns1. Removal of // samples/CommandProcessor/HelloWorldAsync/GreetingCommandHandlerAsync.cs
-return await base.HandleAsync(command, cancellationToken).ConfigureAwait(ContinueOnCapturedContext);
+return await base.HandleAsync(command, cancellationToken);
Recommendation: Restore 2. -host.WaitForShutdown();
+host.Run();
3. AWS samples: services registered outside the credential guard In This is a pre-existing bug carried over from the original code, but the refactor rearranged registration enough to make it more visible. Worth a follow-up fix (move 4. Minor: inconsistent indentation in builder.Services.AddConsumers(options =>
{ // extra indent level compared to surrounding code
options.Subscriptions = subscriptions;Cosmetic only. SummaryThe PR is in good shape and achieves its goals cleanly. The main actionable item is restoring |
AddHostedService<RunCommandProcessor> and AddHostedService<ServiceActivatorHostedService> were registered unconditionally outside the credentials check, causing a cryptic DI exception at startup when AWS credentials are absent. Move them inside the guard and add an else branch that prints a clear error message and exits. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Receiver UseScheduler is an extension method in Paramore.Brighter.Extensions.DependencyInjection, which was not imported in the Redis receiver's Program.cs, causing CS1061.
PR Review: refactor(samples): modernise CommandProcessor samplesOverall, this is a solid modernisation effort. The changes are consistent, purposeful, and move the codebase to modern .NET idioms.
Serilog removal - Reduces the dependency footprint and eliminates logging bootstrapping boilerplate. The built-in Namespace bug fix in Deletion of
Issues and Suggestions: 1. The host is built and 2. Removal of
3. The pattern of conditionally registering services then calling 4. Whitespace noise in licence headers Several files have trivial trailing-whitespace changes in the MIT licence block. These appear to be editor artefacts. They inflate the diff and make it harder to spot substantive changes. Worth stripping before merge. 5.
Summary:
The PR achieves its stated goals cleanly. The two things most worth addressing before merge are (1) the Reviewed with Claude Code |
Consistent with the async context and modern .NET patterns.
There was a problem hiding this comment.
No application code in the PR — skipped Code Health checks.
See analysis details in CodeScene
Quality Gate Profile: Clean Code Collective
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.
|
PR Review: refactor(samples) modernise CommandProcessor samples |
|
Review posted - see below for full details |
|
PR Review: refactor(samples) modernise CommandProcessor samples Overall this is a well-executed modernisation. The changes are consistent and align with current .NET idioms. Positives: Host.CreateApplicationBuilder() is the right move for .NET 7+. GetRequiredService over GetService fails fast rather than returning null. Serilog removal reduces friction for new developers. String interpolation is a minor but consistent improvement. internal sealed on command/handler types is appropriate for samples. Namespace fix in HelloWorldInternalBus (was incorrectly in namespace HelloWorld). Explicit error messages for missing AWS credentials are much friendlier than a null-reference failure downstream. |
|
Issue 1: ConfigureAwait(ContinueOnCapturedContext) removed without explanation File: samples/CommandProcessor/HelloWorldAsync/GreetingCommandHandlerAsync.cs Before: return await base.HandleAsync(command, cancellationToken).ConfigureAwait(ContinueOnCapturedContext); ContinueOnCapturedContext is a protected virtual property on RequestHandlerAsync that the framework uses to control synchronisation-context propagation. Removing ConfigureAwait silently opts into ConfigureAwait(true) behaviour. This pattern is idiomatic Brighter and its removal could mislead developers copying from this sample into omitting ConfigureAwait throughout their real handlers. Consider restoring the original pattern or adding a comment explaining why it can safely be omitted here. |
|
Issue 2: HelloWorldInternalBus - sync Post changed to async PostAsync (behavioural change) File: samples/CommandProcessor/HelloWorldInternalBus/Program.cs Before: commandProcessor?.Post(new GreetingCommand("Ian")); The async path is appropriate, but check whether any documentation or README still describes the synchronous behaviour. Issue 3: GreetingsPumper StartAsync still calls synchronous Post inside an async loop File: samples/TaskQueue/AWSTaskQueue/GreetingsPumper/Program.cs This is pre-existing, but since the class was touched it is a natural opportunity to switch to PostAsync. If kept synchronous intentionally (e.g. to demonstrate outbox behaviour), a comment explaining why would help readers. Issue 4: Noisy whitespace diff in licence headers Several files have trailing-space removals in the licence block. These inflate the diff and distract from the meaningful changes. Consider handling whitespace-only changes in a separate commit. Issue 5: HelloWorldInternalBus mapper removal Deleting GreetingCommandMessageMapper is correct since the internal bus does not require serialisation. Worth confirming AutoFromAssemblies does not inadvertently attempt to resolve a mapper for GreetingCommand at runtime. |
|
Minor suggestions: KafkaDynamicEventStream/TaskReceiverConsole adds using System explicitly - with ImplicitUsings enabled this should be unnecessary. The explanatory comment moved to the top of GreetingsScopedReceiverConsole/Program.cs is a nice touch and belongs in a README too. |
|
Summary: Solid modernisation across a large surface area. Main items before merging: (1) Clarify or restore the ConfigureAwait(ContinueOnCapturedContext) pattern in GreetingCommandHandlerAsync - it is idiomatic Brighter and its removal could mislead developers copying from the sample. (2) Consider switching RunCommandProcessor.StartAsync to PostAsync for async consistency. Everything else is non-blocking or pre-existing. Nice work! |