如何将名为“ file []”的已发布数据绑定到MVC模型?

时间:2018-09-05 11:07:32

标签: asp.net-mvc file-upload model-binding redactor

我正在使用Redactor作为HTML编辑器,该编辑器具有component for uploading images and files

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的上传请求。因此,您无需在任何地方添加此enctype

2 个答案:

答案 0 :(得分:1)

您应该创建一个自定义模型活页夹,以将上传的文件绑定到一个属性。 首先创建一个具有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());

这不是一个通用的解决方案,但我想您明白了。

答案 1 :(得分:1)

在ASP.NET MVC项目中集成jQuery.filer时遇到了类似的问题。当jQuery.filer在输入名称属性的末尾添加“ []”(即从文件到文件[])时,我不得不手动更改名称属性的值,如下所示:

  const browser = await puppeteer.launch({
    headless: true // whether you want to run the test headless
  });

这是我通过AJAX在某些项目中使用的方法,并且没有任何问题。您可以尝试一下,让我知道它是否有效:

ViewModel:

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


视图:

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

希望这对您有帮助...