Подтвердить что ты не робот

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?

4b9b3361

Ответ 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)
{
    ...
}

Это помогает читать книгу каждый раз через некоторое время, вместо того чтобы полагаться исключительно на блоги и веб-форумы.