0
votes

So the ViewModel has 2 sets of data. The CurrentDetails and UpdatedDetails. Both are instances of the same class which carries strings and whatnot inside etc.

This method has worked with all other views and models I've attempted with, but for THIS one instance, when the form is posted to the controller, its contents (CurrentDetails and UpdatedDetails) are both found to be null.

I've tried changing the parameter name from model to test and to other arbitrary things, but to no avail.

The one thing that worked (but is not a solution to me) is NOT having instances of the class inside the ViewModel, and just having the data there (but I don't see why I should be forced to do things this way.

Here's the controller:

[HttpPost]
public ActionResult FloristProfile(MerchantFloristProfileViewModel test)
{
    if (!ModelState.IsValid)
        return View(test);

    using (var db = new ApplicationDbContext())
    {
        Florist florist = db.Florists.Find(MerchantBase.FloristID);
        if (Request.Form["editSubmit"] != null)
        {
            florist.Name = test.UpdatedDetails.Name;
            florist.Website = test.UpdatedDetails.Website;
            db.SaveChanges();
            return RedirectToAction("FloristProfile");
        }
        else if (Request.Form["photoSubmit"] != null)
        {
            if (test.CurrentDetails.File.ContentLength > 0)
            {
                CloudBlobContainer container = FlowerStorage.GetCloudBlobContainer();
                string blobName = String.Format("florist_{0}.jpg", Guid.NewGuid().ToString());
                CloudBlockBlob photoBlob = container.GetBlockBlobReference(blobName);
                    photoBlob.UploadFromStream(test.CurrentDetails.File.InputStream);
                florist.LogoPath = blobName;
                florist.isRendering = true;
                db.SaveChanges();
                return RedirectToAction("FloristProfile");
            }
        }
    }
    return Content("Invalid Request");
}

View:

@using (Html.BeginForm("FloristProfile", "Merchant", FormMethod.Post, new { @class = "form-horizontal" }))
{
    @Html.ValidationSummary(false, "", new { @class = "text-danger" })
    @Html.HiddenFor(x => x.CurrentDetails.FloristID)
    @Html.HiddenFor(x => x.CurrentDetails.Name)
    @Html.HiddenFor(x => x.CurrentDetails.StaffCount)
    @Html.HiddenFor(x => x.CurrentDetails.StoreCount)
    @Html.HiddenFor(x => x.CurrentDetails.Website)
    <div class="form-group">
        @Html.LabelFor(x => x.UpdatedDetails.Name, new { @class = "col-sm-2 control-label" })
        <div class="col-sm-10">
            @Html.TextBoxFor(x => x.UpdatedDetails.Name, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        @Html.LabelFor(x => x.UpdatedDetails.Website, new { @class = "col-sm-2 control-label" })
        <div class="col-sm-10">
            @Html.TextBoxFor(x => x.UpdatedDetails.Website, new { @class = "form-control" })
        </div>
    </div>
    <div class="form-group">
        <div class="col-sm-offset-2 col-sm-10">
            <button type="submit" name="editSubmit" class="btn btn-success">Save</button>
        </div>
    </div>
}

ViewModel:

public class MerchantFloristProfileViewModel
{
    public class FloristProfileDetails
    {
        public int FloristID { get; set; }
        [Required(ErrorMessage = "Please Enter a Name")]
        public string Name { get; set; }
        [DataType(DataType.Url)]
        [Required(ErrorMessage = "Please Enter a Website")]
        public string Website { get; set; }
        public int StoreCount { get; set; }
        public int StaffCount { get; set; }
        // For Picture Upload
        public HttpPostedFileBase File { get; set; }
    }
    public FloristProfileDetails CurrentDetails;
    public FloristProfileDetails UpdatedDetails;
}
1

1 Answers

3
votes

Both CurrentDetails and UpdatedDetails in your MerchantFloristProfileViewModel model are fields, not properties (no getter/setter) so the DefaultModelBinder cannnot set the values. Change them to

public FloristProfileDetails CurrentDetails { get; set; }
public FloristProfileDetails UpdatedDetails { get; set; }

But you should not be sending all that extra data to the view, then sending it all back again unchanged. Apart from the extra overhead, any malicious user could alter the values in the hidden fields causing your app to fail. Just get the original from the repository again if you need it in the POST method