【问题标题】:howto: Nesting extension method calls如何:嵌套扩展方法调用
【发布时间】:2011-10-27 14:10:01
【问题描述】:

在我的 cshtml 中,我有以下行:

@Html.TextBoxFor(m => m.EmailAddress, new { @class = "field size4",
placeholder = LogOnUIMessages.EmailFieldLabel, id = "LoginEmailAddress",
name="LoginEmail", autofocus = "", required=""})

因为字段'required'已经被定义为一个数据注释(该属性是为了简单干净的JS验证而添加的),我想写一个TextBoxFor的新实现,它包括基于数据注释的'required':

[Required(ErrorMessageResourceType = typeof(LogOnUIMessages), ErrorMessageResourceName = LogOnResourceKeys.ErrorEmailIsRequired)]
[StringLength(UserNameMaxLength, ErrorMessageResourceType = typeof(LogOnUIMessages), ErrorMessageResourceName = LogOnResourceKeys.ErrorUserNameMaxLenghtExceeded)]
[RegularExpression(RegEx.CorrectEmailRegExp, ErrorMessageResourceType = typeof(ProfileUIMessages), ErrorMessageResourceName = LogOnResourceKeys.ErrorEmailIsNotValid)]
[DataType(DataType.EmailAddress)]
public String EmailAddress { get; set; }

(给出了更多的注释,现在只显示最重要的一个)作为概念证明,我写了一个扩展方法和一个辅助方法:

public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(
        this HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        object htmlAttributes
    )
{
    return htmlHelper.TextBoxFor(expression, htmlAttributes);
}

public static MvcHtmlString CustomTextBoxForToo<TModel, TProperty>(
        HtmlHelper<TModel> htmlHelper,
        Expression<Func<TModel, TProperty>> expression,
        object htmlAttributes
    )
{
    return htmlHelper.TextBoxFor(expression, 
    HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}

但是当像这样调用时:

@Html.CustomTextBoxFor(
    m => m.EmailAddress, new { @class = "field size4", placeholder = 
    LogOnUIMessages.EmailFieldLabel, id = "LoginEmailAddress",
    name="LoginEmail", autofocus = "", required=""})

@PocExtensions.CustomTextBoxForToo(
    this.Html, m => m.EmailAddress, new { @class = "field size4", 
    placeholder = LogOnUIMessages.EmailFieldLabel, 
    id = "LoginEmailAddress", name="LoginEmail", 
    autofocus = "", required=""})

他们都返回:

<input autofocus="" class="field size4" id="LoginEmailAddress" 
name="EmailAddress" placeholder="vul je e-mail adres in" 
required="" type="text" value="">

而不是我的预期:

<input autofocus="" class="field size4" data-val="true" 
data-val-length="Het opgegeven emailadres is te lang." 
data-val-length-max="128" data-val-regex="Het opgegeven adres is niet geldig" 
data-val-regex-pattern="[A-Za-z0-9!#$%&amp;'*+/=?^_`{|}~-]+(?:\.[A-Za-z0-
9!#$%&amp;'*+/=?^_`{|}~-]+)*@(?:[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])
?\.)+[A-Za-z0-9](?:[A-Za-z0-9-]*[A-Za-z0-9])?" 
data-val-required="Dit veld is verplicht." id="LoginEmailAddress" 
name="EmailAddress" placeholder="vul je e-mail adres in" 
required="" type="text" value="">

我做错了什么?

编辑#1,附加信息

IEnumerable<ModelValidator> modelValidators=metadata.GetValidators(htmlHelper.ViewContext); 

返回 4 个验证器。而:

htmlHelper.GetUnobtrusiveValidationAttributes(elementName, metadata);

返回一个空集合?

编辑#2 我找到了问题的原因,但还没有一个干净的解决方案。问题是在 GetTextBoxFor 函数中调用的 GetUnobtrusiveValidationAttributes 函数。 这不会到达我的对象上的数据注释,因为调用函数时使用的名称应该具有 [CLASS].[PROPERTY] 结构,而 ExpressionHelper.GetExpressionText 函数(在 GetTextBoxFor 中使用)仅产生 [PROPERTY] 名称.

现在我想知道,这是一个错误还是设计使然?

我已经设法建立了一个 POC:

public static MvcHtmlString CustomTextBoxFor<TModel, TProperty>(
    this HtmlHelper<TModel> htmlHelper,
    Expression<Func<TModel, TProperty>> expression,
    object htmlAttributes
)
{
    var elementName = ExpressionHelper.GetExpressionText(expression);
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

    var dataAnnotationAttributeDictionary = htmlHelper.GetUnobtrusiveValidationAttributes
(
    String.Format("{0}.{1}", metadata.ContainerType.FullName, elementName),
    metadata
);
var providedAttributeDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);

return htmlHelper.TextBoxFor(expression, providedAttributeDictionary.Concat(dataAnnotationAttributeDictionary).ToDictionary(pair => pair.Key, pair => pair.Value));
    }

现在我的问题是:(如何)这可以做得更好?

【问题讨论】:

  • 使用正则表达式? ;)
  • 我没有看到任何读取属性的代码,那么您认为这应该如何工作?
  • @Daniel:我从我自己的扩展 (CustomTextBoxFor) 中调用执行属性插入的函数 (TextBoxFor)。据我所知,这与直接从 cshtml 调用一样。所以我希望原始方法(TextBoxFor)会根据注释插入所有属性。我的代码只是包装扩展方法的简单测试。
  • 你期望的字符串 - 你从哪里得到它?当您使用@Html.TextBoxFor 而不是@Html.CustomTextBoxFor 时,它会返回吗?
  • 我在问,因为预期的输出与您显示的属性不匹配...

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


【解决方案1】:

在我的助手类中,当我添加数据然后传递给底层 MVC 3 助手时,我使用以下内容:

return InputExtensions.TextBoxFor(htmlHelper, expression, htmlAttributes);

我没有针对这个问题检查 MVC 3 源代码,但我认为通过 htmlHelper 调用是导致问题的原因。

【讨论】:

  • 也试过了:return InputExtensions.TextBoxFor&lt;TModel, TProperty&gt;(htmlHelper, expression, (IDictionary&lt;string, object&gt;) HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); 没有任何区别。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多