twitter-bootstrap 在引导模式中使用时,MVC 中的文件上传返回 null

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26563289/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-21 21:45:31  来源:igfitidea点击:

File upload in MVC when used in bootstrap modal returns null

asp.net-mvctwitter-bootstrapfile-uploadhttppostedfilebase

提问by Krishna Thota

I'm trying to upload images to my application but it always returns null. I'm unable to find the issue here. Can you help me out? Here's my code.

我正在尝试将图像上传到我的应用程序,但它始终返回 null。我在这里找不到问题。你能帮我吗?这是我的代码。

Model

模型



[Table("Slider")]
public partial class Slider : BaseModel
{
    [Required]
    [StringLength(200)]
    public string FileName { get; set; }

    [StringLength(200)]
    public string Title { get; set; }

    [StringLength(1000)]
    public string Description { get; set; }

    public int? Order { get; set; }
}


[NotMapped]
public class SliderImage : Slider
{
    public HttpPostedFileBase ImageFile { get; set; }
}

View

看法



@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="modal-body">
    <div class="form-horizontal">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.FileName, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.FileName, new { @class = "form-control", @readonly = "readonly" })
                @Html.ValidationMessageFor(model => model.FileName, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.ImageFile, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextBoxFor(m => m.ImageFile, new { @class = "form-control", type = "file" })
               //This is Same as below
               //<input class="form-control" id="ImageFile" name="ImageFile" type="file" value="">
            </div>
        </div>

Controller

控制器



    public ActionResult Edit(int id)
    {
        Slider slider = _db.Sliders.Find(id);
        if (slider == null)
        {
            return HttpNotFound();
        }
        Mapper.CreateMap<Slider, SliderImage>();
        SliderImage sliderImage = Mapper.Map<Slider, SliderImage>(slider);
        return PartialView("_Edit", sliderImage);
    }


    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult EditSlider([Bind(Include = "Id,FileName,Title,Description,Order,IsActive,Name,ImageFile")] SliderImage sliderImage)
    {
        if (ModelState.IsValid)
        {
            Mapper.CreateMap<SliderImage, Slider>();
            Slider slider = Mapper.Map<SliderImage, Slider>(sliderImage);
            _db.Entry(slider).State = EntityState.Modified;
            _db.SaveChanges();
            return Json(new { success = true });
        }
        return PartialView("_EditSlider");
    }

What am I doing wrong i this?

我做错了什么?



Found The Issue

发现问题

I'm binding the partial view inside the bootstrap modal popup. When I upload from the popup, the upload returning null. Instead if I open the partial View directly in browser, then the file is present in the model. So there is no problem with file upload. The problem is with modal popup or something.

我在 bootstrap 模态弹出窗口中绑定了局部视图。当我从弹出窗口上传时,上传返回空值。相反,如果我直接在浏览器中打开局部视图,则该文件存在于模型中。所以文件上传没有问题。问题出在模态弹出窗口或其他东西上。

When Using Bootstrap model When Using Bootstrap model

使用 Bootstrap 模型时 使用 Bootstrap 模型时

When using partial View Directy When using partial View Directy

使用部分视图直接时 使用部分视图直接时

Check the difference found when using fiddler between the Bootstrap Modal Submit and Using the partial View Directly in the following image respectively

分别查看下图中Bootstrap Modal Submit和Using the partial View Directly使用fiddler时发现的区别

Comparison of Fiddler requests

Fiddler 请求比较

When posting from the modal popup, the content type is changed to application/x-www-form-urlencodedwhere as when using the partial view directly it is multipart/form-data

从模态弹出窗口发布时,内容类型更改为application/x-www-form-urlencoded直接使用局部视图时的位置multipart/form-data



Found the root Issue.

找到了根本问题。

$('form', dialog).submit(function () {
                    var $form = $(this);
                    var enctype = $form.attr('id');
                    $.ajax({
                        url: this.action,
                        type: this.method,
                        data: $(this).serialize(),
                        success: function (result) {
                            if (result.success) {
                                $('#myModal').modal('hide');
                                //Refresh
                                location.reload();
                            } else {
                                $('#myModalContent').html(result);
                                bindForm();
                            }
                        }
                    });
                    return false;
                });

I'm using AJAX posting to submit the data from my form. When using $(this).serialize()the ajax success is being called but the file is not returning as the content type is different. How can I change this??

我正在使用 AJAX 发布来提交表单中的数据。当使用$(this).serialize()ajax 成功被调用但文件没有返回时,因为内容类型不同。我怎样才能改变这个??

回答by Márcio Douglas

I think I have been able to identify your problem, Ajax does not support file serialization, you should use the following method in the script:

我想我已经能够识别你的问题了,ajax不支持文件序列化,你应该在脚本中使用以下方法:

$('form', dialog).submit(function () {
        var formData = new FormData($(this)[0]);
        $.ajax({
            url: this.action,
            type: this.method,
            contentType: this.enctype,
            data: formData,
            success: function (result) {
                if (result.success) {
                    $('#myModal').modal('hide');
                    $('#replacetarget').load(result.url); //  Load data from the server and place the returned HTML into the matched element
                } else {
                    $('#myModalContent').html(result);
                    bindForm(dialog);
                }
            }
        });
        return false;
    });

回答by jennyfofenny

Ok, I think your current issue is related to the default settings for the jQuery.ajax method. By default, the content type for the jQuery.ajax() method is 'application/x-www-form-urlencoded; charset=UTF-8'. So, in a sample project, I modified your javascript function to specify the contentType as a paramter to the ajax method: contentType: this.enctype

好的,我认为您当前的问题与 jQuery.ajax 方法的默认设置有关。默认情况下,jQuery.ajax() 方法的内容类型是'application/x-www-form-urlencoded; charset=UTF-8'. 因此,在示例项目中,我修改了您的 javascript 函数以将 contentType 指定为 ajax 方法的参数:contentType: this.enctype

I think there also may be a couple additional issues. The next issue that I noticed is that on submission, I was connecting to another actions, so I updated this line in the view:

我认为可能还有一些额外的问题。我注意到的下一个问题是,在提交时,我正在连接到另一个操作,所以我在视图中更新了这一行:

@using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))

