MVC UpdateModel is not updating some of the model properties

1.6k views Asked by At

In my MVC 5 EF Database First project I have been using UpdateModel method in my controller action successfully, but after including some additional fields (previously unused by application) I find that the new fields simply refuse to get values from the UpdateModel method call. The only thing of any significance I can identify is that the fields share part of their name.

Consider this class as an example:

public class Record
{
public int ID {get;set;}
public string Details {get;set;}
public string DetailsFile {get;set;}
...
}

The property/field DetailsFile was previously unused, but now is an optional field on the web form. It is stored in a <input type="hidden" name="DetailsFile" id="DetailsFile /> and is successfully posted to the controller action with the correct value (or empty string).

Within the controller action I handle the update like this:

[HttpPost]
public async Task<ActionResult> Edit(Record_EditView model, FormCollection collection)
{
    if (ModelState.IsValid)
    {
        try
        {
            var record = await db.Record.FindAsync(model.ID);
            UpdateModel(record, collection);
            db.Entry(record).State = EntityState.Modified;
            await db.SaveChangesAsync();
        }
        catch(Exception ex)
        {
            throw ex;
        }
    }
    // do more stuff here
    ...
}

Which has been working fine, but with the additional field all fields except the DetailsFile get updated from the FormCollection that is passed in. I have inspected both the model and the collection and they have the correct value, but the record never gets the values until I do a second post of the same data. Then the values get pushed in to the fields as expected.

I don't get any errors thrown and am at a bit of a loss as to what is going on. For the time being I have resorted to modifying my controller action to this:

[HttpPost]
public async Task<ActionResult> Edit(Record_EditView model, FormCollection collection)
{
    if (ModelState.IsValid)
    {
        try
        {
            var record = await db.Record.FindAsync(model.ID);
            UpdateModel(record, collection);
            record.DetailsFile = collection["DetailsFile"]; // <-- Manually insert DetailsFile value
            db.Entry(record).State = EntityState.Modified;
            await db.SaveChangesAsync();
        }
        catch(Exception ex)
        {
            throw ex;
        }
    }
    // do more stuff here
    ...
}

And this works OK, however I'm sure that I shouldn't have to do this, and hope that someone out there can explain what I am overlooking!

1

There are 1 answers

0
adamc-au On

Finally found the problem, it is not likely to benefit many people but just in case here is the answer.

More Information

In my project I started using a jquery plugin for styling file input elements in a more bootstrap fashion, namely Jasny Bootstrap.

The plugin works great, however as part of it's internal workings it takes steps to maintain state of existing data and avoid post conflict by using hidden input and renaming the file input like this:

this.$hidden.val('')
this.$hidden.attr('name', '')
this.$input.attr('name', this.name)

The Problem

Which ends up with element(s) that have an attribute name="" and that caused the page to post the element and the FormCollection to include an empty/"" item(s).

Despite the fact that no errors were thrown, nonetheless it seems to break the call to

UpdateModel(record,collection)

The Solution

To fix this and avoid posting the selected file (my project doesn't actually want the file to be posted, just the file path) I just intercept the form submit to remove the unwanted form elements prior to posting:

$('form').submit(function (e) {
    e.preventDefault();
    // get rid of any input elements that have name="" or file elemnts so will not mess with the posted form collection
    $('input[name=""],input[type="file"]').remove();
    this.submit();
})