ASP.NET MVC опубликовала привязку файловой модели, когда параметр Model
Есть ли способ опубликовать файлы (<input type="file" />
), чтобы принять участие в привязке модели в ASP.NET MVC без ручного поиска контекста запроса в настраиваемом связующем модуле и без создания отдельного метода действий который принимает только размещенный файл в качестве входных данных?
Я бы подумал, что это сработает:
class MyModel {
public HttpPostedFileBase MyFile { get; set; }
public int? OtherProperty { get; set; }
}
<form enctype="multipart/form-data">
<input type="file" name="MyFile" />
<input type="text" name="OtherProperty" />
</form>
public ActionResult Create(MyModel myModel) { ... }
Но, учитывая приведенный выше сценарий, MyFile
не является частью значений поставщика значений в контексте привязки. (OtherProperty
, конечно.) Но это работает, если я это делаю это:
public ActionResult Create(HttpPostedFileBase postedFile, ...) { ... }
Итак, почему привязка не возникает, когда параметр является моделью, и как я могу заставить его работать? У меня нет проблем с использованием настраиваемого связующего устройства, но как я могу сделать это в настраиваемом подменю модели, не глядя на Request.Files["MyFile"]
?
Для обеспечения согласованности, ясности и тестируемости я бы хотел, чтобы мой код обеспечивал автоматическую привязку всех свойств модели, в том числе связанных с размещенными файлами, без ручного контроля контекста запроса. В настоящее время я тестирую привязку модели, используя подход, о котором писал Scott Hanselman.
Или я об этом неправильно? Как бы вы решили это? Или это невозможно по дизайну из-за истории разделения между Request.Form и Request.Files?
Ответы
Ответ 1
Оказывается, причина в том, что ValueProviderDictionary
работает только в Request.Form
, RouteData
и Request.QueryString
, чтобы заполнить словарь поставщика значений в контексте привязки модели. Таким образом, нет возможности для настраиваемого связующего устройства разрешить размещенные файлы участвовать в привязке к модели без непосредственного осмотра коллекции файлов в контексте запроса. Это самый близкий путь, который я нашел, чтобы выполнить одно и то же:
public ActionResult Create(MyModel myModel, HttpPostedFileBase myModelFile) { }
Пока myModelFile
на самом деле является именем поля формы ввода file
, нет необходимости в каких-либо настраиваемых материалах.
Ответ 2
Другой способ - добавить скрытое поле с тем же именем, что и вход:
<input type="hidden" name="MyFile" id="MyFileSubmitPlaceHolder" />
DefaultModelBinder затем увидит поле и создаст правильное связующее.
Ответ 3
Вы просмотрели этот пост, с которым он ссылается тот вы связались с (через еще один...)?
Если нет, это выглядит довольно просто. Это модель, которую он использует:
public class HttpPostedFileBaseModelBinder : IModelBinder {
public ModelBinderResult BindModel(ModelBindingContext bindingContext) {
HttpPostedFileBase theFile =
bindingContext.HttpContext.Request.Files[bindingContext.ModelName];
return new ModelBinderResult(theFile);
}
}
Он регистрирует его в Global.asax.cs
следующим образом:
ModelBinders.Binders[typeof(HttpPostedFileBase)] =
new HttpPostedFileBaseModelBinder();
и сообщения с формой, которая выглядит так:
<form action="/File/UploadAFile" enctype="multipart/form-data" method="post">
Choose file: <input type="file" name="theFile" />
<input type="submit" />
</form>
Весь код скопирован прямо из сообщения в блоге...
Ответ 4
Вам не нужно регистрировать настраиваемое связующее, HttpPostedFileBase
зарегистрировано по умолчанию в рамках:
public ActionResult Create(HttpPostedFileBase myFile)
{
...
}
Это помогает читать книгу каждый раз через некоторое время, вместо того чтобы полагаться исключительно на блоги и веб-форумы.