无法使用 SetModelValue 修改 ModelState
Posted
技术标签:
【中文标题】无法使用 SetModelValue 修改 ModelState【英文标题】:Cannot modify ModelState using SetModelValue 【发布时间】:2017-05-10 03:38:03 【问题描述】:我正在开发一个 MVC/EF Web 应用程序。在其中一种形式中,我编辑了一个模型。该模型有一个图像字段(public byte[] BioPhoto)
当我将图像上传到该字段并保存数据时,ModelState.IsValid
是 false
,因为在 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>
【问题讨论】:
显示类及其所有验证属性。 我添加了模型 你如何从客户端上传模型中的图像 我正在使用引导文件输入。我加我查看 如果不需要,为什么要标记Required
?
【参考方案1】:
由于您没有使用视图模型,因此您应该为图像使用HttpPostedFileBase
类型的参数。然后在你的action方法中,你可以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();
【讨论】:
OP 刚刚说这是必需的,所以问题在其他地方。 我打赌字节数组字段的数据没有从表单中发布,因此模型验证失败。他不应该从表单中加载和发布 byte array 数据。如果需要,他应该发布一个 HttpPostedFileBase 实例。 删除必需的属性是最后的选择。我仍在尝试了解为什么 SetModelValue 不起作用。无论如何感谢您的回答。当我完成我的研究时,我会标记它。 @Shyju,你是说我使用 HttpPostedFileBase 而不是 byte[] 吗? 您可以将byte[]
用于实体模型,但使用HttpPostedFileBase
接收上传的文件数据,除非您有自定义模型绑定器来进行转换【参考方案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。不过这不是必须的。
【讨论】:
我选择这个答案,因为它比另一个容易得多。无论如何感谢@Shyju。以上是关于无法使用 SetModelValue 修改 ModelState的主要内容,如果未能解决你的问题,请参考以下文章