无法使用SetModelValue修改ModelState

时间:2016-12-25 02:18:31

标签: c# asp.net-mvc entity-framework model-view-controller

我正在研究MVC / EF Web应用程序。在其中一种形式中,我编辑了一个模型。该模型具有图像字段(public byte[] BioPhoto)

当我将图片上传到该字段并保存数据时,ModelState.IsValidfalse,因为ModelState中的BioPhoto属性为null。请注意,模型中的BioPhoto加载了图像数据。

我尝试使用下面的代码将图片注入ModelState,但ModelState.IsValid仍为false

public ActionResult Edit([Bind(Include = "BusinessId,Name,About,Phone,TollFree,FAX,Email,Bio,BioPhoto")] Business business)
{
    if (System.IO.File.Exists("image.jpg"))
    {
        business.BioPhoto = System.IO.File.ReadAllBytes("image.jpg");
        ModelState.SetModelValue("BioPhoto", 
                   new ValueProviderResult(business.BioPhoto, "", System.Globalization.CultureInfo.InvariantCulture));
    }

    if (ModelState.IsValid)
    {
        db.Entry(business).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(business);
}

我做错了什么。对于这个问题有没有更好的解决方案?

我在SO中读了几个答案,但无法弄清楚如何解决我的问题。

这是我的模特

public class Business
{
    public int BusinessId { get; set; }

    [Required]
    [StringLength(100)]
    public string Name { get; set; }

    [Required]
    public Address address { get; set; }

    [Required]
    [StringLength(20)]
    public string Phone { get; set; }

    [StringLength(20)]
    public string TollFree { get; set; }

    [StringLength(20)]
    public string FAX { get; set; }

    [Required]
    [StringLength(50)]
    public string Email { get; set; }

    [Required]
    [StringLength(100)]
    public string WebSite { get; set; }

    [Required]
    public string About { get; set; }

    [Required]
    public string Bio { get; set; }

    [Required]
    public byte[] BioPhoto { get; set; }
}

我的观点

<div class="form-group">
    @Html.LabelFor(model => model.BioPhoto, "BIO Photo (Best Size: 350 x 450)", htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        <form enctype="multipart/form-data">
            <div class="form-group" style="width:400px">
                <input id="BioPhoto" type="file" multiple class="file" data-overwrite-initial="false" />
            </div>
        </form>
        @Html.ValidationMessageFor(model => model.BioPhoto, "", new { @class = "text-danger" })
    </div>
</div>

2 个答案:

答案 0 :(得分:2)

就像我说的那样,问题是表单没有将BioPhoto发布到控制器 - 最有可能。您可以使用Chrome查看http请求正文中的内容。

如果您想要添加图像,即使控制器没有接收到它,请尝试此操作。

尝试仅删除与图像属性相关的错误:

ModelState["BioPhoto"].Errors.Clear();

然后添加图片:

business.BioPhoto = System.IO.File.ReadAllBytes("image.jpg");

然后更新模型:

UpdateModel(business);

现在,如果您致电ModelState.IsValid,则需要考虑BioPhoto的设置并重新评估IsValid

编辑:

我建议打电话

ModelState.SetModelValue("BioPhoto", new ValueProviderResult(business.BioPhoto, "", System.Globalization.CultureInfo.InvariantCulture));

实际将值推送到ModelState.Values。但这不是必要的。

答案 1 :(得分:0)

由于您未使用视图模型,因此应为图像使用类型为HttpPostedFileBase的参数。然后在您的操作方法中,您可以convert it's InputStream property value to byte array并保存它。

public ActionResult Edit([Bind(Include = "BusinessId,Name,About,Phone,TollFree,
                    FAX,Email,Bio")] Business business,HttpPostedFileBase BioPhoto)
{
   // to do read BioPhoto.InputStream and convert to your byteArray
   // to do  :Return something
}

您必须从模型类的字节数组属性中删除[Required]属性。

最佳解决方案是使用视图模型,该视图模型仅包含您所需的属性。您不需要每次都从编辑屏幕重新发布图像。仅当用户在编辑表单中选择新图像时才更新该属性。如果不是,请在保存时不更新该列的现有值。

public class EditBusinessVm
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Name { get; set; }

    [Required]
    public Address address { get; set; }

    [Required]
    [StringLength(20)]
    public string Phone { get; set; }

    public HttpPostedFileBase BioPhoto { set;get;}

    // Add other properties as needed.
}

现在您的观点必须强烈输入此类

@model EditBusinessVm
@using(Html.BeginForm())
{
  @Html.TextBoxFor(s=>s.Name)
  <input type="file" name="BioPhoto" />
  @Html.HiddenFor(f=>f.Id)
  <!-- add other fields needed -->
  <input type="submit"  />
}

并且您的httppost操作方法将使用此类型作为参数

public ACtionResult Edit(EditBusinessVm model)
{
  // purposefully omitting null checks/model validations code here

   //get existing entity
   var b=db.Businesses.FirstOrDefault(f=>f.BusinessId==model.Id);
  //update the properties from the posted view model
   b.Name = model.Name;
   if(model.BioPhoto!=null)  // user selected a new photo.
     b.BioPhoto = GetByteArray(model.BioPhoto);
   // to do : Set other properties as well.

   db.Entry(business).State = EntityState.Modified;
   db.SaveChanges();
   return RedirectToAction("Index");

}
private byte[] GetByteArray(HttpPostedFileBase file)
{
   MemoryStream target = new MemoryStream();
   file.InputStream.CopyTo(target);
   return target.ToArray();      
}