嵌套类C#的数据注释本地化

时间:2019-02-24 07:40:19

标签: c# asp.net-core

我正在尝试在我的ASP.NET Core Web API 2项目中本地化数据注释,我的代码对于普通类非常有效,但不适用于嵌套类C#。我的代码有什么问题吗? .NET Core甚至支持它?

普通班的作品:

namespace ShagerdanehAPI.Models.API
{
    public class APIInputs
    {
        [Required(ErrorMessage = "The {0} field is required.")]
        [EmailAddress(ErrorMessage = "The {0} field is not valid.")]
        [Display(Name = "Email")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "The {0} field is required.")]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }

    }
}

但嵌套类无法正常工作

namespace ShagerdanehAPI.Models.API
{
    public class APIInputs
    {
        public  class InputLogin
        {

            [Required(ErrorMessage = "The {0} field is required.")]
            [EmailAddress(ErrorMessage = "The {0} field is not valid.")]
            [Display(Name = "Email")]
            public string UserName { get; set; }

            [Required(ErrorMessage = "The {0} field is required.")]
            [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
            [DataType(DataType.Password)]
            [Display(Name = "Password")]
            public string Password { get; set; }
        }
    }
}

项目结构:

enter image description here

启动类:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }
    public IConfiguration Configuration { get; }
    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        string connectionString = Configuration.GetConnectionString("DefaultConnection");
        services.AddDbContext<ApplicationDbContext>(options =>
                         options.UseSqlServer(connectionString));
        builder = new IdentityBuilder(builder.UserType, typeof(ApplicationRole), builder.Services);
        builder.AddRoleManager<RoleManager<ApplicationRole>>();
        builder.AddSignInManager<SignInManager<ApplicationUser>>();
        builder.AddEntityFrameworkStores<ApplicationDbContext>();
        builder.AddDefaultTokenProviders();

        //add Localization
        services.AddSingleton<localizationService>();
        services.AddLocalization(options => options.ResourcesPath = "Resources");
        //add roles
        services.AddMvcCore()
        .AddAuthorization()
        .AddJsonFormatters()
        .AddDataAnnotations()
        .AddDataAnnotationsLocalization()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.Configure<RequestLocalizationOptions>(
            options =>
            {
                List<CultureInfo> supportedCultures = new List<CultureInfo>
                    {
                                    new CultureInfo("en-US"),
                                    new CultureInfo("fa-IR")
                    };
                options.DefaultRequestCulture = new RequestCulture(culture: "fa-IR", uiCulture: "fa-IR");
                options.SupportedCultures = supportedCultures;
                options.SupportedUICultures = supportedCultures;

                options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(context =>
                {

                    string userLangs = context.Request.Headers["Accept-Language"].ToString();
                    string firstLang = userLangs.Split(',').FirstOrDefault();
                    string defaultLang = string.IsNullOrEmpty(firstLang) ? "fa-IR" : firstLang;
                    return Task.FromResult(new ProviderCultureResult(defaultLang, defaultLang));
                }));

            });
        services.Configure<ApiBehaviorOptions>(options =>
        {
            options.SuppressModelStateInvalidFilter = true;
        });
        JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
        services.AddAuthentication("Bearer")
            .AddIdentityServerAuthentication(options =>
            {
                options.Authority = "http://localhost:5000";
                options.RequireHttpsMetadata = false;
                options.ApiName = "api1";

            });
        services.Configure<ShagerdanehConfig>(Configuration.GetSection("ShagerdanehConfig"));
        services.AddCors(options =>
        {
            options.AddPolicy("AllowSpecificOrigin",
                building => building.WithOrigins(
                    "http://localhost:3000",
                    "http://192.168.30.2:3000",
                       AllowAnyMethod()
                      .AllowAnyHeader()
                  .SetPreflightMaxAge(TimeSpan.FromMinutes(30)));
        });
    }
    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        IOptions<RequestLocalizationOptions> locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
        app.UseRequestLocalization(locOptions.Value);
        app.UseAuthentication();
        app.UseCors("AllowSpecificOrigin");
        app.UseMvc();
    }
}

已发送Json:

enter image description here

2 个答案:

答案 0 :(得分:1)

嵌套类的实例应在嵌套外部类中定义。完成验证后,验证就可以正常进行。

我的模特:

public class UserDetailNested
{
    // Property Instance in Outer class
    public UserInfo UserData { get; set; }

    public class UserInfo
    {
        [Required(ErrorMessage = "The {0} field is required.")]
        [EmailAddress(ErrorMessage = "The {0} field is not valid.")]
        [Display(Name = "Email")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "The {0} field is required.")]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }
    }
}

控制器方法:

// POST api/values
[HttpPost]
public IActionResult Post([FromBody]UserDetailNested userDetail)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);
    else
        return Ok();
}

回复屏幕截图: Insomnia Rest Client Screenshot

答案 1 :(得分:1)

这是由于嵌套以及期望将译文定位在何处。第一个可行的示例是在resources目录中的APIInputs中寻找翻译。而第二个示例在不存在的APIInputs> InputLogin中查找它。

一种方法是

namespace ShagerdanehAPI.Models.API
{
    public class LoginDetails
    {
        [Required(ErrorMessage = "The {0} field is required.")]
        [EmailAddress(ErrorMessage = "The {0} field is not valid.")]
        [Display(Name = "Email")]
        public string UserName { get; set; }

        [Required(ErrorMessage = "The {0} field is required.")]
        [StringLength(100, ErrorMessage = "The {0} must be at least {2} and at max {1} characters long.", MinimumLength = 6)]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }
    }
}

然后创建:

namespace ShagerdanehAPI.Models.API
{
    public class APIInputs
    {
         public LoginDetails UserLoginDetails { get; set; }
    }
}

您的资源文件应重命名为LoginDetails.fa-IR.resx

您将看到翻译属性在LoginDetails中,而不在APIInputs中,因此就可以看到它。您可以将附加属性添加到APIInputs类中,如果在模型上进行模型验证,则可以像完成APIInputs.fa-IR.resx一样添加资源类,它将从那里获取该属性转换,而其他转换将是从LoginDetails.fa-IR.resx中检索。