【问题标题】:MVC Helper, Method with same parameters gives different resultsMVC Helper,具有相同参数的方法给出不同的结果
【发布时间】:2014-05-27 07:05:09
【问题描述】:

我正在为 MVC 创建一个辅助类,并在以不同方式传递参数“routeValues”时发现问题。默认情况下,创建这些方法是为了定义一些属性。下面的代码是我用来解释我的问题的 sn-p。

我有一个方法“MyBeginForm()”,它不接受“routeValues”的参数,“routeValues”参数直接作为空值传递给“BeginForm”方法。另一种方法“MyBeginForm(object routeValues)”接受“routeValues”的参数,我通过参数传递了“null”值。问题是生成的html不一样。

//Custom Class for custom attributes
public class MyHtmlHelper<TModel>
{
    private readonly HtmlHelper<TModel> htmlHelper;

    internal MyHtmlHelper(HtmlHelper<TModel> htmlHelper)
    {
        this.htmlHelper = htmlHelper;
    }

    //Here the routeValues parameter of Begin Form is passed directly to the method as null
    public MvcForm MyBeginForm()
    {
        var myAttributes = new Dictionary<string, object>(){
            {"test", "value"},
            {"test2", "value2"},
        };

        return htmlHelper.BeginForm("Index", "Home", null, FormMethod.Post, myAttributes);
    }

    //Here I have passed the null value through the parameter
    public MvcForm MyBeginForm(object routeValues)
    {
        var myAttributes = new Dictionary<string, object>(){
            {"test", "value"},
            {"test2", "value2"},
        };

        return htmlHelper.BeginForm("Index", "Home", routeValues, FormMethod.Post, myAttributes);
    }
}

//This class is used for static call in html
public static class MyHtmlHelperkEx
{
    public static MyHtmlHelper<TModel> MyHtmlHelper<TModel>(this HtmlHelper<TModel> htmlHelper)
    {
        return new MyHtmlHelper<TModel>(htmlHelper);
    }
}

html端使用如下sn-p

<h1>Without Parameter</h1>
@using (Html.MyHtmlHelper().MyBeginForm()) { }

<h1>With parmeter</h1>
@using (Html.MyHtmlHelper().MyBeginForm(null)) { }

以下是生成的html。您可以看到属性的生成方式不同。

<h1>Without Parameter</h1>
<form action="/" method="post" test="value" test2="value2">
    System.Web.Mvc.Html.MvcForm
</form>

<h1>With parmeter</h1>
<form comparer="System.Collections.Generic.GenericEqualityComparer`1[System.String]" count="2" keys="System.Collections.Generic.Dictionary`2+KeyCollection[System.String,System.Object]" values="System.Collections.Generic.Dictionary`2+ValueCollection[System.String,System.Object]" action="/" method="post"></form>

有人可以解释为什么会发生这种情况以及我该如何解决。

【问题讨论】:

    标签: c# html asp.net-mvc-4 generics form-helpers


    【解决方案1】:

    您正在混合 routeValueshtmlAttributes 参数的类型。

    BeginForm 有 2 个重载,需要 5 个参数:

    • routeValues 和 htmlAttributes 都声明为 匿名对象。见msdn

    • 另一个 routeValues 的类型为 RouteValueDictionary 和 htmlAttributes 的类型为IDictionary&lt;string, Object&gt;。看 msdn

    但是在你的助手中,你混合了类型。 htmlAttributes 被声明为字典,而 routeValues 被声明为对象。

    不带参数的 MyBeginForm 重载有效,因为您将 null 作为 routeValues 参数传递,因此编译器使用其他参数的类型来决定应该使用 BeginForm 的哪个重载。由于 htmlAttributes 是一个字典,它将使用我上面描述的第二个重载。 您可以快速尝试更改您的方法以强制将 null routeValues 设为对象类型,这将强制错误的重载成为选择器,并且您会得到相同的意外 html:

    return htmlHelper.BeginForm("Index", "Home", (object)null, FormMethod.Post, myAttributes);
    

    同样,您的第二个MyBeginForm 重载无法按预期工作,因为您声明了 object 类型的 routeValues,因此编译器将始终获得我上面提到的第一个重载(同时处理 routeValues 和 htmlAttributes作为匿名对象)。

    既然您知道发生了什么,您只需要确保选择正确的过载来解决您的问题。我将修复允许指定 routeValues 的 MyBeginForm 重载,然后更新不带参数的重载以调用它(避免重复代码)。

    修复它的最简单方法是将方法内的 htmlAttributes 定义为匿名对象:

    public MvcForm MyBeginForm(object routeValues)
    {
        var myAttributes = new{
            test = "value",
            test2 = "value2",
        };
        return htmlHelper.BeginForm("Index", "Home", routeValues, FormMethod.Post, myAttributes);
    }
    

    另一个选项是将 routeValues 参数声明为 RouteValuesDictionary,因此您可以继续将 htmlAttributes 定义为字典。

    public MvcForm MyBeginForm(RouteValueDictionary routeValues)
    {
        var myAttributes = new Dictionary<string, object>(){
            {"test", "value"},
            {"test2", "value2"},
        };
        return htmlHelper.BeginForm("Index", "Home", routeValues, FormMethod.Post, myAttributes);
    }
    

    在这两种情况下,调用你的助手传递 null 作为参数将呈现预期的 html(虽然我更喜欢使用 routeValues 作为匿名对象):

    <form action="/" method="post" test="value" test2="value2"></form>
    

    然后您可以像这样更新助手的第一个重载:

    public MvcForm MyBeginForm()
    {            
        return MyBeginForm(null);
    }
    

    现在MyBeginForm 的两个重载应该可以按预期工作。

    希望对你有帮助!

    【讨论】:

    • 非常感谢。我没有意识到它选择了不同的重载方法。再次感谢。
    猜你喜欢
    • 2014-04-19
    • 2017-10-16
    • 2019-03-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-13
    • 1970-01-01
    • 2013-10-15
    • 1970-01-01
    相关资源
    最近更新 更多