From 62a8b7f5697fad87bec258475eea30e5651cc7c0 Mon Sep 17 00:00:00 2001 From: hello Date: Sat, 6 Apr 2024 10:06:38 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E8=87=AA=E5=8A=A8=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/UsersController.cs | 1 + .../Models/Users/UserCreateRequest.cs | 5 +- src/HelloShop.IdentityService/Program.cs | 2 +- .../Users/UserCreateRequestValidator.cs | 24 +++++++ .../Users/UserUpdateRequestValidator.cs | 25 +++++++ .../Extensions/ModelBindingExtensionns.cs | 16 ++++- .../HelloShop.ServiceDefaults.csproj | 1 + .../CustomFluentValidationLanguageManager.cs | 66 +++++++++++++++++++ 8 files changed, 137 insertions(+), 3 deletions(-) create mode 100644 src/HelloShop.IdentityService/Validations/Users/UserCreateRequestValidator.cs create mode 100644 src/HelloShop.IdentityService/Validations/Users/UserUpdateRequestValidator.cs create mode 100644 src/HelloShop.ServiceDefaults/Infrastructure/CustomFluentValidationLanguageManager.cs diff --git a/src/HelloShop.IdentityService/Controllers/UsersController.cs b/src/HelloShop.IdentityService/Controllers/UsersController.cs index 3d610e4..9860aef 100644 --- a/src/HelloShop.IdentityService/Controllers/UsersController.cs +++ b/src/HelloShop.IdentityService/Controllers/UsersController.cs @@ -1,4 +1,5 @@ using AutoMapper; +using FluentValidation; using HelloShop.IdentityService.Entities; using HelloShop.IdentityService.EntityFrameworks; using HelloShop.IdentityService.Models.Users; diff --git a/src/HelloShop.IdentityService/Models/Users/UserCreateRequest.cs b/src/HelloShop.IdentityService/Models/Users/UserCreateRequest.cs index 7b9c144..1f58b60 100644 --- a/src/HelloShop.IdentityService/Models/Users/UserCreateRequest.cs +++ b/src/HelloShop.IdentityService/Models/Users/UserCreateRequest.cs @@ -1,9 +1,12 @@ -namespace HelloShop.IdentityService.Models.Users; +using System.ComponentModel.DataAnnotations; + +namespace HelloShop.IdentityService.Models.Users; public class UserCreateRequest { public required string UserName { get; init; } + [Length(8, 16)] public string? PhoneNumber { get; set; } public string? Email { get; set; } diff --git a/src/HelloShop.IdentityService/Program.cs b/src/HelloShop.IdentityService/Program.cs index a6de747..51194f1 100644 --- a/src/HelloShop.IdentityService/Program.cs +++ b/src/HelloShop.IdentityService/Program.cs @@ -57,7 +57,7 @@ builder.Services.AddDataSeedingProviders(); builder.Services.AddOpenApi(); builder.Services.AddPermissionDefinitions(); builder.Services.AddAuthorization().AddDistributedMemoryCache().AddHttpClient().AddHttpContextAccessor().AddTransient().AddCustomAuthorization(); -builder.Services.AddModelMapper(); +builder.Services.AddModelMapper().AddModelValidator(); var app = builder.Build(); diff --git a/src/HelloShop.IdentityService/Validations/Users/UserCreateRequestValidator.cs b/src/HelloShop.IdentityService/Validations/Users/UserCreateRequestValidator.cs new file mode 100644 index 0000000..625dfd7 --- /dev/null +++ b/src/HelloShop.IdentityService/Validations/Users/UserCreateRequestValidator.cs @@ -0,0 +1,24 @@ +using FluentValidation; +using HelloShop.IdentityService.Entities; +using HelloShop.IdentityService.EntityFrameworks; +using HelloShop.IdentityService.Models.Users; +using Microsoft.EntityFrameworkCore; + +namespace HelloShop.IdentityService.Validations.Users; + +public class UserCreateRequestValidator : AbstractValidator +{ + public UserCreateRequestValidator(IdentityServiceDbContext dbContext) + { + RuleFor(m => m.UserName).NotNull().NotEmpty().Length(8, 16).Matches("^[a-zA-Z]+$"); + + RuleFor(m => m.PhoneNumber).NotNull().NotEmpty().Length(11).Matches(@"^1\d{10}$").Must((phoneNumber) => + { + return !dbContext.Set().Any(e => e.PhoneNumber == phoneNumber); + }); + + RuleFor(m => m.Password).NotNull().NotEmpty().Length(8, 16); + + RuleFor(m => m.Email).EmailAddress().Length(8, 32); + } +} diff --git a/src/HelloShop.IdentityService/Validations/Users/UserUpdateRequestValidator.cs b/src/HelloShop.IdentityService/Validations/Users/UserUpdateRequestValidator.cs new file mode 100644 index 0000000..399538b --- /dev/null +++ b/src/HelloShop.IdentityService/Validations/Users/UserUpdateRequestValidator.cs @@ -0,0 +1,25 @@ +using FluentValidation; +using HelloShop.IdentityService.Entities; +using HelloShop.IdentityService.EntityFrameworks; +using HelloShop.IdentityService.Models.Users; +using Microsoft.EntityFrameworkCore; + +namespace HelloShop.IdentityService.Validations.Users; + +public class UserUpdateRequestValidator : AbstractValidator +{ + public UserUpdateRequestValidator(IdentityServiceDbContext dbContext) + { + RuleFor(m => m.UserName).NotNull().NotEmpty().Length(8, 16).Matches("^[a-zA-Z]+$"); + + RuleFor(m => m.PhoneNumber).NotNull().NotEmpty().Length(11).Matches(@"^1\d{10}$").Must((phoneNumber) => + { + return !dbContext.Set().Any(e => e.PhoneNumber == phoneNumber); + }); + + RuleFor(m => m.Password).NotNull().NotEmpty().Length(8, 16); + + RuleFor(m => m.Email).EmailAddress().Length(8, 32); + } + +} diff --git a/src/HelloShop.ServiceDefaults/Extensions/ModelBindingExtensionns.cs b/src/HelloShop.ServiceDefaults/Extensions/ModelBindingExtensionns.cs index f4602b3..985fb2f 100644 --- a/src/HelloShop.ServiceDefaults/Extensions/ModelBindingExtensionns.cs +++ b/src/HelloShop.ServiceDefaults/Extensions/ModelBindingExtensionns.cs @@ -1,4 +1,7 @@ -using Microsoft.Extensions.DependencyInjection; +using FluentValidation; +using FluentValidation.AspNetCore; +using HelloShop.ServiceDefaults.Infrastructure; +using Microsoft.Extensions.DependencyInjection; using System.Reflection; namespace HelloShop.ServiceDefaults.Extensions; @@ -13,4 +16,15 @@ public static class ModelBindingExtensionns return services; } + + public static IServiceCollection AddModelValidator(this IServiceCollection services, Assembly? assembly = null) + { + assembly ??= Assembly.GetCallingAssembly(); + + services.AddValidatorsFromAssembly(assembly).AddFluentValidationAutoValidation(); + + ValidatorOptions.Global.LanguageManager = new CustomFluentValidationLanguageManager(); + + return services; + } } diff --git a/src/HelloShop.ServiceDefaults/HelloShop.ServiceDefaults.csproj b/src/HelloShop.ServiceDefaults/HelloShop.ServiceDefaults.csproj index 8287707..5151dfc 100644 --- a/src/HelloShop.ServiceDefaults/HelloShop.ServiceDefaults.csproj +++ b/src/HelloShop.ServiceDefaults/HelloShop.ServiceDefaults.csproj @@ -9,6 +9,7 @@ + diff --git a/src/HelloShop.ServiceDefaults/Infrastructure/CustomFluentValidationLanguageManager.cs b/src/HelloShop.ServiceDefaults/Infrastructure/CustomFluentValidationLanguageManager.cs new file mode 100644 index 0000000..457f818 --- /dev/null +++ b/src/HelloShop.ServiceDefaults/Infrastructure/CustomFluentValidationLanguageManager.cs @@ -0,0 +1,66 @@ +namespace HelloShop.ServiceDefaults.Infrastructure; + +public class CustomFluentValidationLanguageManager : FluentValidation.Resources.LanguageManager +{ + + public CustomFluentValidationLanguageManager() + { + AddTranslation("en-US", "EmailValidator", "{PropertyName} is invalid"); + AddTranslation("en-US", "GreaterThanOrEqualValidator", "{PropertyName} must be greater than or equal to {ComparisonValue}"); + AddTranslation("en-US", "GreaterThanValidator", "{PropertyName} must be greater than {ComparisonValue}"); + AddTranslation("en-US", "LengthValidator", "{PropertyName} must be between {MinLength} and {MaxLength} characters"); + AddTranslation("en-US", "MinimumLengthValidator", "The length of {PropertyName} must be at least {MinLength} characters"); + AddTranslation("en-US", "MaximumLengthValidator", "The length of {PropertyName} must be {MaxLength} characters or fewer"); + AddTranslation("en-US", "LessThanOrEqualValidator", "{PropertyName} must be less than or equal to {ComparisonValue}"); + AddTranslation("en-US", "LessThanValidator", "{PropertyName} must be less than {ComparisonValue}"); + AddTranslation("en-US", "NotEmptyValidator", "{PropertyName} must not be empty"); + AddTranslation("en-US", "NotEqualValidator", "{PropertyName} must not be equal to {ComparisonValue}"); + AddTranslation("en-US", "NotNullValidator", "{PropertyName} must not be empty"); + AddTranslation("en-US", "PredicateValidator", "The specified condition was not met for {PropertyName}"); + AddTranslation("en-US", "AsyncPredicateValidator", "The specified condition was not met for {PropertyName}"); + AddTranslation("en-US", "RegularExpressionValidator", "{PropertyName} is not in the correct format"); + AddTranslation("en-US", "EqualValidator", "{PropertyName} must be equal to {ComparisonValue}"); + AddTranslation("en-US", "ExactLengthValidator", "{PropertyName} must be {MaxLength} characters in length"); + AddTranslation("en-US", "InclusiveBetweenValidator", "{PropertyName} must be between {From} and {To}"); + AddTranslation("en-US", "ExclusiveBetweenValidator", "{PropertyName} must be between {From} and {To}"); + AddTranslation("en-US", "CreditCardValidator", "{PropertyName} is not a valid credit card number"); + AddTranslation("en-US", "ScalePrecisionValidator", "{PropertyName} must not be more than {ExpectedPrecision} digits in total with allowance for {ExpectedScale} decimals"); + AddTranslation("en-US", "EmptyValidator", "{PropertyName} must be empty"); + AddTranslation("en-US", "NullValidator", "{PropertyName} must be empty"); + AddTranslation("en-US", "EnumValidator", "{PropertyName} has a range of values which does not include {PropertyValue}"); + AddTranslation("en-US", "Length_Simple", "{PropertyName} must be between {MinLength} and {MaxLength} characters"); + AddTranslation("en-US", "MinimumLength_Simple", "The length of {PropertyName} must be at least {MinLength} characters"); + AddTranslation("en-US", "MaximumLength_Simple", "The length of {PropertyName} must be {MaxLength} characters or fewer"); + AddTranslation("en-US", "ExactLength_Simple", "{PropertyName} must be {MaxLength} characters in length"); + AddTranslation("en-US", "InclusiveBetween_Simple", "{PropertyName} must be between {From} and {To}"); + + AddTranslation("zh-CN", "EmailValidator", "{PropertyName}必须是有效的邮件格式"); + AddTranslation("zh-CN", "GreaterThanOrEqualValidator", "{PropertyName}必须大于等于{ComparisonValue}"); + AddTranslation("zh-CN", "GreaterThanValidator", "{PropertyName}必须大于{ComparisonValue}"); + AddTranslation("zh-CN", "LengthValidator", "{PropertyName}必须{MinLength}-{MaxLength}个字符"); + AddTranslation("zh-CN", "MinimumLengthValidator", "{PropertyName}至少{MinLength}个字符"); + AddTranslation("zh-CN", "MaximumLengthValidator", "{PropertyName}最多{MaxLength}个字符"); + AddTranslation("zh-CN", "LessThanOrEqualValidator", "{PropertyName}必须小于等于{ComparisonValue}"); + AddTranslation("zh-CN", "LessThanValidator", "{PropertyName}必须小于{ComparisonValue}"); + AddTranslation("zh-CN", "NotEmptyValidator", "{PropertyName}不能为空"); + AddTranslation("zh-CN", "NotEqualValidator", "{PropertyName}不能和{ComparisonValue}相等"); + AddTranslation("zh-CN", "NotNullValidator", "{PropertyName}不能为空"); + AddTranslation("zh-CN", "PredicateValidator", "{PropertyName}不符合指定的条件"); + AddTranslation("zh-CN", "AsyncPredicateValidator", "{PropertyName}不符合指定的条件"); + AddTranslation("zh-CN", "RegularExpressionValidator", "{PropertyName}格式不正确"); + AddTranslation("zh-CN", "EqualValidator", "{PropertyName}应该和{ComparisonValue}相等"); + AddTranslation("zh-CN", "ExactLengthValidator", "{PropertyName}必须是{MaxLength}个字符"); + AddTranslation("zh-CN", "InclusiveBetweenValidator", "{PropertyName}必须在{From}-{To}之间"); + AddTranslation("zh-CN", "ExclusiveBetweenValidator", "{PropertyName}必须在{From}-{To}之间"); + AddTranslation("zh-CN", "CreditCardValidator", "{PropertyName}不是有效的信用卡号"); + AddTranslation("zh-CN", "ScalePrecisionValidator", "{PropertyName}不能超过{ExpectedPrecision}位,小数部分{ExpectedScale}位"); + AddTranslation("zh-CN", "EmptyValidator", "{PropertyName}必须为空"); + AddTranslation("zh-CN", "NullValidator", "{PropertyName}必须为空"); + AddTranslation("zh-CN", "EnumValidator", "{PropertyName}范围不包含{PropertyValue}"); + AddTranslation("zh-CN", "Length_Simple", "{PropertyName}必须是{MinLength}-{MaxLength}个字符"); + AddTranslation("zh-CN", "MinimumLength_Simple", "{PropertyName}至少{MinLength}个字符"); + AddTranslation("zh-CN", "MaximumLength_Simple", "{PropertyName}最多{MaxLength}个字符"); + AddTranslation("zh-CN", "ExactLength_Simple", "{PropertyName}必须是{MaxLength}个字符"); + AddTranslation("zh-CN", "InclusiveBetween_Simple", "{PropertyName}必须在{From}-{To}之间"); + } +}