问题描述

默认语言是zh-Hans,但数据模型验证却是en

  1. {
  2. "error": {
  3. "code": null,
  4. "message": "你的请求无效!",
  5. "details": "验证时发现以下错误.\r\n - The field Age must be between 0 and 150.\r\n - The Name field is required.\r\n - The field Name must be a string with a minimum length of 1 and a maximum length of 100.\r\n",
  6. "data": {},
  7. "validationErrors": [
  8. {
  9. "message": "The field Age must be between 0 and 150.",
  10. "members": [
  11. "age"
  12. ]
  13. },
  14. {
  15. "message": "The Name field is required.",
  16. "members": [
  17. "name"
  18. ]
  19. },
  20. {
  21. "message": "The field Name must be a string with a minimum length of 1 and a maximum length of 100.",
  22. "members": [
  23. "name"
  24. ]
  25. }
  26. ]
  27. }
  28. }

如何解决

经过查看源码,发现数据模型验证加载本地化是通过AddDataAnnotationsLocalization这个扩展进行的。

  1. public class AbpAspNetCoreMvcModule : AbpModule
  2. {
  3. public override void ConfigureServices(ServiceConfigurationContext context)
  4. {
  5. // 省略其它代码...
  6. var mvcCoreBuilder = context.Services.AddMvcCore(options =>
  7. {
  8. options.Filters.Add(new AbpAutoValidateAntiforgeryTokenAttribute());
  9. });
  10. context.Services.ExecutePreConfiguredActions(mvcCoreBuilder);
  11. var abpMvcDataAnnotationsLocalizationOptions = context.Services
  12. .ExecutePreConfiguredActions(
  13. new AbpMvcDataAnnotationsLocalizationOptions()
  14. );
  15. context.Services
  16. .AddSingleton<IOptions<AbpMvcDataAnnotationsLocalizationOptions>>(
  17. new OptionsWrapper<AbpMvcDataAnnotationsLocalizationOptions>(
  18. abpMvcDataAnnotationsLocalizationOptions
  19. )
  20. );
  21. var mvcBuilder = context.Services.AddMvc()
  22. .AddDataAnnotationsLocalization(options =>
  23. {
  24. options.DataAnnotationLocalizerProvider = (type, factory) =>
  25. {
  26. // 获取资源
  27. var resourceType = abpMvcDataAnnotationsLocalizationOptions
  28. .AssemblyResources
  29. .GetOrDefault(type.Assembly);
  30. if (resourceType != null)
  31. {
  32. return factory.Create(resourceType);
  33. }
  34. return factory.CreateDefaultOrNull() ??
  35. factory.Create(type);
  36. };
  37. })
  38. .AddViewLocalization(); //TODO: How to configure from the application? Also, consider to move to a UI module since APIs does not care about it.
  39. // 省略其它代码...
  40. }
  41. }

DataAnnotationLocalizerProvider接受一个Func<Type, IStringLocalizerFactory, IStringLocalizer>委托。
Abp的逻辑是从AbpMvcDataAnnotationsLocalizationOptions.AssemblyResources获取默认resourceType,如果为null就通过factoryAbpLocalizationOptions.DefaultResourceType中获取默认资源,如果都没有就根据传入type创建,碰巧模块都不符合。

解决方法就是把对应模块的默认资源添加上。同时别忘记AddBaseTypes(typeof(AbpValidationResource)),因为数据验证本地化资源在AbpValidationResource已经定义了,直接拿来用就行。

  1. Configure<AbpLocalizationOptions>(options =>
  2. {
  3. options.Resources
  4. .Add<BookStoreResource>("en")
  5. .AddBaseTypes(typeof(AbpValidationResource))
  6. .AddVirtualJson("/Localization/BookStore");
  7. options.DefaultResourceType = typeof(BookStoreResource);
  8. options.Languages.Add(new LanguageInfo("en", "en", "English"));
  9. options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文"));
  10. });