web-dev-qa-db-ja.com

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フラグが問題なく設定されていることです-画像データがnullです。

写真のバイト配列がコントローラーに投稿されたモデルに含まれるように、何を変更する必要があるかを誰かに教えてもらえますか?

15
Rob Bowman

ビューに入力されたファイルの名前はuploadImagesです。この名前のプロパティがビューモデルに表示されません。バイト配列であるいくつかのImageDataプロパティを持っているようですが、ビューにこの名前の対応する入力フィールドがないようです。

これは、nullになる理由を説明しています。慣習を尊重することで、この作業を行うことができます。たとえば、ビューにそのような入力フィールドを含めるつもりなら、

<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ビューモデルクラスがあります。

25
Darin Dimitrov

この行を変更します。

@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);
 }
3
acfrancis

見る:

@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;
    ...
}
1
joe