2013-12-07 130 views
12

我有以下型号:上传图像

public class Photo 
{ 
    public int PhotoId { get; set; } 
    public byte[] ImageData { get; set; } 
    public DateTime DateUploaded { get; set; } 
    public string Description { get; set; } 
    public bool IsActive { get; set; } 

} 

我希望用户能够进入细节的照片,然后上传模型中的控制器。我的控制器操作如下:

[HttpPost] 
    public ActionResult Create(WilhanWebsite.DomainClasses.Photo photo) 
    { 
     if (ModelState.IsValid) 
     { 
      photo.DateUploaded = DateTime.Now; 
      _context.Photos.Add(photo); 
      _context.SaveChanges(); 

      return RedirectToAction("Index"); 
     } 
     //we only get here if there was a problem 
     return View(photo); 
    } 

我的看法如下:

@using (Html.BeginForm()) 
{ 
@Html.AntiForgeryToken() 

<div class="form-horizontal"> 
    <h4>Photo</h4> 
    <hr /> 
    @Html.ValidationSummary(true) 

    <div class="form-group"> 
     @Html.LabelFor(model => model.ImageData, new { @class = "control-label col-md-2" }) 
     <div class="col-md-10"> 
      <input type="file" name="uploadImages" class="input-files" /> 
     </div> 
    </div> 

    <div class="form-group"> 
     @Html.LabelFor(model => model.DateUploaded, new { @class = "control-label col-md-2" }) 
     <div class="col-md-10"> 
      @Html.EditorFor(model => model.DateUploaded) 
      @Html.ValidationMessageFor(model => model.DateUploaded) 
     </div> 
    </div> 

    <div class="form-group"> 
     @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" }) 
     <div class="col-md-10"> 
      @Html.EditorFor(model => model.Description) 
      @Html.ValidationMessageFor(model => model.Description) 
     </div> 
    </div> 

    <div class="form-group"> 
     @Html.LabelFor(model => model.IsActive, new { @class = "control-label col-md-2" }) 
     <div class="col-md-10"> 
      @Html.EditorFor(model => model.IsActive) 
      @Html.ValidationMessageFor(model => model.IsActive) 
     </div> 
    </div> 

    <div class="form-group"> 
     <div class="col-md-offset-2 col-md-10"> 
      <input type="submit" value="Create" class="btn btn-default" /> 
     </div> 
    </div> 
</div> 
} 

视图显示OK,并允许用户从他们的本地磁盘中选择一个文件,然后输入其他模型的细节。 我的问题是,虽然模型发布到控制器ok,说明,日期和IsActive标志填充好 - 图像数据为空。

任何人都可以让我知道我需要改变什么,以便照片的字节数组包含在发布到控制器的模型中?

回答

19

您视图中的文件输入名称为uploadImages。在视图模型中,我看不到具有此名称的属性。您似乎有一些ImageData属性,它是一个字节数组,但在您的视图中似乎没有与此名称对应的输入字段。

这解释了为什么你会得到空值。你可以通过尊重约定来完成这项工作。因此,例如,如果你打算在你考虑到这样的输入域:

<input type="file" name="uploadImages" class="input-files" /> 

然后确保你有相同名称的视图模型的属性。当然还有HttpPostedFileBase

public HttpPostedFileBase UploadImages { get; set; } 

而且在您的视图确保您设置的multipart/form-data正确的内容类型:

@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" })) 
{ 
    ... 
} 

你或许可能要经过following blog post更好地与如何上传的基本知识熟悉文件在ASP.NET MVC中工作。我还写了一个similar answer here,你可能会咨询。

所以一旦你在你的视图模型与UploadImages名称添加HttpPostedFileBase属性,你可以调整你的控制器动作读取字节数组,并将其存储您的ImageData属性:

[HttpPost] 
public ActionResult Create(WilhanWebsite.DomainClasses.Photo photo) 
{ 
    if (ModelState.IsValid) 
    { 
     photo.DateUploaded = DateTime.Now; 
     photo.ImageData = new byte[photo.UploadImages.ContentLength]; 
     photo.UploadImages.Read(photo.ImageData, 0, photo.ImageData.Length); 

     _context.Photos.Add(photo); 
     _context.SaveChanges(); 

     return RedirectToAction("Index"); 
    } 

    //we only get here if there was a problem 
    return View(photo); 
} 

现在牢记这是一个绝对糟糕的解决方案。切勿在真实世界的应用程序中这样做。在设计正确的应用程序中,您将拥有一个视图模型,您的控制器操作将作为参数。您永远不会直接使用自动生成的EF模型作为控制器操作的参数。您将拥有一个包含HttpPostedFileBase属性的视图模型,该属性将映射到您的域模型。

因此,在设计正确的应用程序中,您的控制器操作将采用PhotoViewModel视图模型类。

+0

另一个伟大的答案感谢达林。我将创建一个专门的视图模型。我为这个解决方案使用了一个存储库项目,但是我发现额外的抽象层真的使我的moq'd单元测试复杂化了。 –

+0

非常好的答案谢谢! +1 –

+0

不应该是这样的:'photo.UploadImages.InputStream.Read' –

1

改变这一行:

@using (Html.BeginForm()) 

要这样:

@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" })) 

然后改变:

<input type="file" name="uploadImages" class="input-files" /> 

要:

<input type="file" name="ImageData" class="input-files" /> 

然后改变这行:

public byte[] ImageData { get; set; } 

向该:

public HttpPostedFileBase ImageData { get; set; } 

最后,使用像这样的代码来读取图像入一个字节数组:

var bs = new byte[ImageData.ContentLength]; 
using (var fs = ImageData.InputStream) 
{ 
    var offset = 0; 
    do 
    { 
     offset += fs.Read(bs, offset, bs.Length - offset); 
    } while (offset < bs.Length); 
} 
1

检视:

@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" })) 
{ 
    ... 
    <input type="file" id="ImageFile" name="ImageFile" .../> 
    ... 
} 

控制器:

[HttpPost] 
public ActionResult Create(Photo photo, HttpPostedFileBase ImageFile) 
{ 
    byte[] buf = new byte[ImageFile.ContentLength]; 
    ImageFile.InputStream.Read(buf, 0, buf.Length); 
    photo.ImageData = buf; 
    ... 
}