简体   繁体   English

MVC助手,具有相同参数的方法会产生不同的结果

[英]MVC Helper, Method with same parameters gives different results

I am creating a helper class for MVC and found a problem when the parameter "routeValues" is passed in different ways. 我正在为MVC创建帮助器类,并在以不同方式传递参数“ routeValues”时发现了一个问题。 The methods are created to define some attributes by default. 默认情况下,创建方法来定义一些属性。 The code below is a snippet i am using to explain what my problem is. 下面的代码是我用来解释我的问题的摘要。

I have a method "MyBeginForm()" that does not accept a parameter for "routeValues", the "routeValues" parameter is is passed directly to the "BeginForm" method as null. 我有一个方法“ MyBeginForm()”,该方法不接受“ routeValues”的参数,“ routeValues”参数直接作为null传递给“ BeginForm”方法。 The other method "MyBeginForm(object routeValues)" accepts a parameter for "routeValues" and I have passed "null" value through the parameter. 另一个方法“ MyBeginForm(object routeValues)”接受“ routeValues”的参数,并且我已通过该参数传递了“ null”值。 The problem is that the html generated is different from each other. 问题在于生成的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);
    }
}

The following snippet are used on the html side 以下代码段用于html端

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

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

And the following is the html generated. 而以下是生成的html。 You can see the attributes are generated differently. 您可以看到属性生成的方式有所不同。

<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>

Can someone explain why this is happening and how i can solve it please. 有人可以解释为什么会这样,我如何解决。

You are mixing the types of routeValues and htmlAttributes parameters. 您正在混合routeValueshtmlAttributes参数的类型。

There are 2 overloads of BeginForm that expect 5 parameters: BeginForm有2个重载, BeginForm需要5个参数:

  • One where routeValues and htmlAttributes are both declared as anonymous objects . 其中routeValues和htmlAttributes都声明为匿名对象 See msdn 参见msdn

  • Another where routeValues is of type RouteValueDictionary and htmlAttributes is of type IDictionary<string, Object> . routeValues的类型为RouteValueDictionary且htmlAttributes的类型为IDictionary<string, Object>的类型。 See msdn 参见msdn

However in your helper, you have mixed the types. 但是,在您的助手中,您混合了各种类型。 The htmlAttributes are declared as a dictionary and the routeValues as an object. htmlAttributes被声明为字典,而routeValues被声明为对象。

The MyBeginForm overload without arguments works because you pass null as the routeValues arguments, so the compiler uses the type of the other arguments to decide which overload of BeginForm should be used. 没有参数的MyBeginForm重载可以工作,因为您将null作为routeValues参数传递,所以编译器使用其他参数的类型来确定应使用BeginForm重载。 As the htmlAttributes is a dictionary it will use the second overload I describe above. 由于htmlAttributes是一个字典,它将使用我上面描述的第二个重载。 You could quickly try changing that method of yours to force the null routeValues as of type object, which would force the wrong overload to be picker and you would get the same unexpected html: 您可以快速尝试更改您的方法,以将null的routeValues强制为object类型,这将迫使错误的重载成为选择器,并且您将得到相同的意外html:

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

In the same way, your second MyBeginForm overload doesn´t work as you expected because you have declared routeValues of type object, so the compiler will always get the first overload I mentioned above (where both routeValues and htmlAttributes are treated as anonymous objects). 同样,第二个MyBeginForm重载MyBeginForm按预期工作,因为您已声明类型为object的routeValues,因此编译器将始终获得上述的第一个重载(其中routeValues和htmlAttributes均被视为匿名对象)。

Now that you know what´s going, you just need to make sure you are picking the right overload to fix your issue. 现在,您知道发生了什么,您只需要确保选择正确的过载即可解决问题。 I would fix the MyBeginForm overload that allows routeValues to be specified, and then update the overload without parameters to call this one (avoiding duplicated code). 我将修复允许指定routeValues的MyBeginForm重载,然后更新不带参数的重载以调用此重载(避免重复的代码)。

The easiest way to fix it would be to define the htmlAttributes inside the method as an anonymous object: 修复它的最简单方法是将方法内部的htmlAttributes定义为匿名对象:

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

The other option consists in declaring routeValues parameter as an RouteValuesDictionary, so you can keep defining the htmlAttributes as a dictionary. 另一个选项在于将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);
}

In both cases, calling your helper passing null as parameter will render the expected html (Although I prefer using routeValues as an anonymous object): 在这两种情况下,调用传递null作为参数的助手将呈现预期的html(尽管我更喜欢使用routeValues作为匿名对象):

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

You could then update the first overload of your helper like this: 然后,您可以像这样更新助手的第一个重载:

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

Now both overloads of MyBeginForm should work as you expected. 现在, MyBeginForm两个重载都MyBeginForm预期工作。

Hope it helps! 希望能帮助到你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM