首页 > 解决方案 > 序列化时如何本地化类属性?

问题描述

我正在开发一个 asp.net core 5 web api 项目,我想在序列化并将其转换为 json 时本地化(翻译)我的 DTO 属性。例如假设我们有这个类:

public class PersonDto
{
    public string Name { get; set; }
    public int Grade { get; set; }
}

所以当我尝试序列化这个对象时,JsonConvert.Serialize(personDto)我得到了一个像这样的 json:

{
    "name": "any name",
    "grade": 90
}

但是当用户发送Accept-Language: fr-FR标头时,我想返回如下响应:

{
    "nom": "any name",
    "classe": 90
}

(我不懂法语,我只是用谷歌翻译来证明我的目的。)

到目前为止我所做的:

首先,我在我的项目中添加了本地化。这是配置:

services.AddLocalization();

services.Configure<RequestLocalizationOptions>(
    options =>
    {
        var supportedCultures = new List<CultureInfo>
        {
            new CultureInfo("en-US"),
            new CultureInfo("fr-FR")
        };

        options.DefaultRequestCulture = new RequestCulture(culture: "fr-FR", uiCulture: "fr-FR");
        options.SupportedCultures = supportedCultures;
        options.SupportedUICultures = supportedCultures;
        options.RequestCultureProviders = new[] { new AcceptLanguageHeaderRequestCultureProvider() };
    });

对于启动的配置部分:

// ..
app.UseRouting();

app.UseRequestLocalization();
// ..

并且本地化在我刚刚写的TestContoller中工作:

public class Test : BaseController // BaseController is inherited from ControllerBase (it's OK)
{
    private readonly IStringLocalizer<Resource> _localizer;
    public Test(IStringLocalizer<Resource> localizer)
    {
        _localizer = localizer;
    }

    [HttpGet]
    public string Get()
    {
        return _localizer.GetString("Hello");
    }
}

因此,当我们发送Accept-Language: fr-FR标头时,我们会得到Bonjour作为响应,这没关系。

但我不知道如何翻译类属性。我尝试编写一个CustomContractResolver并且它工作但它有一个错误。这是ContractResolver

public class CustomContractResolver : DefaultContractResolver
{
    private readonly HashSet<Type> _localizeds;
    private readonly IStringLocalizer<Resource> _localizer;

    public CustomContractResolver(IStringLocalizer<Resource> localizer)
    {
        _localizer = localizer;
        _localizeds = new HashSet<Type>();
    }

    public void Localize(Type type)
    {
        if (!_localizeds.Contains(type))
            _localizeds.Add(type);
    }

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);

        if (IsLocalized(property.DeclaringType, property.PropertyName))
        {
            property.PropertyName = _localizer.GetString(property.PropertyName);
        }

        return property;
    }

    private bool IsLocalized(Type type, string jsonPropertyName)
    {
        if (!_localizeds.Contains(type))
            return false;

        return type.GetProperties().Any(p => p.Name.Equals(jsonPropertyName));
    }
}

我通过在启动的配置方法中JsonDefaultSettings调用它来添加它:app.ChangePropertyNameForLocalizableClasses();

public static class NewtonsoftJsonOptionsExtensions
{
    public static void ChangePropertyNameForLocalizableClasses(this IApplicationBuilder app)
    {
        // CustomLocalizeAttribute is a custom attribute that I add to classes that I want to localize them when serializng
        // We are using reflection to get all the classes that should be localized when serializing
        var types = Assembly.GetExecutingAssembly().GetTypes()
            .Where(c => c.HasAttribute<CustomLocalizeAttribute>() && !c.IsAbstract && c.IsPublic && c.IsClass);

        // Our problem starts here: I have to inject localizer manually and DI isn't working
        var localizer = app.ApplicationServices.GetRequiredService<IStringLocalizer<Resource>>();
        
        var jsonResolver = new PropertyRenameAndIgnoreSerializerContractResolver(localizer);

        foreach (var type in types)
        {
            jsonResolver.Localize(type);
        }

        JsonConvert.DefaultSettings = () =>
        {
            var settings = new JsonSerializerSettings {ContractResolver = jsonResolver};
            return settings;
        };
    }
}

所以我的问题是当程序启动时,如果第一个请求具有Accept-Language: fr-FR标头,那么所有具有的类CustomLocalizeAttribute在序列化时都将被本地化,并且它们忽略了Accept-Language标头实际上是什么。

如何_localizer在每个请求中获取 (IStringLocalizer) 的新实例?

也许我一路走错!这是一项常见的任务吗?还有其他解决方案吗?

标签: c#serializationpropertieslocalization

解决方案


推荐阅读