Загрузить изображение, включенное в модель 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