Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从自定义AdditionalMetadataAttribute(asp.net mvc 5)访问模型类实例_C#_Asp.net_Asp.net Mvc_Asp.net Mvc 4_Asp.net Mvc 5 - Fatal编程技术网

C# 从自定义AdditionalMetadataAttribute(asp.net mvc 5)访问模型类实例

C# 从自定义AdditionalMetadataAttribute(asp.net mvc 5)访问模型类实例,c#,asp.net,asp.net-mvc,asp.net-mvc-4,asp.net-mvc-5,C#,Asp.net,Asp.net Mvc,Asp.net Mvc 4,Asp.net Mvc 5,我有以下情况-我需要编写一个自定义的附加元数据属性,该属性基于另一个属性值(来自同一个模型),向AdditionalValues字典添加一个值。现在,我的问题是无法访问属性类中的模型实例 [AttributeUsage(AttributeTargets.Property)] public class ExtendedAdditionalMetadataAttribute : Attribute, IMetadataAware { #region Private properties

我有以下情况-我需要编写一个自定义的附加元数据属性,该属性基于另一个属性值(来自同一个模型),向AdditionalValues字典添加一个值。现在,我的问题是无法访问属性类中的模型实例

[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.
    }
}
正如您从代码注释中看到的,在OnMetadataCreated内部,我需要访问模型类实例,但是,尽管ContainerType是正确的,但Container属性为NULL

你能帮我就这个问题给我一个提示吗

提前谢谢你

埃夫丁

后期编辑

考虑到我没有给出太多解释,我还将在这里粘贴一个示例,说明如何在模型类上使用此属性:

/// <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; } 
//
///获取或设置创建的ISAccount
/// 
///ISAccount已创建。
[UIHint(“FormFieldStringTemplate”)]
[ExtendedAdditionalMetadata(“IsExternalAccount”、“true”、“ReadOnly”、“true”)]
公共重写布尔值IsAccountCreated{get;set;}
/// 
///获取或设置ISAccountable
/// 
///这件事是可以解释的。
[显示(Name=“Este cont activ?”)]
[UIHint(“FormFieldStringTemplate”)]
[ExtendedAdditionalMetadata(“IsExternalAccount”、“true”、“ReadOnly”、“true”)]
公共重写布尔值ISAccountable{get;set;}
/// 
///获取或设置IsExternalAccount
/// 
///IsExternalAccount。
[显示(Name=“Este cont extern?”)]
[UIHint(“FormFieldStringTemplate”)]
[附加元数据(“只读”、“真”)]
公共重写布尔IsExternalAccount{get;set;}
以后编辑和以后编辑

尽管@stephen muecke给出的响应在当前情况下更加简单和可接受,但为了编程挑战,我已经寻找了其他选项,并发现了以下可能性:实现自定义
DataAnnotationsModelMetadataProvider
类。简单地说,它是有效的,我能够获得模型类实例,但只有当模型类是一个简单类时,否则会有很多缺点-例如,如果您有一个模型类,并且您在视图中使用它,那么这是可以的,但是如果您在另一个类中有一个类(viewmodel中的模型)这种方法已经不可用了


再次感谢您@stephen muecke

由于您似乎需要访问模型的多个属性,因此该属性应以
AttributeTargets.class
)为目标,并应用于模型,而不是属性。这可能意味着您需要添加另一个属性,该属性是您试图将此应用于的属性的名称。注意
元数据。ContainerType
仅提供
类型,而不是此实例,因此只能获取其属性的默认值

编辑

如果需要将属性应用于模型中的多个属性,则无法访问
OnMetadataCreated
中的容器,因为元数据是从最里面的属性创建的,因此尚未创建模型的元数据

根据OP的评论,更好的解决方案是创建一个定制的html助手。例如,根据另一个属性的值生成只读的文本框

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);
    }
  }
}
创建“只读”复选框有点困难,因为
Readonly
属性对
复选框没有影响。为了防止用户交互,您需要禁用它,但这意味着该值不会发回

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);
  }
}

尝试
metadata.Model
它没有帮助,因为
metadata.Model
为我提供了应用属性的属性的值,我不需要这个值-如果从
extraFieldToCheck
获取的属性值等于属性的值
extraFieldValueToCheck
。到目前为止,我已经尝试了以下方法-通过这样的反射访问“other”属性:
PropertyInfo modelProperty=metadata.ContainerType.GetProperty(this.extraFieldToCheck,bindingsflags.Public | bindingsflags.NonPublic | bindingsflags.Static)
但是
modelProperty
总是空的。首先,这(理论上)只能解决获取类实例的问题,但另一方面,它会使代码更难看(请原谅,但这是我个人的观点),因为我将有一个有25个属性的模型,我需要把这个属性放在其中的10个上,它会变得非常丑陋。。。其次,我尝试了您的方法,虽然我已经声明了属性作用域为class,并且用这个属性装饰了模型类,但是没有调用
OnMetadataCreated
方法。。。不知道为什么…:(我同意,如果它适用于多个属性,那么这不是正确的解决方案。至于不起作用,不确定为什么-它对我来说确实有效。只是为了给出一些额外的解释,元数据是从内部到外部创建的,因此模型(类)的元数据是最后创建的。您尚未解释此操作的上下文,但我假设您有一个自定义html帮助程序。如果是这种情况,请将值添加到字典中(
metadata.AdditionalValues[“SomeKey”]=extraFieldToCheck
),在帮助程序中,您可以访问完整的metatdata,然后可以通过元数据访问这些键。属性是的-我认为您是对的-我没有对我的目标给出太多解释…简单地说,这是一个真实的示例:我有一个表,其中包含一个字段,例如-
IsExternalAccount
;取决于此字段lue,我需要为其他字段向AdditionalValues字典添加一个名为
ReadOnly
的值;例如:
[ExtendedAdditionalMetadata(“IsExternalAccount”、“true”、“ReadOnly”、“true”)]public overri
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)