diff --git a/docs/guide/handlers/index.md b/docs/guide/handlers/index.md
index 8167859b3..12c717078 100644
--- a/docs/guide/handlers/index.md
+++ b/docs/guide/handlers/index.md
@@ -525,3 +525,59 @@ public static class PingHandler
snippet source | anchor
+## Validation
+
+Wolverine provides several options for validating messages before they are processed by your handler logic. These range from lightweight, inline validation to full integration with popular validation libraries.
+
+### Lightweight Validation with String Messages
+
+The simplest approach is to add a `Validate` or `ValidateAsync` method to your handler class that returns validation error messages as strings. If any messages are returned, Wolverine will log them and abort the handler execution.
+
+Supported return types are `IEnumerable`, `string[]`, `Task`, and `ValueTask`.
+
+For **message handlers**, Wolverine will:
+1. Check if there are any validation messages
+2. If none, continue processing
+3. If there are messages, log each one as a warning using `ILogger`
+4. Abort the handler by returning early
+
+
+
+
+You can also use synchronous `string[]` returns:
+
+
+
+
+Or asynchronous validation:
+
+
+
+
+For **HTTP endpoints**, the behavior is different — Wolverine will create a `ProblemDetails` response with a 400 status code containing the validation messages:
+
+
+
+
+### Validation with HandlerContinuation
+
+For more control, your `Validate` method can return a `HandlerContinuation` to explicitly signal whether processing should continue or stop:
+
+
+
+
+### Validation with ProblemDetails
+
+In HTTP endpoints (and message handlers with the Wolverine.Http package), you can return a `ProblemDetails` object for richer validation responses:
+
+
+
+
+### FluentValidation Integration
+
+For more complex validation scenarios, Wolverine integrates with [FluentValidation](/guide/handlers/fluent-validation). This allows you to use FluentValidation's full feature set including rule builders, conditional rules, and custom validators.
+
+### Data Annotations Integration
+
+Wolverine also supports [.NET Data Annotations](/guide/handlers/dataannotations-validation) for validation, allowing you to use standard `[Required]`, `[Range]`, and other validation attributes on your message types.
+
diff --git a/src/Http/Wolverine.Http.Tests/simple_validation_in_http_endpoints.cs b/src/Http/Wolverine.Http.Tests/simple_validation_in_http_endpoints.cs
new file mode 100644
index 000000000..58e4eb36b
--- /dev/null
+++ b/src/Http/Wolverine.Http.Tests/simple_validation_in_http_endpoints.cs
@@ -0,0 +1,92 @@
+using Alba;
+using Shouldly;
+using WolverineWebApi;
+
+namespace Wolverine.Http.Tests;
+
+public class simple_validation_in_http_endpoints : IntegrationContext
+{
+ public simple_validation_in_http_endpoints(AppFixture fixture) : base(fixture)
+ {
+ }
+
+ [Fact]
+ public async Task happy_path_with_ienumerable_string_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpEnumerableMessage(3)).ToUrl("/simple-validation/ienumerable");
+ });
+ }
+
+ [Fact]
+ public async Task sad_path_with_ienumerable_string_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpEnumerableMessage(20)).ToUrl("/simple-validation/ienumerable");
+ x.StatusCodeShouldBe(400);
+ x.ContentTypeShouldBe("application/problem+json");
+ });
+ }
+
+ [Fact]
+ public async Task happy_path_with_string_array_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpStringArrayMessage(3)).ToUrl("/simple-validation/string-array");
+ });
+ }
+
+ [Fact]
+ public async Task sad_path_with_string_array_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpStringArrayMessage(20)).ToUrl("/simple-validation/string-array");
+ x.StatusCodeShouldBe(400);
+ x.ContentTypeShouldBe("application/problem+json");
+ });
+ }
+
+ [Fact]
+ public async Task happy_path_with_async_string_array_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpAsyncMessage(3)).ToUrl("/simple-validation/async");
+ });
+ }
+
+ [Fact]
+ public async Task sad_path_with_async_string_array_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpAsyncMessage(20)).ToUrl("/simple-validation/async");
+ x.StatusCodeShouldBe(400);
+ x.ContentTypeShouldBe("application/problem+json");
+ });
+ }
+
+ [Fact]
+ public async Task happy_path_with_valuetask_string_array_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpValueTaskMessage(3)).ToUrl("/simple-validation/valuetask");
+ });
+ }
+
+ [Fact]
+ public async Task sad_path_with_valuetask_string_array_validate()
+ {
+ await Scenario(x =>
+ {
+ x.Post.Json(new SimpleValidateHttpValueTaskMessage(20)).ToUrl("/simple-validation/valuetask");
+ x.StatusCodeShouldBe(400);
+ x.ContentTypeShouldBe("application/problem+json");
+ });
+ }
+}
diff --git a/src/Http/Wolverine.Http/CodeGen/SimpleValidationHttpFrame.cs b/src/Http/Wolverine.Http/CodeGen/SimpleValidationHttpFrame.cs
new file mode 100644
index 000000000..f5b1d6cdf
--- /dev/null
+++ b/src/Http/Wolverine.Http/CodeGen/SimpleValidationHttpFrame.cs
@@ -0,0 +1,56 @@
+using JasperFx.CodeGeneration;
+using JasperFx.CodeGeneration.Frames;
+using JasperFx.CodeGeneration.Model;
+using JasperFx.Core.Reflection;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Wolverine.Http.CodeGen;
+
+///
+/// Frame that generates validation code for HTTP endpoints.
+/// Creates a ProblemDetails with status 400 and writes it to the response if validation messages exist.
+///
+internal class SimpleValidationHttpFrame : AsyncFrame
+{
+ private static int _count;
+ private readonly Variable _variable;
+ private Variable? _context;
+
+ public SimpleValidationHttpFrame(Variable variable)
+ {
+ _variable = variable;
+ _variable.OverrideName(_variable.Usage + ++_count);
+ uses.Add(_variable);
+ }
+
+ public override IEnumerable FindVariables(IMethodVariables chain)
+ {
+ _context = chain.FindVariable(typeof(HttpContext));
+ yield return _context;
+ }
+
+ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
+ {
+ writer.WriteComment("Check for any simple validation messages and abort with ProblemDetails if any exist");
+ writer.Write(
+ $"var validationMessages{_count} = {_variable.Usage}.ToArray();");
+ writer.Write(
+ $"BLOCK:if (validationMessages{_count}.Length > 0)");
+ writer.Write(
+ $"var problemDetails{_count} = new {typeof(ProblemDetails).FullNameInCode()}();");
+ writer.Write(
+ $"problemDetails{_count}.{nameof(ProblemDetails.Status)} = 400;");
+ writer.Write(
+ $"problemDetails{_count}.{nameof(ProblemDetails.Title)} = \"Validation failed\";");
+ writer.Write(
+ $"problemDetails{_count}.{nameof(ProblemDetails.Extensions)}[\"errors\"] = validationMessages{_count};");
+ writer.Write(
+ $"await {nameof(HttpHandler.WriteProblems)}(problemDetails{_count}, {_context!.Usage}).ConfigureAwait(false);");
+ writer.Write("return;");
+ writer.FinishBlock();
+ writer.BlankLine();
+
+ Next?.GenerateCode(method, writer);
+ }
+}
diff --git a/src/Http/Wolverine.Http/HttpChain.cs b/src/Http/Wolverine.Http/HttpChain.cs
index 681dfedf5..f485a3cd6 100644
--- a/src/Http/Wolverine.Http/HttpChain.cs
+++ b/src/Http/Wolverine.Http/HttpChain.cs
@@ -302,6 +302,12 @@ public override bool HasAttribute()
return HasRequestType ? RequestType : ComplexQueryStringType;
}
+ public override Frame? CreateSimpleValidationFrame(Variable variable)
+ {
+ Metadata.Produces(400, contentType: "application/problem+json");
+ return new SimpleValidationHttpFrame(variable);
+ }
+
public override Frame[] AddStopConditionIfNull(Variable variable)
{
return [new SetStatusCodeAndReturnIfEntityIsNullFrame(variable)];
diff --git a/src/Http/WolverineWebApi/SimpleValidationUsage.cs b/src/Http/WolverineWebApi/SimpleValidationUsage.cs
new file mode 100644
index 000000000..16faa8a6e
--- /dev/null
+++ b/src/Http/WolverineWebApi/SimpleValidationUsage.cs
@@ -0,0 +1,90 @@
+using System.Diagnostics;
+using Wolverine.Http;
+
+namespace WolverineWebApi;
+
+#region sample_simple_validation_http_ienumerable
+
+public record SimpleValidateHttpEnumerableMessage(int Number);
+
+public static class SimpleValidationHttpEnumerableEndpoint
+{
+ public static IEnumerable Validate(SimpleValidateHttpEnumerableMessage message)
+ {
+ if (message.Number > 10)
+ {
+ yield return "Number must be 10 or less";
+ }
+ }
+
+ [WolverinePost("/simple-validation/ienumerable")]
+ public static string Post(SimpleValidateHttpEnumerableMessage message) => "Ok";
+}
+
+#endregion
+
+#region sample_simple_validation_http_string_array
+
+public record SimpleValidateHttpStringArrayMessage(int Number);
+
+public static class SimpleValidationHttpStringArrayEndpoint
+{
+ public static string[] Validate(SimpleValidateHttpStringArrayMessage message)
+ {
+ if (message.Number > 10)
+ {
+ return ["Number must be 10 or less"];
+ }
+
+ return [];
+ }
+
+ [WolverinePost("/simple-validation/string-array")]
+ public static string Post(SimpleValidateHttpStringArrayMessage message) => "Ok";
+}
+
+#endregion
+
+#region sample_simple_validation_http_async
+
+public record SimpleValidateHttpAsyncMessage(int Number);
+
+public static class SimpleValidationHttpAsyncEndpoint
+{
+ public static Task ValidateAsync(SimpleValidateHttpAsyncMessage message)
+ {
+ if (message.Number > 10)
+ {
+ return Task.FromResult(new[] { "Number must be 10 or less" });
+ }
+
+ return Task.FromResult(Array.Empty());
+ }
+
+ [WolverinePost("/simple-validation/async")]
+ public static string Post(SimpleValidateHttpAsyncMessage message) => "Ok";
+}
+
+#endregion
+
+#region sample_simple_validation_http_valuetask
+
+public record SimpleValidateHttpValueTaskMessage(int Number);
+
+public static class SimpleValidationHttpValueTaskEndpoint
+{
+ public static ValueTask ValidateAsync(SimpleValidateHttpValueTaskMessage message)
+ {
+ if (message.Number > 10)
+ {
+ return new ValueTask(new[] { "Number must be 10 or less" });
+ }
+
+ return new ValueTask(Array.Empty());
+ }
+
+ [WolverinePost("/simple-validation/valuetask")]
+ public static string Post(SimpleValidateHttpValueTaskMessage message) => "Ok";
+}
+
+#endregion
diff --git a/src/Testing/CoreTests/Acceptance/simple_validation_handlers.cs b/src/Testing/CoreTests/Acceptance/simple_validation_handlers.cs
new file mode 100644
index 000000000..1cb2e8ecc
--- /dev/null
+++ b/src/Testing/CoreTests/Acceptance/simple_validation_handlers.cs
@@ -0,0 +1,227 @@
+using System.Diagnostics;
+using Microsoft.Extensions.Hosting;
+using Wolverine.Tracking;
+using Xunit;
+
+namespace CoreTests.Acceptance;
+
+public class simple_validation_handlers
+{
+ [Fact]
+ public async Task happy_path_with_ienumerable_string_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationEnumerableHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateEnumerableMessage(3));
+
+ SimpleValidationEnumerableHandler.Handled.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task sad_path_with_ienumerable_string_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationEnumerableHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateEnumerableMessage(20));
+
+ SimpleValidationEnumerableHandler.Handled.ShouldBeFalse();
+ }
+
+ [Fact]
+ public async Task happy_path_with_string_array_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationStringArrayHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateStringArrayMessage(3));
+
+ SimpleValidationStringArrayHandler.Handled.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task sad_path_with_string_array_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationStringArrayHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateStringArrayMessage(20));
+
+ SimpleValidationStringArrayHandler.Handled.ShouldBeFalse();
+ }
+
+ [Fact]
+ public async Task happy_path_with_async_string_array_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationAsyncHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateAsyncMessage(3));
+
+ SimpleValidationAsyncHandler.Handled.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task sad_path_with_async_string_array_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationAsyncHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateAsyncMessage(20));
+
+ SimpleValidationAsyncHandler.Handled.ShouldBeFalse();
+ }
+
+ [Fact]
+ public async Task happy_path_with_valuetask_string_array_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationValueTaskHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateValueTaskMessage(3));
+
+ SimpleValidationValueTaskHandler.Handled.ShouldBeTrue();
+ }
+
+ [Fact]
+ public async Task sad_path_with_valuetask_string_array_validate()
+ {
+ using var host = await Host.CreateDefaultBuilder()
+ .UseWolverine()
+ .StartAsync();
+
+ SimpleValidationValueTaskHandler.Handled = false;
+
+ await host.InvokeMessageAndWaitAsync(new SimpleValidateValueTaskMessage(20));
+
+ SimpleValidationValueTaskHandler.Handled.ShouldBeFalse();
+ }
+}
+
+#region sample_simple_validation_ienumerable
+
+public record SimpleValidateEnumerableMessage(int Number);
+
+public static class SimpleValidationEnumerableHandler
+{
+ public static IEnumerable Validate(SimpleValidateEnumerableMessage message)
+ {
+ if (message.Number > 10)
+ {
+ yield return "Number must be 10 or less";
+ }
+ }
+
+ public static void Handle(SimpleValidateEnumerableMessage message)
+ {
+ Debug.WriteLine("Handled " + message);
+ Handled = true;
+ }
+
+ public static bool Handled { get; set; }
+}
+
+#endregion
+
+#region sample_simple_validation_string_array
+
+public record SimpleValidateStringArrayMessage(int Number);
+
+public static class SimpleValidationStringArrayHandler
+{
+ public static string[] Validate(SimpleValidateStringArrayMessage message)
+ {
+ if (message.Number > 10)
+ {
+ return ["Number must be 10 or less"];
+ }
+
+ return [];
+ }
+
+ public static void Handle(SimpleValidateStringArrayMessage message)
+ {
+ Debug.WriteLine("Handled " + message);
+ Handled = true;
+ }
+
+ public static bool Handled { get; set; }
+}
+
+#endregion
+
+#region sample_simple_validation_async
+
+public record SimpleValidateAsyncMessage(int Number);
+
+public static class SimpleValidationAsyncHandler
+{
+ public static Task ValidateAsync(SimpleValidateAsyncMessage message)
+ {
+ if (message.Number > 10)
+ {
+ return Task.FromResult(new[] { "Number must be 10 or less" });
+ }
+
+ return Task.FromResult(Array.Empty());
+ }
+
+ public static void Handle(SimpleValidateAsyncMessage message)
+ {
+ Debug.WriteLine("Handled " + message);
+ Handled = true;
+ }
+
+ public static bool Handled { get; set; }
+}
+
+#endregion
+
+#region sample_simple_validation_valuetask
+
+public record SimpleValidateValueTaskMessage(int Number);
+
+public static class SimpleValidationValueTaskHandler
+{
+ public static ValueTask ValidateAsync(SimpleValidateValueTaskMessage message)
+ {
+ if (message.Number > 10)
+ {
+ return new ValueTask(new[] { "Number must be 10 or less" });
+ }
+
+ return new ValueTask(Array.Empty());
+ }
+
+ public static void Handle(SimpleValidateValueTaskMessage message)
+ {
+ Debug.WriteLine("Handled " + message);
+ Handled = true;
+ }
+
+ public static bool Handled { get; set; }
+}
+
+#endregion
diff --git a/src/Wolverine/Configuration/Chain.cs b/src/Wolverine/Configuration/Chain.cs
index ecebfeeff..920b4f535 100644
--- a/src/Wolverine/Configuration/Chain.cs
+++ b/src/Wolverine/Configuration/Chain.cs
@@ -45,6 +45,14 @@ public abstract class Chain : IChain
public abstract bool TryInferMessageIdentity(out PropertyInfo? property);
+ ///
+ /// Default implementation for message handlers: log validation messages and return
+ ///
+ public virtual Frame? CreateSimpleValidationFrame(Variable variable)
+ {
+ return new SimpleValidationHandlerFrame(variable);
+ }
+
public bool IsTransactional { get; set; }
public abstract bool ShouldFlushOutgoingMessages();
public abstract bool RequiresOutbox();
diff --git a/src/Wolverine/Configuration/IChain.cs b/src/Wolverine/Configuration/IChain.cs
index 4b4c9b038..14af7c2ea 100644
--- a/src/Wolverine/Configuration/IChain.cs
+++ b/src/Wolverine/Configuration/IChain.cs
@@ -170,6 +170,14 @@ public interface IChain
Frame[] AddStopConditionIfNull(Variable data, Variable? identity, IDataRequirement requirement);
bool TryInferMessageIdentity(out PropertyInfo? property);
+
+ ///
+ /// Create a Frame for simple validation based on a variable that contains
+ /// string validation messages (IEnumerable<string>, string[], etc.)
+ ///
+ /// The variable containing validation messages
+ /// A frame that checks for validation messages and aborts if any exist, or null if not supported
+ Frame? CreateSimpleValidationFrame(Variable variable);
}
#endregion
\ No newline at end of file
diff --git a/src/Wolverine/Middleware/ContinuationHandling.cs b/src/Wolverine/Middleware/ContinuationHandling.cs
index 8bb63d875..606b94ee2 100644
--- a/src/Wolverine/Middleware/ContinuationHandling.cs
+++ b/src/Wolverine/Middleware/ContinuationHandling.cs
@@ -16,7 +16,7 @@ public static List ContinuationStrategies(this Generation
return list;
}
- return [new HandlerContinuationPolicy()];
+ return [new HandlerContinuationPolicy(), new SimpleValidationContinuationPolicy()];
}
///
@@ -36,6 +36,7 @@ public static List ContinuationStrategies(this Generation
list =
[
new HandlerContinuationPolicy(),
+ new SimpleValidationContinuationPolicy(),
new T()
];
rules.Properties[Continuations] = list;
diff --git a/src/Wolverine/Middleware/SimpleValidationContinuationPolicy.cs b/src/Wolverine/Middleware/SimpleValidationContinuationPolicy.cs
new file mode 100644
index 000000000..7d7dfa89e
--- /dev/null
+++ b/src/Wolverine/Middleware/SimpleValidationContinuationPolicy.cs
@@ -0,0 +1,125 @@
+using JasperFx.CodeGeneration;
+using JasperFx.CodeGeneration.Frames;
+using JasperFx.CodeGeneration.Model;
+using JasperFx.Core.Reflection;
+using Microsoft.Extensions.Logging;
+using Wolverine.Configuration;
+
+namespace Wolverine.Middleware;
+
+///
+/// Continuation strategy that detects Validate/ValidateAsync methods returning
+/// IEnumerable<string>, string[], Task<string[]>, or ValueTask<string[]>
+/// and generates appropriate validation handling code.
+///
+public class SimpleValidationContinuationPolicy : IContinuationStrategy
+{
+ private static readonly Type[] ValidReturnTypes =
+ [
+ typeof(IEnumerable),
+ typeof(string[])
+ ];
+
+ ///
+ /// Helper used by generated code to log validation messages and return a boolean
+ /// indicating whether there are any validation failures.
+ ///
+ public static bool LogValidationMessages(ILogger logger, IEnumerable messages)
+ {
+ var hasMessages = false;
+ foreach (var message in messages)
+ {
+ hasMessages = true;
+ logger.LogWarning("Validation failure: {ValidationMessage}", message);
+ }
+
+ return hasMessages;
+ }
+
+ public bool TryFindContinuationHandler(IChain chain, MethodCall call, out Frame? frame)
+ {
+ // Only apply to methods named Validate or ValidateAsync
+ if (call.Method.Name != "Validate" && call.Method.Name != "ValidateAsync")
+ {
+ frame = null;
+ return false;
+ }
+
+ var variable = FindStringEnumerableVariable(call);
+ if (variable == null)
+ {
+ frame = null;
+ return false;
+ }
+
+ frame = chain.CreateSimpleValidationFrame(variable);
+ return frame != null;
+ }
+
+ internal static Variable? FindStringEnumerableVariable(MethodCall call)
+ {
+ foreach (var variable in call.Creates)
+ {
+ if (IsStringEnumerable(variable.VariableType))
+ {
+ return variable;
+ }
+ }
+
+ return null;
+ }
+
+ internal static bool IsStringEnumerable(Type type)
+ {
+ if (type == typeof(IEnumerable)) return true;
+ if (type == typeof(string[])) return true;
+ if (type == typeof(List)) return true;
+
+ return false;
+ }
+}
+
+///
+/// Frame that generates validation code for message handlers.
+/// Logs validation messages and returns if any are found.
+///
+internal class SimpleValidationHandlerFrame : SyncFrame
+{
+ private static int _count;
+ private readonly Variable _variable;
+ private Variable? _logger;
+
+ public SimpleValidationHandlerFrame(Variable variable)
+ {
+ _variable = variable;
+ _variable.OverrideName(_variable.Usage + ++_count);
+ uses.Add(_variable);
+ }
+
+ public override IEnumerable FindVariables(IMethodVariables chain)
+ {
+ _logger = chain.FindVariable(typeof(ILogger));
+ yield return _logger;
+ }
+
+ public override void GenerateCode(GeneratedMethod method, ISourceWriter writer)
+ {
+ writer.WriteComment("Check for any simple validation messages and abort if any exist");
+ writer.Write(
+ $"BLOCK:if ({typeof(SimpleValidationContinuationPolicy).FullNameInCode()}.{nameof(SimpleValidationContinuationPolicy.LogValidationMessages)}({_logger!.Usage}, {_variable.Usage}))");
+
+ if (method.AsyncMode == AsyncMode.AsyncTask)
+ {
+ writer.Write("return;");
+ }
+ else
+ {
+ writer.Write($"return {typeof(Task).FullNameInCode()}.{nameof(Task.CompletedTask)};");
+ }
+
+ writer.FinishBlock();
+ writer.BlankLine();
+
+ Next?.GenerateCode(method, writer);
+ }
+}