Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Model Binding a Dictionary

My controller action method passes a Dictionary<string, double?> to the view. I have the following in my view:

<% foreach (var item in Model.Items) { %>
<%: Html.Label(item.Key, item.Key)%>
<%: Html.TextBox(item.Key, item.Value)%>
<% } %>

Below is my action method which handles the POST operation:

[HttpPost]
public virtual ActionResult MyMethod(Dictionary<string, double?> items)
{
    // do stuff........
    return View();
}

When I enter the some values into the textbox and hit the submit button the POST action method is not getting any items back? What am I doing wrong?

like image 266
Kumar Avatar asked Dec 05 '10 09:12

Kumar


People also ask

What is a model binder?

Model binding is a well-designed bridge between the HTTP request and the C# action methods. Data from HTTP requests are used by controllers and Razor pages. Route data, for example, may serve as a record key, while posted form fields may serve as values for model properties.

How does model binding work in MVC?

Model binding is a well-designed bridge between the HTTP request and the C# action methods. It makes it easy for developers to work with data on forms (views), because POST and GET is automatically transferred into a data model you specify. ASP.NET MVC uses default binders to complete this behind the scene.

What is model binding in web API?

Model Binding is the most powerful mechanism in Web API 2. It enables the response to receive data as per requester choice. i.e. it may be from the URL either form of Query String or Route data OR even from Request Body. It's just the requester has to decorate the action method with [FromUri] and [FromBody] as desired.

What is model binding in .NET core?

Model binding allows controller actions to work directly with model types (passed in as method arguments), rather than HTTP requests. Mapping between incoming request data and application models is handled by model binders.


1 Answers

I would recommend you reading this blog post about how your input fields should be named so that you can bind to a dictionary. So you will need an additional hidden field for the key:

<input type="hidden" name="items[0].Key" value="key1" />
<input type="text" name="items[0].Value" value="15.4" />
<input type="hidden" name="items[1].Key" value="key2" />
<input type="text" name="items[1].Value" value="17.8" />

which could be generated with something along the lines:

<% var index = 0; %>
<% foreach (var key in Model.Keys) { %>
    <%: Html.Hidden("items[" + index + "].Key", key) %>
    <%: Html.TextBox("items[" + index +"].Value", Model[key]) %>
    <% index++; %>
<% } %>

This being said, personally I would recommend you NOT using dictionaries in your views. They are ugly and in order to generate proper names for the model binder you need to write ugly code. I would use view models. Here's an example:

Model:

public class MyViewModel
{
    public string Key { get; set; }
    public double? Value { get; set; }
}

Controller:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var model = new[]
        {
            new MyViewModel { Key = "key1", Value = 15.4 },
            new MyViewModel { Key = "key2", Value = 16.1 },
            new MyViewModel { Key = "key3", Value = 20 },
        };
        return View(model);
    }

    [HttpPost]
    public ActionResult Index(IEnumerable<MyViewModel> items)
    {
        return View(items);
    }
}

View (~/Views/Home/Index.aspx):

<% using (Html.BeginForm()) { %>
    <%: Html.EditorForModel() %>
    <input type="submit" value="OK" />
<% } %>

Editor Template (~/Views/Home/EditorTemplates/MyViewModel.ascx):

<%@ Control 
    Language="C#"
    Inherits="System.Web.Mvc.ViewUserControl<Models.MyViewModel>" %>
<%: Html.HiddenFor(x => x.Key) %>
<%: Html.TextBoxFor(x => x.Value) %>
like image 164
Darin Dimitrov Avatar answered Oct 30 '22 20:10

Darin Dimitrov