Add FluentValidation for Question model validation

- Updated `AskEndpoints.cs` to include `MinimalHelpers.FluentValidation` and standardize endpoint descriptions.
- Integrated FluentValidation in `Program.cs` and registered validators.
- Modified `SqlDatabaseVectorSearch.csproj` to add necessary package references for FluentValidation.
- Created `QuestionValidator` class to enforce validation rules on the `Question` model.
This commit is contained in:
Marco Minerva
2025-05-05 15:06:22 +02:00
parent a2ae9c05af
commit 32fce98b63
4 changed files with 23 additions and 3 deletions
@@ -1,5 +1,5 @@
using System.ComponentModel;
using System.ComponentModel; using MinimalHelpers.FluentValidation;
using SqlDatabaseVectorSearch.Models; using SqlDatabaseVectorSearch.Models;
using SqlDatabaseVectorSearch.Services; using SqlDatabaseVectorSearch.Services;
@@ -10,11 +10,12 @@ public class AskEndpoints : IEndpointRouteHandlerBuilder
public static void MapEndpoints(IEndpointRouteBuilder endpoints) public static void MapEndpoints(IEndpointRouteBuilder endpoints)
{ {
endpoints.MapPost("/api/ask", async (Question question, VectorSearchService vectorSearchService, CancellationToken cancellationToken, endpoints.MapPost("/api/ask", async (Question question, VectorSearchService vectorSearchService, CancellationToken cancellationToken,
[Description("If true, the question will be reformulated taking into account the context of the chat identified by the given ConversationId.")] bool reformulate = true) => [Description("If true, the question will be reformulated taking into account the context of the chat identified by the given ConversationId.")] bool reformulate = true) =>
{ {
var response = await vectorSearchService.AskQuestionAsync(question, reformulate, cancellationToken); var response = await vectorSearchService.AskQuestionAsync(question, reformulate, cancellationToken);
return TypedResults.Ok(response); return TypedResults.Ok(response);
}) })
.WithValidation<Question>()
.WithSummary("Asks a question") .WithSummary("Asks a question")
.WithDescription("The question will be reformulated taking into account the context of the chat identified by the given ConversationId.") .WithDescription("The question will be reformulated taking into account the context of the chat identified by the given ConversationId.")
.WithTags("Ask"); .WithTags("Ask");
@@ -35,6 +36,7 @@ public class AskEndpoints : IEndpointRouteHandlerBuilder
return Stream(); return Stream();
}) })
.WithValidation<Question>()
.WithSummary("Asks a question and gets the response as streaming") .WithSummary("Asks a question and gets the response as streaming")
.WithDescription("The question will be reformulated taking into account the context of the chat identified by the given ConversationId.") .WithDescription("The question will be reformulated taking into account the context of the chat identified by the given ConversationId.")
.WithTags("Ask"); .WithTags("Ask");
+4
View File
@@ -1,5 +1,6 @@
using System.Net.Mime; using System.Net.Mime;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using FluentValidation;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.SemanticKernel; using Microsoft.SemanticKernel;
using SqlDatabaseVectorSearch.Components; using SqlDatabaseVectorSearch.Components;
@@ -82,6 +83,9 @@ builder.Services.AddOpenApi(options =>
options.AddDefaultProblemDetailsResponse(); options.AddDefaultProblemDetailsResponse();
}); });
ValidatorOptions.Global.LanguageManager.Enabled = false;
builder.Services.AddValidatorsFromAssemblyContaining<Program>();
builder.Services.AddDefaultProblemDetails(); builder.Services.AddDefaultProblemDetails();
builder.Services.AddDefaultExceptionHandler(); builder.Services.AddDefaultExceptionHandler();
@@ -12,6 +12,7 @@
<PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" /> <PackageReference Include="DocumentFormat.OpenXml" Version="3.3.0" />
<PackageReference Include="EFCore.SqlServer.VectorSearch" Version="9.0.0-preview.2" /> <PackageReference Include="EFCore.SqlServer.VectorSearch" Version="9.0.0-preview.2" />
<PackageReference Include="EntityFrameworkCore.Exceptions.SqlServer" Version="8.1.3" /> <PackageReference Include="EntityFrameworkCore.Exceptions.SqlServer" Version="8.1.3" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="12.0.0" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" /> <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.4">
@@ -25,6 +26,7 @@
<PackageReference Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="1.0.2" /> <PackageReference Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="1.0.2" />
<PackageReference Include="Microsoft.SemanticKernel" Version="1.48.0" /> <PackageReference Include="Microsoft.SemanticKernel" Version="1.48.0" />
<PackageReference Include="MimeMapping" Version="3.1.0" /> <PackageReference Include="MimeMapping" Version="3.1.0" />
<PackageReference Include="MinimalHelpers.FluentValidation" Version="1.1.3" />
<PackageReference Include="MinimalHelpers.Routing.Analyzers" Version="1.1.3" /> <PackageReference Include="MinimalHelpers.Routing.Analyzers" Version="1.1.3" />
<PackageReference Include="PdfPig" Version="0.1.10" /> <PackageReference Include="PdfPig" Version="0.1.10" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.1" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="8.1.1" />
@@ -0,0 +1,12 @@
using FluentValidation;
using SqlDatabaseVectorSearch.Models;
namespace SqlDatabaseVectorSearch.Validators;
public class QuestionValidator : AbstractValidator<Question>
{
public QuestionValidator()
{
RuleFor(x => x.Text).NotEmpty().MaximumLength(4096).WithName("Question Text");
}
}