如何在不使用`DisplayNameAttribute`的情况下更改ViewModel显示名称?

时间:2017-12-30 14:05:11

标签: c# .net asp.net-mvc asp.net-core .net-core

我想直接更改某些属性(ViewModel)的显示名称而不使用[DisplayName("prop name")]。这应该在返回View之前直接在控制器中发生,或者在ViewModel类本身中发生

我不想在视图中更改任何内容,我也不想使用任何数据注释。我怎样才能做到这一点?

是否有任何流利的语法可以得到它?

我正在使用: ASP.Net Core 2.0

数据注释的问题在于我想在运行时获取显示名称(而数据注释是预编译的)。

更新:

提出这个问题的主要原因是找到一种方法来包装IStringLocalizer,特别是在本地化数据注释时的行为。接受的答案解释了这个基础知识。

1 个答案:

答案 0 :(得分:5)

  

@Tseng,对不起我应该说得更清楚,我的意思是我们应该使用命名约定或SharedResources。但不是两者,我有很多情况下我有很多共享资源,以及许多特定于ViewModel的字符串(所以混合)。使用.Net Core本地化解决方案无法实现这一目标。

如果您唯一担心的是您可以或无法确定是否选择了一个或多个资源文件,则可以轻松配置。我不得不在源代码中挖掘一下,看起来有点可能。

我们可以看到here localizer由配置中定义的工厂决定

if (_stringLocalizerFactory != null && _localizationOptions.DataAnnotationLocalizerProvider != null)
{
    localizer = _localizationOptions.DataAnnotationLocalizerProvider(containerType, _stringLocalizerFactory);
}

_localizationOptionsMvcDataAnnotationsLocalizationOptions

MvcDataAnnotationsLocalizationOptions的默认实施是here

/// <inheritdoc />
public void Configure(MvcDataAnnotationsLocalizationOptions options)
{
    if (options == null)
    {
        throw new ArgumentNullException(nameof(options));
    }

    options.DataAnnotationLocalizerProvider = (modelType, stringLocalizerFactory) =>
        stringLocalizerFactory.Create(modelType);
}

因此默认使用每个模型资源。

如果您愿意,可以将其更改为所有数据注释的SharedResource文件,Startup.ConfigureServices中有以下内容(未经测试,但应该有效):

services.AddMvc()
    .AddDataAnnotationsLocalization(options =>
    {
        options.DataAnnotationLocalizerProvider = (type, factory) =>
            factory.Create(typeof(SharedResource));
    });

这将有效地忽略传递的类型,并始终返回共享字符串本地化程序。

当然,您可以在那里添加任何逻辑,并决定您将要使用的本地化程序的每类型类型。

修改

如果这还不够,您可以实现自己的自定义IDisplayMetadataProvider,以您想要的方式处理它。但实际上使用DisplayAttribute应该足够了。 DisplayAttribute具有其他参数,可用于定义资源类型。

[Display(Name = "StringToLocalize", ResourceType = typeof(SharedResource))]

使用ResourceType,您可以选择用于查找本地化的类(以及资源​​文件名)。

编辑2:使用带有回退到每个视图模型资源的包装IStringLocalizer

更优雅的解决方案是使用上面的MvcDataAnnotationsLocalizationOptions选项文件返回您自己的IStringLocalizer,它会查看一个资源文件并回退到另一个资源文件。

public class DataAnnotationStringLocalizer : IStringLocalizer
{
    private readonly IStringLocalizer primaryLocalizer;
    private readonly IStringLocalizer fallbackLocalizer;

    public DataAnnotationStringLocalizer(IStringLocalizer primaryLocalizer, IStringLocalizer fallbackLocalizer)
    {
        this.primaryLocalizer = primaryLocalizer ?? throw new ArgumentNullException(nameof(primaryLocalizer));
        this.fallbackLocalizer = fallbackLocalizer ?? throw new ArgumentNullException(nameof(fallbackLocalizer));
    }

    public LocalizedString this[string name]
    {
        get
        {
            LocalizedString localizedString = primaryLocalizer[name];
            if (localizedString.ResourceNotFound)
            {
                localizedString = fallbackLocalizer[name];
            }

            return localizedString;
        }
    }

    public LocalizedString this[string name, params object[] arguments]
    {
        get
        {
            LocalizedString localizedString = primaryLocalizer[name, arguments];
            if (localizedString.ResourceNotFound)
            {
                localizedString = fallbackLocalizer[name, arguments];
            }

            return localizedString;
        }
    }

    public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
        => primaryLocalizer.GetAllStrings(includeParentCultures).Concat(fallbackLocalizer.GetAllStrings(includeParentCultures));

    public IStringLocalizer WithCulture(CultureInfo culture)
        => new DataAnnotationStringLocalizer(primaryLocalizer.WithCulture(culture), fallbackLocalizer.WithCulture(culture));
}

并使用以下选项

services.AddMvc()
    .AddDataAnnotationsLocalization(options =>
    {
        options.DataAnnotationLocalizerProvider = (type, factory) =>
        {
            return new DataAnnotationStringLocalizer(
                factory?.Create(typeof(SharedResource)),
                factory?.Create(type)
            );
        };
    });

现在,首先从共享资源中解析字符串,如果在那里找不到字符串,它将从视图模型类型(传递给工厂方法的类型参数)中解析它。

如果您不喜欢逻辑,并且您希望它首先查看视图模型资源文件,您只需将订单更改为

services.AddMvc()
    .AddDataAnnotationsLocalization(options =>
    {
        options.DataAnnotationLocalizerProvider = (type, factory) =>
        {
            return new DataAnnotationStringLocalizer(
                factory?.Create(type),
                factory?.Create(typeof(SharedResource))
            );
        }
    });

现在,视图模型是主要解析器,共享资源是辅助