To this:

对此:

@using (Html.BeginForm("EditSlider", "<Your Controller Name>", FormMethod.Post, new { enctype = "multipart/form-data" }))

Lastly, when the ajax submitted, I was being redirected to the partial view. I believe this can be fixed by adding preventDefault to the ajax function:

最后,当 ajax 提交时,我被重定向到局部视图。我相信这可以通过在 ajax 函数中添加 preventDefault 来解决:

$('form', dialog).submit(function (event) {
    event.preventDefault();
    var $form = $(this);
    $.ajax({
        url: this.action,
        type: this.method,
        contentType: this.enctype,
        data: $(this).serialize(),
        success: function (result) {
            if (result.success) {
                $('#myModal').modal('hide');
                //Refresh
                location.reload();
            } else {
                $('#myModalContent').html(result);
                bindForm();
            }
        }
    });
});

This is how I was able to get this example working in a sample project; please post an update if you have additional issues.

这就是我如何让这个示例在示例项目中工作;如果您有其他问题,请发布更新。

回答by Andrei V

Usually, modal pop-ups are rendered at the end of the body. I'm pretty sure that bootstrapdoes the same thing. This, in turn, means that the content of the modal is moved to a new location and is taken out of your formelement. I would recommend a reordering: move the forminside the modal window:

通常,模态弹出窗口在body. 我很确定引导程序会做同样的事情。反过来,这意味着模态的内容被移动到新位置并从form元素中取出。我建议重新排序:移动form模态窗口内部:

<div class="modal-body">
    @using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        @Html.AntiForgeryToken()
        ...
    }
</div>

This will move the entire form (and not just the form elements) when the modal gets built.

这将在模态构建时移动整个表单(而不仅仅是表单元素)。

回答by Jorge F

Only the file uploaded return null? or the other textbox return null as well? As @Andrei comments, usually the modals is moved to a new location and the form is not present or your partialview could be moved to make the modal works.

只有上传的文件返回null?或者其他文本框也返回 null ?正如@Andrei 评论的那样,通常模态被移动到一个新位置并且表单不存在或者您的局部视图可以被移动以使模态工作。

With jqueryUI I had a similar problem. I couldn't find in your question if you are using ajax to submit your data, you could use .ajax() to send your form and see if the image was upload

使用 jqueryUI 我遇到了类似的问题。如果您使用 ajax 提交数据,我在您的问题中找不到,您可以使用 .ajax() 发送表单并查看图像是否已上传

$.ajax({
            url: "@Url.Action("Action", "Controller")",
            type: "POST",
            cache: false,
            data: $("#YourFormID").serialize(),
            success: function (result) {
               //your success data

            },
            error: function (jqXHR, textStatus, errorThrown) {
               //your error handler
            },
        });

         return false;

If you don't want to use $.ajax(), you could try to use .appendTo() with jquery, wrap everything what it is inside your form in a div with an ID, then after you have all your data try to sepecify that you want to appendTo("#YourFormID") on a button click, or as you like. This work for me when I was using modal, hope it helps you with something. Good luck

