从自定义AdditionalMetadataAttribute访问模型类的实例(asp.net的MVC 5) [英] Access model class instance from a custom AdditionalMetadataAttribute (asp.net mvc 5)

查看:228
本文介绍了从自定义AdditionalMetadataAttribute访问模型类的实例(asp.net的MVC 5)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下的情况 - 我需要写一个自定义的额外的元数据属性,基于另一个属性值(来自同一型号),增加了一个值AdditionalValues​​字典。现在,我的问题是,我不能够进入我的属性类的内部模型实例。

I have the following situation - I need to write a custom additional metadata attribute, that based on another property value (from the same model), adds a value to the AdditionalValues dictionary. Right now, my issue is that I'm not able to access the model instance inside my attribute class.

[AttributeUsage(AttributeTargets.Property)]
public class ExtendedAdditionalMetadataAttribute : Attribute, IMetadataAware
{
    #region Private properties
    private string extraFieldToCheck { get; set; }

    private string extraFieldValueToCheck { get; set; }

    private string fieldToBeAdded { get; set; }

    private string fieldValueToBeAdded { get; set; }
    #endregion

    #region Constructor
    public ExtendedAdditionalMetadataAttribute(string extraFieldToCheck, string extraFieldValueToCheck,
        string fieldToBeAdded, string fieldValueToBeAdded)
    {
        this.extraFieldToCheck = extraFieldToCheck;
        this.extraFieldValueToCheck = extraFieldValueToCheck;
        this.fieldToBeAdded = fieldToBeAdded;
        this.fieldValueToBeAdded = fieldValueToBeAdded;
    }
    #endregion

    public void OnMetadataCreated(ModelMetadata metadata)
    {
        // HOW TO GET THE MODEL CLASS INSTANCE??? 
        // metadata.ContainerType is correct by metadata.Container is null.
    }
}

当你从code注释中看到,里面OnMetadataCreated我需要访问模型类的实例,但是,虽然ContainerType是正确的,容器属性为NULL。

As you see from the code comments, inside OnMetadataCreated I need to access the Model class instance but, though ContainerType is correct, the Container property is NULL.

你能请给我对这个问题的提示帮助我吗?

Can you please help me by giving me a hint regarding this issue?

谢谢你在前进!

Evdin

在以后编辑

考虑到我没有给得多的解释,我也会贴在这里我想如何使用此属性的模型类的例子:

Considering that I haven't gave to much explanations, I will also paste here an example on how I would like to use this attribute on a model class:

/// <summary>
/// Gets or sets the IsAccountCreated
/// </summary>
/// <value>The IsAccountCreated.</value>
[UIHint("FormFieldStringTemplate")]
[ExtendedAdditionalMetadata("IsExternalAccount", "true", "ReadOnly", "true")]
public override Boolean IsAccountCreated { get; set; }      

/// <summary>
/// Gets or sets the IsAccountEnabled
/// </summary>
/// <value>The IsAccountEnabled.</value>
[Display(Name = "Este cont activ?")]
[UIHint("FormFieldStringTemplate")]
[ExtendedAdditionalMetadata("IsExternalAccount", "true", "ReadOnly", "true")]
public override Boolean IsAccountEnabled { get; set; }      

/// <summary>
/// Gets or sets the IsExternalAccount
/// </summary>
/// <value>The IsExternalAccount.</value>
[Display(Name = "Este cont extern?")]
[UIHint("FormFieldStringTemplate")]
[AdditionalMetadata("ReadOnly", "true")]
public override Boolean IsExternalAccount { get; set; } 

后来和放大器;后来修改

虽然通过@斯蒂芬 - muecke给出的回应是更多的则简单,目前的情况可以接受的,编程挑战的缘故,我已经看了其他的选择,我发现了以下可能性:实现自定义的 DataAnnotationsModelMetadataProvider 类。在简单的几句话 - 它的作品,我能得到的模型类的实例,但只有当模型类是一个简单的类,否则有很多弊端 - 例如,如果你有一个模型类,并在您的视图中使用它那么它的确定,但如果你有另一个类中的类(视图模型内部的模型),这种做法是不再可用。

