Phil Mar
Phil Mar

Reputation: 157

ASP.Net Core 2.0 MVC dynamic model updating

I'm trying to build a dynamic view, where I can pass a list of properties that need to be filled in by the user.

The collection of properties is dynamic, so I can't build the view that displays specific properties.

I've been able to display the property names and their initial values, and the user can change the values on the screen, but those updated values don't make it to the controller action that would update the model.

I've tried using a dynamic model, as well as a list of key/value pairs.

I'm thinking that it has something to do with the over-posting protection. Since the properties are dynamic, I can't list them in the Bind attribute in the update action.

Here's the controller action methods:

public IActionResult Test()
{
    dynamic testObj = new ExpandoObject();
    testObj.IntProperty = 100;
    testObj.StringProperty = "A String Value";
    return View(testObj);
}

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Test(ExpandoObject model)
{
    return Ok();
}

Here's the view:

@model dynamic

@{
    ViewData["Title"] = "Test";
}

<form asp-action="Test" method="post">
    <div class="form-horizontal">
        @foreach (var propertyName in ((System.Collections.Generic.IDictionary<string, object>)Model).Keys)
        {        
            <div class="form-group">
                <label class="col-md-2 control-label">@propertyName</label>
                <div class="col-md-10">
                    @Html.TextBox(propertyName, ((System.Collections.Generic.IDictionary<string, object>)Model)[propertyName])
                </div>
            </div>
        }
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>

This is a new application, and I'm doing code-first - so the model can be changed somewhat. All I really need to do is to be able to have different properties that can be updated.

Thanks in advance.

Upvotes: 0

Views: 2596

Answers (1)

Transcendent
Transcendent

Reputation: 5755

I recommend that you do not rely on the IModelBinder for this purpose at all and why I recommend this is because the form data that is passed between the controller and view is dynamic in terms of structure. A better, yet more troublesome, solution would be to get the form data directly out of the HttpContext.Request.Form. This type has an indexer which allows you to access the posted values by their names. For example

var name = HttpContext.Request.Form["name"].FirstOrDefault();

The .FirstOrDefault() (or SingleOrDefault(), this throws an exception when finding more than a value that meets a condition in a collection) is called assuming that there would be a single value (or a single value that meets a condition) for the "Name" input. However, when you have an array of those, you can get the values either in a foreach loop, or using linq methods, or directly by an index. For example:

 var name = HttpContext.Request.Form["name"].FirstOrDefault(x=> x.ToString().StartsWith("x"));
 var name = HttpContext.Request.Form["name"][0];

Upvotes: 2

Related Questions