Загрузить изображение, включенное в модель MVC
У меня есть следующая модель:
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>
}
Вид отображается в порядке и позволяет пользователю выбирать файл со своего локального диска и вводить другие данные модели.
Моя проблема в том, что, хотя модель отправляется на контроллер в порядке, флаги описания, даты и IsActive заполняются нормально - данные изображения равны нулю.
Может кто-нибудь, пожалуйста, сообщите мне, что мне нужно изменить, чтобы массив байтов для фотографии был включен в модель, отправленную в контроллер?
Ответы
Ответ 1
Файл ввода в вашем представлении имеет имя uploadImages
. Я не вижу недвижимость с таким именем в вашей модели просмотра. Кажется, у вас ImageData
свойство 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
что вы могли бы проконсультироваться.
Поэтому, как только вы добавляете HttpPostedFileBase
свойство с UploadImages
именем в модели представления можно адаптировать действие контроллера для чтения массива байт и сохранить его ваш 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
который будет выполнять действие вашего контроллера.
Ответ 2
Измените эту строку:
@using (Html.BeginForm())
Для этого:
@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
Затем измените:
<input type="file" name="uploadImages" class="input-files" />
To:
<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);
}
Ответ 3
Вид:
@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;
...
}
Ответ 4
@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
Теперь он работает Спасибо, acfrancis