Home > Software engineering >  .NET 6 - Model Binding a Dictionary property returning unexpected value
.NET 6 - Model Binding a Dictionary property returning unexpected value

Time:09-30

On my PageModel, I have a property that is of type ConcurrentDictionary<string, string> and I want to bind that property. However, applying the [BindProperty] attribute to that property doesn't work. The dictionary is populated with information about the PageModel itself, not the expected content of the dictionary.

Page:

@page
@model MyApp.Pages.MyPageModel

<h6>Dictionary</h6>
<dl>
    @foreach (var key in Model.Dict.Keys)
    {
        <dt>@key</dt>
        <dd>@Model.Dict[key]</dd>
    }
</dl>

<h6>Concurrent Dictionary</h6>
<dl>
    @foreach (var key in Model.ConcurrentDict.Keys)
    {
        <dt>@key</dt>
        <dd>@Model.ConcurrentDict[key]</dd>
    }
</dl>

<form method="post">
    <input type="submit" value="submit" />
</form>

PageModel:

namespace MyApp.Pages;

using System.Collections.Concurrent;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

[AllowAnonymous]
public class MyPageModel : PageModel
{
    [BindProperty]
    public ConcurrentDictionary<string, string> ConcurrentDict { get; set; }

    [BindProperty]
    public Dictionary<string, string> Dict { get; set; }

    public IActionResult OnGet()
    {
        ConcurrentDict = new()
        {
            ["concurrent_foo"] = "concurrent_bar"
        };

        Dict = new()
        {
            ["foo"] = "bar"
        };

        return this.Page();
    }

    public IActionResult OnPost()
    {
        return this.Page();
    }
}

After a GET request:

response for GET request

After a POST request (form submission):

response for POST request

Anyone have an idea what's going on here? Any known work-around? Obviously .NET's built-in model binding doesn't play nicely with dictionaries... But I sure would like it to.

CodePudding user response:

You need to pass the values of dictionaries when submitting the form.If you don't want to show the inputs,add hidden:

<form method="post">

    @for (var i = 0; i < Model.ConcurrentDict.Count; i  )
    {
        <input name="ConcurrentDict[@i].Key" value="@Model.ConcurrentDict.ElementAt(i).Key" hidden />
        <input name="ConcurrentDict[@i].Value" value="@Model.ConcurrentDict.ElementAt(i).Value" hidden />
    }
    @for (var i = 0; i < Model.Dict.Count; i  )
    {
        <input name="Dict[@i].Key" value="@Model.Dict.ElementAt(i).Key" hidden />
        <input name="Dict[@i].Value" value="@Model.Dict.ElementAt(i).Value" hidden />
    }
    <input type="submit" value="submit" />
</form>
  • Related