Though the response given by @stephen-muecke is more then simple and acceptable in current situation, for the sake of programming challenge I've looked for other options and I found the following possibility: implementing a custom DataAnnotationsModelMetadataProvider class. In few simple words - it works and I'm able to obtain the model class instance BUT only if the model class is a simple class, otherwise there are many drawbacks - for example if you have a Model class and you use it in your view then it's ok but if you have a class inside another class (a model inside a viewmodel) that this approach is not usable anymore.

再次谢谢@斯蒂芬 - muecke!

Thank you again @stephen-muecke!

推荐答案

因为你似乎需要访问模型的多个属性,该属性应该针对 AttributeTargets.Class ),并应用到该模型,而不是一个属性。这可能意味着您需要添加另一个属性,是你试图将此应用到属性的名称。注 metadata.ContainerType 只给你的键入,不是这种情况,所以你只能得到其属性的默认值

Since you seem to need access to multiple properties of the model, the attribute should target class (AttributeTargets.Class) and be applied to the model, not a property. This might mean you need to add another property that is the name of the property you were trying to apply this to. Note metadata.ContainerType only gives you the type, not this instance so you can only get the default value of its properties.

修改

如果属性需要在模型中应用到多个属性,那么你就不能因为元数据是从最里面的属性创建访问 OnMetadataCreated 容器出这样的模型元数据还没有被创建。

If the attributes need to be applied to multiple properties in the model, then you cannot access the container in OnMetadataCreated because metadata is created from the innermost properties out so the model's metadata has not yet been created.

根据OP的评论,一个更好的解决方案是创建一个自定义的HTML帮助。例如生成是只读基于另一个属性的值

Based on OP's comments, a better solution would be to create a custom html helper. For example to generate a textbox that is readonly based on the value of another property

namespace MyHelpers.Html
{
  public static class ReadOnlyHelpers
  {
    public static MvcHtmlString ReadOnlyTextBoxIf<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, bool isReadOnly)
    {
      object attributes = isReadOnly ? new { @readonly = "readonly" } : null;
      return InputExtensions.TextBoxFor(helper, expression, attributes);
    }
  }
}

和在你的视图中使用如

@Html.ReadOnlyTextBoxIf(m => m.SomeTextProperty, Model.SomeBooleanValue)

创建只读复选框是有点困难,因为只读属性没有与影响复选框 。为了prevent用户交互,你需要禁用它,但是这意味着值不会回来后

Creating a 'Readonly' checkbox is a little more difficult because the readonly attribute has no affect with a checkbox. In order to prevent user interaction you need to disable it but that means the value wont post back

public static MvcHtmlString ReadOnlyCheckBoxIf<TModel>(this HtmlHelper<TModel> helper, Expression<Func<TModel, bool>> expression, bool isReadOnly)
{
  if (isReadOnly)
  {
    // If you want to 'visually' render a checkbox (otherwise just render a div with "YES" or "NO")
    ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
    StringBuilder html = new StringBuilder();
    // Add a hidden input for postback
    html.Append(InputExtensions.HiddenFor(helper, expression).ToString());
    // Add a visual checkbox without name so it does not post back
    TagBuilder checkbox = new TagBuilder("input");
    checkbox.MergeAttribute("type", "checkbox");
    checkbox.MergeAttribute("disabled", "disabled");
    if ((bool)metaData.Model)
    {
      checkbox.MergeAttribute("checked", "checked");
    }
    html.Append(checkbox.ToString());
    return MvcHtmlString.Create(html.ToString());
  }
  else
  {
    // return normal checkbox
    return InputExtensions.CheckBoxFor(helper, expression);
  }
}

和在你的视图中使用如

@Html.ReadOnlyCheckBoxIf(m => m.IsAccountCreated, Model.IsExternalAccount)

这篇关于从自定义AdditionalMetadataAttribute访问模型类的实例(asp.net的MVC 5)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