c# - net - Configuración única de DisplayFormatAttribute personalizada una vez
mvc asp.net c# (1)
Estoy configurando NullDisplayText en DisplayFormat desde el recurso a través del siguiente código
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;
}
}
}
Mi cultura predeterminada utilizada es "en-US", una vez que cambio la cultura a es-AR y cargue las páginas funciona bien, pero cuando cambio la cultura a los campos en-US no vuelvo a convertir.
Cambio la cultura de la siguiente manera
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
{
}
}
Yo uso el atributo DisplayFormat en ViewModel como
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; }
}
Aquí hay una idea de lo que está mal.
Mvc está utilizando una forma de TypeDescriptor ( AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type)
) para leer los atributos de sus modelos. Los TypeDescriptors están almacenando en caché información sobre propiedades y atributos. Por lo tanto, su atributo LocalizedDisplayFormatAttribute
solo se creará una instancia una vez, en términos de la API de TypeDescriptor, lo que significa que la información del recurso solo se lee una vez (en la construcción). Ver la parte inferior de la respuesta para referencias.
Soluciones que no funcionan
La reacción de parpadeo es simplemente extraer la última información de recursos de su
LocalizedDisplayFormatAttribute NullDisplayText
cada vez que se accede a través del getter. DesafortunadamenteDisplayFormatAttribute
NullDisplayText
no es virtual, y está sombreando la propiedad con una palabra clavenew
. Esto no funcionará desde una perspectiva de envío polimórfico (Mvc está llamando al getter como unDisplayFormatAttribute
lugar de unLocalizedDisplayFormatAttribute
, por lo que nunca se llamará a su propiedad sombreada)TypeDescriptor.Refresh()
sobrecarga https://msdn.microsoft.com/en-us/library/z1ztz056(v=vs.110).aspx y no tuve suerte
Las opciones restantes que conozco no son tan convenientes ni sorprendentes de una manera u otra. Probablemente no recomendado.
- Alguna manera de actualizar correctamente los
AssociatedMetadataTypeTypeDescriptionProvider TypeDescriptors
. No estoy muy familiarizado con estos, por lo que podría haber uno totalmente. Simplemente no estoy viendo uno actualmente. -
ModelMetadataProvider
aModelMetadataProvider
o cree unModelMetadataProvider
propio. Todo es de código abierto, por lo que es posible, aunque no estoy seguro de que lo recomendaría, excepto como último recurso. - Posiblemente pueda trabajar con las API de TypeDescriptor para forzar una nueva instanciación de su atributo cada vez que se tira de él. Ver https://.com/a/12143653/897291 .
- Modele las propiedades necesarias directamente en MVC (como propiedades del modelo, en lugar de atributos). Podrían ser propiedades completamente nuevas, o podría tener algún tipo de lógica dentro de sus propiedades originales, que cuando null devuelva algo más. Difícil de manejar sin embargo.
Nada grandioso, lo sé. Tal vez esto le dará a alguien más suficiente información para llegar a algo mejor?
Para verificar esto usted mismo, consulte https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/DataAnnotationsModelMetadataProvider.cs Método CreateMetaData
que llama SetFromDataTypeAndDisplayAttributes
método result.NullDisplayText = displayFormatAttribute.NullDisplayText;
DataAnnotationsModelMetadataProvider
extiende AssociatedMetadataProvider
que es responsable de pasar los atributos. Consulte el método https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/AssociatedMetadataProvider.cs GetMetadataForProperty
como ejemplo.