استفاده از Fluent Validation در برنامههای ASP.NET Core - قسمت پنجم - اعتبارسنجی تنظیمات آغازین برنامه
نویسنده: وحید نصیری
تاریخ: ۱۳۹۹/۰۴/۰۳ ۱۴:۱۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
services.AddOptions<BearerTokensOptions>()
.Bind(configuration.GetSection("BearerTokens"))
.Validate(bearerTokens =>
{
return bearerTokens.AccessTokenExpirationMinutes < bearerTokens.RefreshTokenExpirationMinutes;
}, "RefreshTokenExpirationMinutes is less than AccessTokenExpirationMinutes. Obtaining new tokens using the refresh token should happen only if the access token has expired."); {
"ApiSettings": {
"AllowedEndpoints": [
{
"Name": "Service 1",
"Timeout": 30,
"Url": "http://service1.site.com"
},
{
"Name": "Service 2",
"Timeout": 10,
"Url": "https://service2.site.com"
}
]
}
} using System;
using System.Collections.Generic;
namespace FluentValidationSample.Models
{
public class AllowedEndpoint
{
public string Name { get; set; }
public int Timeout { get; set; }
public Uri Url { get; set; }
}
public class ApiSettings
{
public IEnumerable<AllowedEndpoint> AllowedEndpoints { get; set; }
}
} namespace FluentValidationSample.Web
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApiSettings>(Configuration.GetSection(nameof(ApiSettings))); using System;
using System.Linq;
using FluentValidation;
using FluentValidationSample.Models;
namespace FluentValidationSample.ModelsValidations
{
public class ApiSettingsValidator : AbstractValidator<ApiSettings>
{
public ApiSettingsValidator()
{
RuleFor(apiSetting => apiSetting).NotNull()
.WithMessage("مدخل ApiSettings تعریف نشدهاست.");
RuleFor(apiSetting => apiSetting.AllowedEndpoints).NotNull().NotEmpty()
.WithMessage("مدخل AllowedEndpoints تعریف نشدهاست.");
When(apiSetting => apiSetting.AllowedEndpoints != null,
() =>
{
RuleFor(apiSetting => apiSetting.AllowedEndpoints)
.Must(endpoints => endpoints.GroupBy(endpoint => endpoint.Name).Count() == endpoints.Count())
.WithMessage("نامهای سرویسها باید منحصربفرد باشند.");
RuleFor(apiSetting => apiSetting.AllowedEndpoints)
.Must(endpoints => !endpoints.Any(endpoint => endpoint.Timeout > 90 || endpoint.Timeout < 1))
.WithMessage("مقدار timeout باید بین 1 و 90 باشد");
RuleFor(apiSetting => apiSetting.AllowedEndpoints)
.Must(endpoints => endpoints.GroupBy(endpoint => endpoint.Url.ToString().ToLower()).Count() == endpoints.Count())
.WithMessage("آدرسهای سرویسها باید منحصربفرد باشند.");
RuleFor(apiSetting => apiSetting.AllowedEndpoints)
.Must(endpoints => endpoints.All(endpoint => endpoint.Url.Scheme.Equals("https", StringComparison.CurrentCultureIgnoreCase)))
.WithMessage("تمام آدرسها باید HTTPS باشند.");
});
}
}
} services.AddOptions<BearerTokensOptions>()
.Bind(configuration.GetSection("BearerTokens"))
.Validate(bearerTokens =>
{
return bearerTokens.AccessTokenExpirationMinutes < bearerTokens.RefreshTokenExpirationMinutes;
}, "RefreshTokenExpirationMinutes is less than AccessTokenExpirationMinutes. Obtaining new tokens using the refresh token should happen only if the access token has expired."); namespace Microsoft.Extensions.Options
{
public interface IValidateOptions<TOptions> where TOptions : class
{
ValidateOptionsResult Validate(string name, TOptions options);
}
} using System.Linq;
using FluentValidation;
using Microsoft.Extensions.Options;
namespace FluentValidationSample.ModelsValidations
{
public class AppConfigValidator<TOptions> : IValidateOptions<TOptions> where TOptions : class
{
private readonly IValidator<TOptions> _validator;
public AppConfigValidator(IValidator<TOptions> validator)
{
_validator = validator;
}
public ValidateOptionsResult Validate(string name, TOptions options)
{
if (options is null)
{
return ValidateOptionsResult.Fail("Configuration object is null.");
}
var validationResult = _validator.Validate(options);
return validationResult.IsValid
? ValidateOptionsResult.Success
: ValidateOptionsResult.Fail(validationResult.Errors.Select(error => error.ToString()));
}
}
} namespace FluentValidationSample.Web
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Configure<ApiSettings>(Configuration.GetSection(nameof(ApiSettings)));
services.AddTransient<IValidateOptions<ApiSettings>, AppConfigValidator<ApiSettings>>(); namespace FluentValidationSample.Web.Controllers
{
public class HomeController : Controller
{
private readonly IUsersService _usersService;
private readonly ApiSettings _apiSettings;
public HomeController(IUsersService usersService, IOptions<ApiSettings> apiSettings)
{
_usersService = usersService;
_apiSettings = apiSettings.Value;
} An unhandled exception occurred while processing the request. OptionsValidationException: تمام آدرسها باید HTTPS باشند.
// work services.AddValidatorsFromAssemblyContaining<Car>(); // not work services.AddValidatorsFromAssemblyContaining<ClassLibrary1.Person>();
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Nullable>enable</Nullable>
</PropertyGroup> public class Person
{
public string? Name { get; set; }
public string? Family { get; set; } services.AddFluentValidation(config =>
{
config.RegisterValidatorsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies());
}); services.AddFluentValidation(config =>
{
//Exclude dynamically generated assemblies
config.RegisterValidatorsFromAssemblies(AppDomain.CurrentDomain.GetAssemblies().Where(p => !p.IsDynamic));
});