Asp.net Mvc: Привязка Данных Модели, Содержащих Изображения

Привязка данных — довольно удобный инструмент ASP.NET MVC. Это удобно прежде всего тем, что позволяет скрыть реализацию преобразования данных между данными модели и данными HTTP-запроса.

В своих проектах я часто сталкиваюсь с необходимостью сохранять различные данные, такие как blob и image. В этой статье я хотел бы показать, как можно легко организовать и использовать привязку данных из модели, содержащей различные изображения.

Например, я взял обучающий проект Музыкальный магазин MVC и решил это исправить - добавить возможность менять обложку музыкального альбома.

При написании этой статьи я использовал версию 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, сначала вызвали базовую реализацию для привязки всех данных, а затем реализовали преобразование и запись в поле данных изображения из поля формы HTTP-запроса типа HttpPostedFileBase. Также было бы неплохо создать свой собственный атрибут:

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. Добавим новое поле изображения типа byte[].

Мы также исключим это новое поле из стандартной привязки.



[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);

К сожалению, это не будет работать для метода Edit, где используется тип FormCollection. в аргументах.

Затем вы можете просто добавить в коллекцию новую привязку, например:

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 — сокращенную версию, чтобы не писать названия контроллера и действий.

Реализация Action для отображения довольно примитивна.

По-хорошему нужно сохранить тип изображения и правильно его вернуть и реализовать валидацию банарных данных.

И вместо помощников, которые я привел в этой статье, более правильный метод — использовать шаблоны редактирования и просмотра.

Вы также можете использовать такой мощный инструмент, как фильтры.



Источники

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 Теги: #asp.net mvc 3 #C++ #binding #image #ASP #ASP
Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.