如果您不想使用 $.ajax(),您可以尝试将 .appendTo() 与 jquery 一起使用,将表单中的所有内容包装在一个带有 ID 的 div 中,然后在您拥有所有数据后尝试指定您要在单击按钮时或根据需要附加到(“#YourFormID”)。当我使用模态时,这对我有用,希望它可以帮助您。祝你好运

回答by Pablote

If I understand you make the form in a partial View, and this partial is used in a modal popup, it's right.

如果我理解你在局部视图中制作表单,并且这个局部用于模态弹出窗口,那就对了。

1) make a model for used in the form with all elements for the form, 2) declare the model in the first line in the partial view 3) pass as parameter the model to the post function. 4) you use a Partial view, well is possible use this view in differents pages, you need specify the control to treatement the form. in code:

1) 为表单中的所有元素创建一个模型,2) 在局部视图的第一行中声明模型 3) 将模型作为参数传递给 post 函数。4) 您使用的是 Partial 视图,可以在不同的页面中使用此视图,您需要指定控件来处理表单。在代码中:

MODEL

模型

public partial class SliderModel
{
    [Required]
    [StringLength(200)]
    public string FileName { get; set; }

    [StringLength(200)]
    public string Title { get; set; }

    [StringLength(1000)]
    public string Description { get; set; }

    public int? Order { get; set; }

    [NotMapped]
    public HttpPostedFileBase ImageFile { get; set; }
}

VIEW

看法

@model YOURNAMESPACE.Models.SliderModel
<form method="post" class="form-horizontal" role="form" id="sendMail" 
    enctype="multipart/form-data"  action="/CONTROLLERNAME/EditSlider">

@Html.AntiForgeryToken()
<div class="modal-body">
    <div class="form-horizontal">
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.Id)

        <div class="form-group">
            @Html.LabelFor(model => model.FileName, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextBoxFor(model => model.FileName, new { @class = "form-control", @readonly = "readonly" })
                @Html.ValidationMessageFor(model => model.FileName, "", new { @class = "text-danger" })
            </div>
        </div>
        <div class="form-group">
            @Html.LabelFor(model => model.ImageFile, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextBoxFor(m => m.ImageFile, new { @class = "form-control", type = "file" })
               //This is Same as below
               //<input class="form-control" id="ImageFile" name="ImageFile" type="file" value="">
            </div>
        </div>
<div class="form-group">
        <div class="col-md-offset-1">
            <button type="submit" class="btn btn-success"><b><i class="fa fa-envelope"></i> Envoyer</b> </button>
        </div>
    </div>
</form>

CONTROLLER

控制器

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult EditSlider(SliderModel obj)
{
    if (ModelState.IsValid)
    {
        your options
    }
    return PartialView("_EditSlider");
}

回答by Ganesh Todkar

Try with following way this worked for me :

尝试以下方式这对我有用:

VIEW :

看法 :

@using (Html.BeginForm("ComplaintAndSuggestion", "RegisterComplaints", FormMethod.Post, new { enctype = "multipart/form-data", id = "ajaxUploadForm" }))
{
:
:
:

                    <div class="row mb10">
                        <div class="col-sm-3 col-md-3">
                            <label for="file1">Upload Image 1</label>
                            <input type="file" name="images" id="file1" accept="image/*" />
                        </div>
                        <div class="col-sm-3 col-md-3">
                            <label for="file2">Upload Image 2</label>
                            <input type="file" name="images" id="file2" accept="image/*" />
                        </div>
                        <div class="col-sm-3 col-md-3">
                            <label for="file3">Upload Image 3</label>
                            <input type="file" name="images" id="file3" accept="image/*" />
                        </div>
                        <div class="col-sm-3 col-md-3">
                            <label for="file4">Upload Image 4</label>
                            <input type="file" name="images" id="file4" accept="image/*" />
                        </div>
                    </div>

   <input type="submit" value="Create" />

}

Controller :

控制器 :

     [HttpPost]
        public ActionResult ComplaintAndSuggestion(Register register, IEnumerable<HttpPostedFileBase> images, IEnumerable<HttpPostedFileBase> videos)
        {


 foreach (var file in images)
                {

                    if (file != null)
                    {
                        string filenameWithDateTime = AppendTimeStamp(file.FileName);
                        file.SaveAs(Server.MapPath(Path.Combine("~/Images/", filenameWithDateTime)));
                        fileUploadModel.FilePath = (Server.MapPath(Path.Combine("~/Images/", filenameWithDateTime)));
                        fileUploadModel.FileName = filenameWithDateTime;
                        fileUploadModel.FileType = "Image";
                        fileUploadModel.RegisterId = register.RegisterId;
                        mediaRepository.Add(fileUploadModel);
                        mediaRepository.Save();
                    }

                }

}

Let me know.

让我知道。