2

I have this model with required properties. Yes they are required for creating an item, but when I want to update a single column of them, I get this error about required fields. So it seems that my controller wants to update all of them.

In this case there's an item for sale and one can make an offer for it.

Part of my model:

public class Ad
{
    public int AdID { get; set; }

    [Required()]
    [Display(Name = "Otsikko")]
    public string Title { get; set; }

    [Required()]
    [DataType(DataType.MultilineText)]
    [AllowHtml]
    [Display(Name = "Kuvaus")]
    public string Text { get; set; }

    [Required()]
    [DataType(DataType.Currency)]
    [Display(Name = "Hinta")]
    public float Price { get; set; }

    [DataType(DataType.Currency)]
    [Display(Name = "Tarjottu")]
    public float Offer { get; set; }

My controller:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Offer([Bind(Include = "Offer")] Ad ad)
{
    if (ModelState.IsValid)
    {
       db.Entry(ad).State = EntityState.Modified;
       db.SaveChanges();
       return RedirectToRoute("ilmoitus", new { id = ad.AdID });
    }
    else
    {
       var message = string.Join(" | ", ModelState.Values
       .SelectMany(v => v.Errors)
       .Select(e => e.ErrorMessage));
       return new HttpStatusCodeResult(HttpStatusCode.BadRequest, message);
    }
}

Part of view:

@using (Html.BeginForm("Offer", "Ads"))
{
     @Html.AntiForgeryToken()
     @Html.HiddenFor(model => model.AdID)
     @Html.EditorFor(model => model.Offer, new { htmlAttributes = new { @class = "form-control offer-input", @placeholder = "Tarjoa..." } })
     <button class="btn-default btn offer-btn">Tarjoa {{offer}} €</button>
 }

I've tried this with same error How to Update only single field using EF

Community
  • 1
  • 1
  • Could you please post the exact error? In your linked question I didn't find an error message too. – UeliDeSchwert Jul 29 '16 at 09:12
  • I think the issue is you haven't included all the properties for your Ad entity on your html form, so the post has lost the values. i.e. @Html.HiddenFor(model => model.Price) – Koenyn Jul 29 '16 at 09:13
  • Well the error is just "The x field is required". But hey, thanks, it works now. I added all the values as hidden and bound all the values in controller. It seems a bit silly and not very secure way, but what do I know, it works! – Aapeli Poranen Jul 29 '16 at 09:30

2 Answers2

1

I got it working like this, included all the other properties as hidden and bound them in the controller:

View:

@using (Html.BeginForm("Offer", "Ads"))
{
       @Html.AntiForgeryToken()
       @Html.HiddenFor(model => model.AdID)
       @Html.HiddenFor(model => model.Title)
       @Html.HiddenFor(model => model.Text)
       @Html.HiddenFor(model => model.Price)
       @Html.HiddenFor(model => model.Location)
       @Html.HiddenFor(model => model.PaymentOptions)
       @Html.HiddenFor(model => model.DeliveryOptions)
       @Html.HiddenFor(model => model.SellerEmail)
       @Html.EditorFor(model => model.Offer, new { htmlAttributes = new { @class = "form-control offer-input", @placeholder = "Tarjoa..." } })
       <button class="btn-default btn offer-btn">Tarjoa {{offer}} €</button>
 }

Controller:

[HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Offer([Bind(Include = "AdID,Title,Text,Price,Offer,Location,PaymentOptions,DeliveryOptions,SellerEmail")] Ad ad)
    {
        if (ModelState.IsValid)
        {
            db.Entry(ad).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToRoute("ilmoitus", new { id = ad.AdID });
        }
        else
        {
            var message = string.Join(" | ", ModelState.Values
            .SelectMany(v => v.Errors)
            .Select(e => e.ErrorMessage));
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest, message);
        }

    }

Is this a security issue though?

0

I have two solution for the above query.

  • You can use two different models for updating and insertion example

  • Remove the properties from ModelState then TryUpdateModel

    public ActionResult UpdateAd(Ad ad)
    {
        ModelState.Remove("Title");
        ModelState.Remove("Text");
        ModelState.Remove("Price");
        var p = GetAd();   
        if (TryUpdateModel(p))
        {
             //Save Changes;
        }
     }
    
Community
  • 1
  • 1