Подтвердить что ты не робот

Индивидуальная настройка DisplayFormatAttribute только один раз

Я устанавливаю NullDisplayText в DisplayFormat из ресурса через следующий код

public class LocalizedDisplayFormatAttribute : DisplayFormatAttribute
{

    private readonly PropertyInfo _propertyInfo;


    public LocalizedDisplayFormatAttribute(string resourceKey, Type resourceType)
        : base()
    {
        this._propertyInfo = resourceType.GetProperty(resourceKey, BindingFlags.Static | BindingFlags.Public);
        if (this._propertyInfo == null)
        {
            return;
        }

        base.NullDisplayText = (string)this._propertyInfo.GetValue(this._propertyInfo.DeclaringType, null);
    }


    public new string NullDisplayText
    {
        get
        {
            return base.NullDisplayText;
        }

        set
        {
            base.NullDisplayText = value;
        }
    }
}

Моя культура по умолчанию используется как "en-US", как только я меняю культуру на es-AR и загружаю страницы, работающие нормально, но когда я меняю культуру обратно на en-US, поля не возвращаются.

Я меняю культуру следующим образом

protected void Application_AcquireRequestState(object sender, EventArgs e)
    {
        try
        {
            HttpCookie cookie = HttpContext.Current.Request.Cookies.Get("CurrentCulture");
            string culutureCode = cookie != null && !string.IsNullOrEmpty(cookie.Value) ? cookie.Value : "en";
            CultureInfo ci = new CultureInfo(culutureCode);
            System.Threading.Thread.CurrentThread.CurrentUICulture = ci;
            System.Threading.Thread.CurrentThread.CurrentCulture =
            CultureInfo.CreateSpecificCulture(ci.Name);
        }
        catch
        {
        }
    }

Я использую атрибут DisplayFormat в ViewModel как

  public class AlarmCodeDetailsViewModel
    {
        /// <summary>
        /// Gets or sets the alarm code ID
        /// </summary>
        public int AlarmCodeID { get; set; }

        /// <summary>
        /// Gets or sets the alarm code
        /// </summary>
        [LocalizedDisplayName("Label_AlarmCode")]
        [LocalizedDisplayFormatAttribute("Warning_NullDisplayText", typeof(Properties.Resources), HtmlEncode = false)]
        public string Code { get; set; }

        /// <summary>
        /// Gets or sets the Description
        /// </summary>
        [LocalizedDisplayName("Label_Description")]
        [LocalizedDisplayFormatAttribute("Warning_NullDisplayText", typeof(Properties.Resources), HtmlEncode = false)]
        public string Description { get; set; }

        /// <summary>
        /// Gets or sets the Notes
        /// </summary>
        [LocalizedDisplayName("Label_Notes")]
        [LocalizedDisplayFormatAttribute("Warning_NullDisplayText", typeof(Properties.Resources), HtmlEncode = false)]
        public string Notes { get; set; }
    }
4b9b3361

Ответ 1

Вот некоторое представление о том, что неправильно.

Mvc использует форму TypeDescriptor (AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type)) для чтения атрибутов с ваших моделей. TypeDescriptors кэширует информацию о свойствах и атрибутах. Таким образом, ваш атрибут LocalizedDisplayFormatAttribute получает экземпляр только один раз, с точки зрения TypeDescriptor api, что означает, что информация о ресурсе считывается только один раз (при построении). См. Нижнюю часть ответа для ссылок.

Решения, которые не работают

  • Реакция мигания заключается в том, чтобы просто вытащить последнюю информацию о ресурсах из вашего LocalizedDisplayFormatAttribute NullDisplayText каждый раз, когда к нему обращаются через геттер. К сожалению, DisplayFormatAttribute NullDisplayText не является виртуальным, и вы затеняете свойство с помощью ключевого слова new. Это не сработает с точки зрения полиморфной диспетчеризации (Mvc вызывает геттер как DisplayFormatAttribute вместо LocalizedDisplayFormatAttribute, поэтому ваше теневое свойство никогда не вызывается)

  • Я пробовал перегружать TypeDescriptor.Refresh() https://msdn.microsoft.com/en-us/library/z1ztz056(v=vs.110).aspx и не повезло

Остальные варианты, о которых я знаю, не так удобны или не удивительны так или иначе. Вероятно, не рекомендуется.

  • Как можно успешно обновить AssociatedMetadataTypeTypeDescriptionProvider TypeDescriptors. Я не слишком хорошо знаком с ними, поэтому вполне может быть один. Я просто не вижу его в настоящее время.
  • Восстановите или создайте ModelMetadataProvider самостоятельно. Все это с открытым исходным кодом, поэтому его возможно, хотя я не уверен, что рекомендую его, кроме как в крайнем случае.
  • Возможно, вы можете работать с Api TypeDescriptor для принудительного повторного создания вашего атрибута всякий раз, когда он вытягивается. См. fooobar.com/info/239918/....
  • Сопоставьте необходимые свойства непосредственно в MVC (как свойства модели, а не атрибуты). Могли бы либо быть совершенно новые свойства, либо вы могли бы иметь какую-то логику в своих исходных свойствах, когда null возвращает что-то другое. Неловко иметь дело с этим.

Ничего хорошего, я знаю. Может быть, это даст кому-то еще достаточно проницательности, чтобы придумать что-то лучше?

Чтобы убедиться в этом сами, см. https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/DataAnnotationsModelMetadataProvider.cs CreateMetaData метод, который вызывает метод SetFromDataTypeAndDisplayAttributes result.NullDisplayText = displayFormatAttribute.NullDisplayText;

DataAnnotationsModelMetadataProvider extends AssociatedMetadataProvider, который является неприемлемым для передачи в атрибутах. В качестве примера рассмотрим метод https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/AssociatedMetadataProvider.cs GetMetadataForProperty.