IValidationMetadataProvider 在更改语言 asp.net core 时不返回验证

问题描述 投票:0回答:1
public class LocalizedValidationMetadataProvider : IValidationMetadataProvider
{
public LocalizedValidationMetadataProvider()
{
}

public void CreateValidationMetadata(ValidationMetadataProviderContext context)
{

    var propertyName = context.Key.Name;
if (string.IsNullOrEmpty(propertyName))
        return;

if (context.Key.ModelType.GetTypeInfo().IsValueType && Nullable.GetUnderlyingType(context.Key.ModelType.GetTypeInfo()) == null && context.ValidationMetadata.ValidatorMetadata.Where(m => m.GetType() == typeof(RequiredAttribute)).Count() == 0)
    context.ValidationMetadata.ValidatorMetadata.Add(new RequiredAttribute());
    

foreach (var attribute in context.ValidationMetadata.ValidatorMetadata)
{
var tAttr = attribute as ValidationAttribute;
if (tAttr != null)
{
            var errorName = tAttr.GetType().Name;
            var fallbackName = errorName + "_ValidationError";
            var name = tAttr.ErrorMessage ?? fallbackName;
            var localized = Localizer.GetLocalization(name);
            var text = localized;

            tAttr.ErrorMessage = text;
            tAttr.ErrorMessageResourceName = "";
        }
    }
}

}

此代码在运行应用程序时仅返回一次验证 如果我更改语言,验证不会发生任何变化 连displayName都改成功了

asp.net-core validation metadata
1个回答
0
投票

你可以按照我的样本检查一下哪里出了问题。

  1. 我的控制器
//The index and SetLanguage is necessary
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using System.Diagnostics;
using TestDelete.Models;

namespace TestDelete.Controllers
{
    public class HomeController : Controller
    {
        private readonly ILogger<HomeController> _logger;
        private readonly IStringLocalizer<HomeController> _localizer;

        public HomeController(ILogger<HomeController> logger, IStringLocalizer<HomeController> localizer)
        {
            _logger = logger;
            _localizer = localizer;
        }

        public IActionResult Index()
        {
            ViewData["MyTitle"] = _localizer["The localised title of my app!"];
            return View(new HomeViewModel());
        }

        [HttpPost]
        public IActionResult Index(HomeViewModel model)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            ViewData["Result"] = _localizer["Success!"];
            return View(model);
        }

        [HttpPost]
        public IActionResult SetLanguage(string culture, string returnUrl)
        {
            Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
                new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
            );

            return LocalRedirect(returnUrl);
        }

        public IActionResult Privacy()
        {
            return View();
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}
  1. 我的主页ViewModel
using System.ComponentModel.DataAnnotations;

namespace TestDelete.Models
{
    public class HomeViewModel
    {
        [Required(ErrorMessage = "Required")]
        [EmailAddress(ErrorMessage = "The Email field is not a valid e-mail address")]
        [Display(Name = "Your Email")]
        public string? Email { get; set; }
    }
}
  1. 我的索引视图
@using Microsoft.AspNetCore.Mvc.Localization
@model TestDelete.Models.HomeViewModel

@{
    ViewData["Title"] = "Home Page";
}
<h2>@ViewData["Title"]</h2>
<div class="row">
    <div class="col-md-8">
        <section>
            <form asp-controller="Home" asp-action="Index" method="post" class="form-horizontal" novalidate>
                <h4>@(ViewData["Result"] == null ? "Enter details" : ViewData["Result"])</h4>
                <hr />
                <div class="form-group">
                    <label asp-for="Email" class="col-md-2 control-label"></label>
                    <div class="col-md-10">
                        <input asp-for="Email" class="form-control" />
                        <span asp-validation-for="Email" class="text-danger"></span>
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <button type="submit" class="btn btn-default">Test</button>
                    </div>
                </div>
            </form>
        </section>
    </div>
</div>
  1. 在Views/Shared下设置_layout的footer来渲染设置语言的部分视图
<footer class="border-top footer text-muted">
    …
        <div class="col-sm-6 text-right">
            @await Html.PartialAsync("_SelectLanguagePartial")
        </div>
    </div>
</footer>
  1. 同目录下的_SelectLanguagePartial
@using System.Threading.Tasks
@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home"
          asp-action="SetLanguage" asp-route-returnUrl="@Context.Request.Path"
          method="post" class="form-horizontal" role="form">
        @Localizer["Language:"] <select name="culture"
                                        asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems"></select>
        <button type="submit" class="btn btn-default btn-xs">Save</button>

    </form>
</div>
  1. 您的 LocalizedValidationMetadataProvider 类
public class LocalizedValidationMetadataProvider : IValidationMetadataProvider{
    ...
}
  1. 自定义定位器类
using System.Globalization;
using System.Resources;

public class Localizer
{
    // Create a ResourceManager instance that points to your resource file
  //TestDelete is my namespace, place the resource file in the correct location
    private static ResourceManager _resourceManager = new ResourceManager("TestDelete.HomeViewModel", typeof(Localizer).Assembly);

    // Create a method that returns the localized string for a given name
    public static string GetLocalization(string name)
    {
        // Get the current culture of the application
        var culture = CultureInfo.CurrentCulture;

        // Get the localized string for the name and culture
        var localized = _resourceManager.GetString(name, culture);

        // Return the localized string
        return localized;
    }
}
  1. 程序.cs
…
builder.Services.AddControllersWithViews();
builder.Services.AddLocalization(opts => { opts.ResourcesPath = "Resources"; });
builder.Services.AddMvc(options =>
        {
            options.ModelMetadataDetailsProviders.Add(new LocalizedValidationMetadataProvider());
        })
        .AddViewLocalization(
            LanguageViewLocationExpanderFormat.Suffix,
            opts => { opts.ResourcesPath = "Resources";
            })
        .AddDataAnnotationsLocalization();builder.Services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new List<CultureInfo>
            {
                new CultureInfo("en-GB"),
                new CultureInfo("en-US"),
                new CultureInfo("en"),
                new CultureInfo("fr-FR"),
                new CultureInfo("fr"),
            };

    options.DefaultRequestCulture = new RequestCulture("en-GB");
    // Formatting numbers, dates, etc.
    options.SupportedCultures = supportedCultures;
    // UI strings that we have localized.
    options.SupportedUICultures = supportedCultures;
});

var app = builder.Build();
…
app.UseHttpsRedirection();
app.UseStaticFiles();
var options = ((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(options.Value);
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();
  1. 我的英语和法语资源文件

如果 resx 文件“Build Action = Embedded”,请记住设置属性 资源”

测试:

如果我有什么理解错误的地方,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.