Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public static WolverineOptions UseFluentValidation(this WolverineOptions options
return options;
}

options.Services.AddSingleton(typeof(IFailureAction<>), typeof(FailureAction<>));
options.Services.TryAddSingleton(typeof(IFailureAction<>), typeof(FailureAction<>));

options.ConfigureLazily(o =>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Wolverine.Attributes;
using Wolverine.FluentValidation;
using Wolverine.FluentValidation.Internals;
using Wolverine.Http.FluentValidation;
using Wolverine.Http.FluentValidation.Internals;

[assembly: WolverineModule<FluentValidationExtension>]

Expand All @@ -13,8 +9,6 @@ internal class FluentValidationExtension : IWolverineExtension
{
public void Configure(WolverineOptions options)
{
options.Services.AddSingleton(typeof(IFailureAction<>), typeof(FailureAction<>));

options.Services.AddSingleton(typeof(IProblemDetailSource<>), typeof(ProblemDetailSource<>));
options.UseFluentValidationProblemDetail();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection.Extensions;
using Wolverine.FluentValidation;
using Wolverine.FluentValidation.Internals;
using Wolverine.Http.FluentValidation.Internals;


namespace Wolverine.Http.FluentValidation;

public static class WolverineOptionsExtensions
{
public static WolverineOptions UseFluentValidationProblemDetail(this WolverineOptions options)
{
options.Services.TryAddSingleton(typeof(IFailureAction<>), typeof(FailureAction<>));
options.Services.TryAddSingleton(typeof(IProblemDetailSource<>), typeof(ProblemDetailSource<>));

return options;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
using Alba;
using FluentValidation;
using IntegrationTests;
using Marten;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Shouldly;
using Wolverine.FluentValidation;
using Wolverine.Http.FluentValidation;

namespace Wolverine.Http.Tests.Bugs;

public class Bug_2182_unresolved_IProblemDetailSource
{
private readonly WebApplicationBuilder _builder;

public Bug_2182_unresolved_IProblemDetailSource()
{
_builder = WebApplication.CreateBuilder([]);

_builder.Services.AddMarten(Servers.PostgresConnectionString);
_builder.Services.DisableAllWolverineMessagePersistence();
_builder.Services.DisableAllExternalWolverineTransports();

_builder.Services.AddWolverineHttp();
}

[Fact]
public async Task can_not_compile_with_manual_discovery_by_default()
{
_builder.Services.AddWolverine(ExtensionDiscovery.ManualOnly, opts =>
{
opts.Discovery.IncludeAssembly(typeof(Bug_2182_Endpoint.Request).Assembly);
opts.UseFluentValidation(); // from Wolverine.FluentValidation
// ExtensionDiscovery.ManualMode and Wolverine.Http.FluentValidation services are not registered
});

await using var host = await AlbaHost.For(_builder, app =>
{
app.MapWolverineEndpoints(opts =>
{
opts.UseFluentValidationProblemDetailMiddleware();
});
});

var result = await host.Scenario(x =>
{
x.Post.Json(new Bug_2182_Endpoint.Request("valid")).ToUrl("/Bug_2182");
x.StatusCodeShouldBe(500);
});

result.ReadAsText()
.ShouldContain(
"JasperFx was unable to resolve a variable of type " +
"Wolverine.Http.FluentValidation.IProblemDetailSource<Wolverine.Http.Tests.Bugs.Bug_2182_Endpoint.Request> " +
"as part of the method POST_Bug_2182.Handle(Microsoft.AspNetCore.Http.HttpContext httpContext)");
}

[Fact]
public async Task can_compile_with_manual_extension_discovery_when_problem_detail_services_are_registered()
{
_builder.Services.AddWolverine(ExtensionDiscovery.ManualOnly, opts =>
{
opts.Discovery.IncludeAssembly(typeof(Bug_2182_Endpoint.Request).Assembly);
opts.UseFluentValidation(); // from Wolverine.FluentValidation
opts.UseFluentValidationProblemDetail(); // from Wolverine.Http.FluentValidation
});

await using var host = await AlbaHost.For(_builder, app =>
{
app.MapWolverineEndpoints(opts =>
{
opts.UseFluentValidationProblemDetailMiddleware();
});
});

await host.Scenario(x =>
{
x.Post.Json(new Bug_2182_Endpoint.Request("valid")).ToUrl("/Bug_2182");
x.StatusCodeShouldBe(200);
});
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task can_compile_with_default_extension_discovery(bool useFluentValidationProblemDetail)
{
_builder.Services.AddWolverine(opts =>
{
opts.Discovery.IncludeAssembly(typeof(Bug_2182_Endpoint.Request).Assembly);
opts.UseFluentValidation();
if (useFluentValidationProblemDetail)
opts.UseFluentValidationProblemDetail();
});

await using var host = await AlbaHost.For(_builder, app =>
{
app.MapWolverineEndpoints(opts =>
{
opts.UseFluentValidationProblemDetailMiddleware();
});
});

await host.Scenario(x =>
{
x.Post.Json(new Bug_2182_Endpoint.Request("valid")).ToUrl("/Bug_2182");
x.StatusCodeShouldBe(200);
});
}

[Theory]
[InlineData(ExtensionDiscovery.ManualOnly, true)]
[InlineData(ExtensionDiscovery.Automatic, true)]
[InlineData(ExtensionDiscovery.Automatic, false)]
public async Task can_validate_request_with_problem_detail_middleware(
ExtensionDiscovery extensionDiscovery, bool useFluentValidationProblemDetail)
{
_builder.Services.AddWolverine(extensionDiscovery, opts =>
{
opts.Discovery.IncludeAssembly(typeof(Bug_2182_Endpoint.Request).Assembly);
opts.UseFluentValidation();
if (useFluentValidationProblemDetail)
opts.UseFluentValidationProblemDetail();
});

await using var host = await AlbaHost.For(_builder, app =>
{
app.MapWolverineEndpoints(opts =>
{
opts.UseFluentValidationProblemDetailMiddleware();
});
});

var invalidRequest = new Bug_2182_Endpoint.Request(string.Empty);
var results = await host.Scenario(x =>
{
x.Post.Json(invalidRequest).ToUrl("/Bug_2182");
x.ContentTypeShouldBe("application/problem+json");
x.StatusCodeShouldBe(400);
});
}
}

public static class Bug_2182_Endpoint
{
[WolverinePost("/Bug_2182")]
public static IResult Post(Request value)
{
return TypedResults.Ok(value);
}

public record Request(string Title)
{
public class Validator : AbstractValidator<Request>
{
public Validator()
{
RuleFor(x => x.Title)
.NotEmpty();
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Microsoft.Extensions.DependencyInjection;
using Wolverine.FluentValidation;
using Wolverine.Http.FluentValidation;
using Shouldly;

namespace Wolverine.Http.Tests;

public class fluent_validation_problem_detail_services_registration
{
[Fact]
public void services_registered_once_automatic_extension_discovery_without_manual_call()
{
var services = new ServiceCollection();
services.AddWolverine(ExtensionDiscovery.Automatic, opts => { opts.UseFluentValidation(); });

int failureActionCount = services.Count(d => d.ServiceType == typeof(IFailureAction<>));
int problemDetailCount = services.Count(d => d.ServiceType == typeof(IProblemDetailSource<>));

failureActionCount.ShouldBe(1);
problemDetailCount.ShouldBe(1);
}

[Fact]
public void services_registered_once_automatic_extension_discovery_with_manual_call()
{
var services = new ServiceCollection();
services.AddWolverine(ExtensionDiscovery.Automatic, opts =>
{
opts.UseFluentValidation();
opts.UseFluentValidationProblemDetail();
});

int failureActionCount = services.Count(d => d.ServiceType == typeof(IFailureAction<>));
int problemDetailCount = services.Count(d => d.ServiceType == typeof(IProblemDetailSource<>));

failureActionCount.ShouldBe(1);
problemDetailCount.ShouldBe(1);
}

[Fact]
public void IProblemDetailSource_not_registered_manual_extension_discovery_without_manual_call()
{
var services = new ServiceCollection();
services.AddWolverine(ExtensionDiscovery.ManualOnly, opts => { opts.UseFluentValidation(); });

int problemDetailCount = services.Count(d => d.ServiceType == typeof(IProblemDetailSource<>));

problemDetailCount.ShouldBe(0);
}

[Fact]
public void services_registered_once_manual_extension_discovery_with_manual_call()
{
var services = new ServiceCollection();
services.AddWolverine(ExtensionDiscovery.ManualOnly, opts =>
{
opts.UseFluentValidation();
opts.UseFluentValidationProblemDetail();
});

int failureActionCount = services.Count(d => d.ServiceType == typeof(IFailureAction<>));
int problemDetailCount = services.Count(d => d.ServiceType == typeof(IProblemDetailSource<>));

problemDetailCount.ShouldBe(1);
failureActionCount.ShouldBe(1);
}

[Fact]
public void services_registered_once_with_multiple_service_registers_in_manual_mode()
{
var services = new ServiceCollection();
services.AddWolverine(ExtensionDiscovery.ManualOnly, opts =>
{
opts.UseFluentValidation();

opts.UseFluentValidationProblemDetail();
opts.UseFluentValidationProblemDetail();
opts.UseFluentValidationProblemDetail();
});

int failureActionCount = services.Count(d => d.ServiceType == typeof(IFailureAction<>));
int problemDetailCount = services.Count(d => d.ServiceType == typeof(IProblemDetailSource<>));

failureActionCount.ShouldBe(1);
problemDetailCount.ShouldBe(1);
}
}
Loading