Как привязать опубликованные данные с именем «file []» к модели MVC? - PullRequest
0 голосов
/ 05 сентября 2018

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

Redactor заботится о бите на стороне клиента, и мне нужно предоставить функцию загрузки на стороне сервера.

У меня нет проблем с загрузкой, если я использую Request.Files в контроллере.

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

Мой вопрос:

Можно ли привязать опубликованный "file[]" к модели MVC? Это неверное имя свойства, и использование file само по себе не работает.


Этот файл ввода выглядит следующим образом. Я могу указать имя, отличное от file, но Redactor добавляет [] в конец, независимо от имени.

<input type="file" name="file" multiple="multiple" style="display: none;">

Я пытаюсь привязать свойство как это:

public HttpPostedFileBase[] File { get; set; }

Когда я смотрю, как происходит загрузка, я вижу это в запросе (я предполагаю, что редактор может добавлять квадратные скобки за кулисы):

Content-Disposition: form-data; name="file[]"; filename="my-image.jpg"

Также актуально:

Redactor всегда отправляет запрос на загрузку с типом контента как multipart / form-data. Так что вам не нужно никуда добавлять этот энтип

Ответы [ 2 ]

0 голосов
/ 10 сентября 2018

Я столкнулся с подобной проблемой при интеграции jQuery.filer в проект ASP.NET MVC. Поскольку jQuery.filer добавляет «[]» в конец атрибута имени ввода (т. Е. Из файлов в файлы []), мне пришлось вручную изменить значение атрибута имени, как показано ниже:

$('#FileUpload').attr('name', 'FileUpload');

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

ViewModel:

[Display(Name = "Attachments")]
[DataType(DataType.Upload)]
public IEnumerable<HttpPostedFileBase> FileUpload { get; set; }


Вид:

@model ViewModel

@using (Html.BeginForm("Insert", "Controller", FormMethod.Post, 
    new { id = "frmCreate", enctype = "multipart/form-data" })) 
{   
    @Html.TextBoxFor(m => m.FileUpload, new { type = "file", multiple = "multiple" })
    <button id="btnSubmit" onclick="insert(event)" type="button">Save</button>
}    

<script>     
function insert(event) {     
    event.preventDefault();

    //As jQuery.filer adds "[]" to the end of name attribute of input (i.e. from files to files[])
    //we have to change the value of name attribute manually
    $('#FileUpload').attr('name', 'FileUpload');        
    var formdata = new FormData($('#frmCreate').get(0)); 

    $.ajax({
        type: "POST",
        url: '@Url.Action("Insert", "Cotroller")',
        cache: false,
        dataType: "json",
        data: formdata,

        /* If you are uploading files, then processData and contentType must be set 
        to falsein order for FormData to work (otherwise comment out both of them) */
        processData: false, 
        contentType: false, 

        success: function (response, textStatus, XMLHttpRequest) {
            //...
        }
    });
};

$(document).ready(function () {         
    $('#FileUpload').filer({        
        //code omitted for brevity
    });  
});  
</script>


Контроллер:

public JsonResult Insert([Bind(Exclude = null)] ViewModel model)
{
    if (ModelState.IsValid)
    {   
        List<FileAttachment> fa = new List<FileAttachment>();
        if (model.FileUpload != null)
        {
            FileAttachment fileAttachment = new FileAttachment //entity model
            {
                Created = DateTime.Now,
                FileMimeType = upload.ContentType,
                FileData = new byte[upload.ContentLength],
                FileName = upload.FileName,
                AuthorId = 1
            };
            upload.InputStream.Read(fileAttachment.FileData, 0, upload.ContentLength);
            fa.Add(fileAttachment);
        }

        //code omitted for brevity
        repository.SaveExperimentWithAttachment(model, fa);
        return Json(new { success = true, message = "Record has been created." });
    }
    // If we got this far, something failed, redisplay form
    return Json(new { success = false, message = "Please check the form and try again." });
}

Надеюсь, это поможет ...

0 голосов
/ 10 сентября 2018

Вы должны создать пользовательский механизм связывания моделей, чтобы привязать загруженные файлы к одному свойству. Сначала создайте модель со свойством HttpPostedFileBase[]

public class RactorModel
{
    public HttpPostedFileBase[] Files { get; set; }
}

затем реализовать DefaultModelBinder и переопределить BindProperty

public class RactorModelBinder : DefaultModelBinder
{
    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
    {
        int len = controllerContext.HttpContext.Request.Files.AllKeys.Length;

        if (len > 0)
        {
            if (propertyDescriptor.PropertyType == typeof(HttpPostedFileBase[]))
            {
                string formName = string.Format("{0}[]", propertyDescriptor.Name);
                HttpPostedFileBase[] files = new HttpPostedFileBase[len];
                for (int i = 0; i < len; i++)
                {
                    files[i] = controllerContext.HttpContext.Request.Files[i];
                }

                propertyDescriptor.SetValue(bindingContext.Model, files);
                return;
            }
        }

        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
    }
}

Также вы должны добавить провайдера связывания в свой проект, а затем зарегистрировать его в global.asax

public class RactorModenBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(Type modelType)
    {
        if (modelType == typeof(RactorModel))
        {
            return new RactorModelBinder();
        }

        return null;
    }
}
...
ModelBinderProviders.BinderProviders.Insert(0, new RactorModenBinderProvider());

это не общее решение, но я думаю, вы поняли.

...