私のプロジェクトでは、ブロブや画像などのさまざまなデータを保存する必要がしばしばあります。 この記事では、さまざまな画像を含むモデルからのデータバインディングを簡単に整理して使用する方法を示したいと思います。 たとえば、 MVC Music Storeトレーニングプロジェクトを取り上げて、それを微調整することにしました-音楽アルバムの表紙の画像を変更する機能を追加します。 この記事を書くときは、APS.NET MVC 3とRazorのバージョンを使用しました。
バインディング実装
一般に、データバインディングは、モデルデータを読み込んで保存するように設計されています。 デフォルトのデータバインディングをカスタマイズするクラスを実装します。
public class ImageModelBinder : DefaultModelBinder { private string _fieldName; public ImageModelBinder(string fieldName) { _fieldName = fieldName; } public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { var obj = base.BindModel(controllerContext, bindingContext); ValueProviderResult valueResult; valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + "." + _fieldName); if (valueResult == null) { valueResult = bindingContext.ValueProvider.GetValue(_fieldName); } if (valueResult != null) { HttpPostedFileBase file = (HttpPostedFileBase)valueResult.ConvertTo(typeof(HttpPostedFileBase)); if (file != null) { byte[] tempImage = new byte[file.ContentLength]; file.InputStream.Read(tempImage, 0, file.ContentLength); PropertyInfo imagePoperty = bindingContext.ModelType.GetProperty(_fieldName); imagePoperty.SetValue(obj, tempImage, null); } } return obj; } }
この実装では、メインのBindModelメソッドを再定義し、最初に基本実装を呼び出してすべてのデータをバインドし、次にHttpPostedFileBaseタイプのHTTPリクエストフォームフィールドから画像データフィールドへの変換と書き込みを実装しました。
属性を作成するのもいいでしょう:
public class ImageBindAttribute : CustomModelBinderAttribute { private IModelBinder _binder; public ImageBindAttribute(string fieldName) { _binder = new ImageModelBinder(fieldName); } public override IModelBinder GetBinder() { return _binder; } }
ビューを作成するには、ファイルアップロードフィールドを作成するための簡単なヘルパーも必要です。
public static IHtmlString ImageUpload(this HtmlHelper helper, string name) { return ImageUpload(helper, name, null); } public static IHtmlString ImageUpload(this HtmlHelper helper, string name, object htmlAttributes) { var tagBuilder = new TagBuilder("input"); tagBuilder.GenerateId(name); UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext); tagBuilder.Attributes["name"] = name; tagBuilder.Attributes["type"] = "file"; tagBuilder.MergeAttributes(new RouteValueDictionary(htmlAttributes)); return MvcHtmlString.Create(tagBuilder.ToString()); }
使用する
次に、メインプロジェクトを変更します。
プロジェクトには、Albumクラスというモデルがあります。 タイプバイト[]の新しい画像フィールドを追加します。 また、この新しいフィールドを標準バインディングから除外します。
[Bind(Exclude = "AlbumId, Image")] public class Album { ... public string AlbumArtUrl { get; set; } [ScaffoldColumn(false)] public byte[] Image { get; set; } ... }
また、データベースに新しいフィールドを追加することを忘れないでください。
次に、バインドを何らかの方法で宣言する必要があります。 これを行うには、対応するアクションに属性を追加するか、データバインディングをグローバルに追加します。
public ActionResult Create([ImageBind("Image")] Album album) { if (ModelState.IsValid) { storeDb.Albums.Add(album);
残念ながら、これはFormCollectionタイプを使用するEditメソッドには適していません。
引数で。 次に、次のように、コレクションに新しいバインディングを追加するだけです。
public ActionResult Edit(int id, FormCollection collection) { var album = storeDb.Albums.Find(id); if (Binders[typeof(Album)] == null) Binders.Add(typeof(Album), new ImageModelBinder("Image")); ...
または、Global.asaxファイルでグローバルに実行します。
ModelBinders.Binders.Add(typeof(Album), new ImageModelBinder("Image"));
画像をアップロードするには、ビューを変更し、フォームにフィールドを追加します。
<div class="editor-field"> @Html.ImageUpload("Image") </div>
新しいHTML属性enctype = "multipart / form-data"を追加してフォームヘルパーの呼び出しを変更し、バイナリデータの拍手を有効にします。
(Html.BeginForm("Edit", "StoreManager", FormMethod.Post, new { enctype = "multipart/form-data" }))
それはロードと保存についてです。
表示するには、新しいアクションを作成する必要があります。
[OutputCache(Duration = 0)] public ActionResult Image(int id) { var album = storeDb.Albums.Find(id); return new FileStreamResult(new MemoryStream(album.Image), "image/png"); }
この例では、PNG形式の画像の使用に限定しています。 また、適切な属性を指定して、キャッシュを処理する必要があります。
ビューを作成するには、単純なヘルパーが必要です。
public static IHtmlString Image(this HtmlHelper helper, string name, string id) { return Image(helper, name, id, null); } public static IHtmlString Image(this HtmlHelper helper, string name, string id, object htmlAttributes) { var tagBuilder = new TagBuilder("img"); UrlHelper urlHelper = new UrlHelper(helper.ViewContext.RequestContext); tagBuilder.Attributes["src"] = urlHelper.Action(name, null, new { id = id }); tagBuilder.Attributes["alt"] = string.Format("{0} of {1}", name, id); tagBuilder.MergeAttributes(new RouteValueDictionary(htmlAttributes)); return MvcHtmlString.Create(tagBuilder.ToString()); }
そして、フォームに追加します。
<div class="field"> @Html.Image("Image", @Model.AlbumId.ToString()) </div>
おわりに
この例では、MVCでデータバインディングをすばやく簡単に整理する方法を示したいと思いました。 ご覧のとおり、バインディングを使用した結果、ビュー、モデル、コントローラーの実装コードは非常にシンプルで簡潔になりました。 そして、最も重要なことは、一度バインディングを実装すると、どこでも使用できることです。
改善できるもの。
コントローラー名とアクションを記述しないために、BeginFormヘルパー(短縮バージョン)を追加します。 表示するアクションの実装はかなり原始的です。 良い方法では、画像タイプを保存し、それを正しく返し、バナーデータの検証を実装する必要があります。 そして、この記事で引用したヘルパーの代わりに、より正しい方法は、テンプレートの編集と表示を使用することです。 フィルターなどの強力なツールを使用することもできます。
ソース
mvcmusicstore.codeplex.com
www.highoncoding.com/Articles/689_Uploading_and_Displaying_Files_Using_ASP_NET_MVC_Framework.aspx
www.hanselman.com/blog/SplittingDateTimeUnitTestingASPNETMVCCustomModelBinders.aspx
odetocode.com/Blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx
odetocode.com/blogs/scott/archive/2009/05/05/iterating-on-an-asp-net-mvc-model-binder.aspx