【问题标题】:HttpPostedFileBase returning null from AJAX post in ASP.NET MVC App [duplicate]HttpPostedFileBase 从 ASP.NET MVC 应用程序中的 AJAX 帖子返回 null [重复]
【发布时间】:2018-08-15 20:49:48
【问题描述】:

我对此做了一些研究,它总是说同样的话,当你尝试用一个文件向 mvc 控制器做一个 ajax 发布时,请确保你有 "multipart/form-data" 的 enctype。据我所知,我已经做到了,但当我运行调试器时,HttpPostedFileBase 始终返回 null。我没有看到我错过了什么可能非常明显的地方。

这是剃刀视图表单。

@using (Html.BeginForm("Edit", "Story", FormMethod.Post, new { encType = "multipart/form-data" }))
            {
                @Html.AntiForgeryToken()
                @Html.ValidationSummary(true, "", new { @class = "text-danger" })
                @Html.HiddenFor(x => x.StoryId)

                <div class="form-group">
                    <div class="row">
                        <div class="col-sm-4">
                            <div class="card">
                                <div class="card-body">
                                    <p class="card-text">Add/Edit cover art to your story</p>
                                    <img class="img-thumbnail" src="~/Imgs/@Model.CoverArt" />
                                    <input type="file" id="file" name="file" class="form-control" />
                                </div>
                            </div>
                        </div>
                        <div class="col-sm-8"></div>
                    </div>
                </div>

                <div class="form-row">
                    <div class="col-6">
                        @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label text-muted" })
                        @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
                    </div>
                    <div class="col-3">
                        @Html.LabelFor(x => x.Genre, htmlAttributes: new { @class = "control-label text-muted" })
                        @Html.DropDownListFor(x => x.Genre, new SelectList(Model.Genres, "Id", "Name"), new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.Genre, "", new { @class = "text-danger" })
                    </div>
                    <div class="col-3">
                        @Html.Label("Visibility", htmlAttributes: new { @class = "control-label text-muted" })
                        <i class="fa fa-question-circle-o" data-toggle="popover" title="What does visibility mean?" data-placement="right" data-content="Visibility determines whether other users can see this story or not. Public means any other user can read, vote, and review the story. You can change this to private, which will hide the story from other users. You, as the author, will be able to see all of your stories - both public and prviate - under your account."></i>
                        @Html.DropDownListFor(x => x.Visibility, new SelectList(Model.Visibilities, "Id", "Name"), new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.Visibility, "", new { @class = "text-danger" })
                    </div>
                </div>
                <div class="form-row mt-3">
                    <div class="col-6">
                        @Html.Label("Story Type", htmlAttributes: new { @class = "control-label text-muted" })
                        @Html.DropDownListFor(x => x.StoryType, new SelectList(Model.StoryTypes, "Id", "Name"), new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.StoryType, "", new { @class = "text-danger" })
                    </div>
                    <div class="col-6">
                        @Html.Label("Target Age Range", htmlAttributes: new { @class = "control-label text-muted" })
                        @Html.DropDownListFor(x => x.StoryAgeRange, new SelectList(Model.StoryAgeRanges, "Id", "Name"), new { @class = "form-control" })
                        @Html.ValidationMessageFor(model => model.StoryAgeRange, "", new { @class = "text-danger" })
                    </div>
                </div>

                <div class="form-row mt-5">
                    <div class="col-12">
                        @Html.Label("Write below", htmlAttributes: new { @class = "control-label text-muted" })
                        @Html.TextAreaFor(model => model.Content, new { htmlAttributes = new { @class = "form-control" } })
                        @Html.ValidationMessageFor(model => model.Content, "", new { @class = "text-danger" })
                    </div>
                </div>

                <div class="form-row mt-3">
                    <div class="btn-group">
                        @Html.ActionLink("Cancel", "Index", "Story", null, new { @class = "btn btn-red" })
                        <input type="button" id="editStoryBtn" value="Edit story" class="btn btn-blue" />
                        <a class="btn btn-link ml-auto" href="@Url.Action("PublishingRules", "Legal")">Publishing Guidelines</a>
                    </div>
                </div>

            }

这里是 ajax 调用的 javascript(以及我用来获取文件名的函数):

//get the filename of the uploaded file
                var fullPath = document.getElementById('file').value;
                if (fullPath) {
                    var startIndex = (fullPath.indexOf('\\') >= 0 ? fullPath.lastIndexOf('\\') : fullPath.lastIndexOf('/'));
                    var filename = fullPath.substring(startIndex);
                    if (filename.indexOf('\\') === 0 || filename.indexOf('/') === 0) {
                        filename = filename.substring(1);
                    }
                }

                //create the new story object
                var editedStory = {
                    __RequestVerificationToken: token,
                    StoryId: storyId,
                    CoverArt: filename,
                    Title: $("input[name='Title']").val(),
                    Content: CKEDITOR.instances.Content.getData(),
                    Genre: $('#Genre').val(),
                    Visibility: $('#Visibility').val(),
                    StoryType: $('#StoryType').val(),
                    StoryAgeRange: $('#StoryAgeRange').val(),
                    WordCount: finalWordCount
                }

                //post the edited story to the controller
                $.ajax({
                    url: "/story/edit/" + storyId,
                    type: 'POST',
                    data: editedStory,
                    success: function (data) {
                        window.location.href = data.Url;
                    },
                    error: function (error) {
                        console.log("error is " + error);
                    }
                });

这里是控制器。

//POST story/edit/5
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
[ValidateInput(false)]
public ActionResult Edit (EditStoryViewModel viewModel, HttpPostedFileBase file)
{
            //confirm model state is valid
            if (ModelState.IsValid)
            {
                //find the correct story by the id and include the reference tables
                var StoryToEdit = dbContext.Stories.SingleOrDefault(x => x.Id == viewModel.StoryId);

                //verify file upload
                if (file != null)
                {
                    StoryToEdit.CoverArt = StoryToEdit.Id + Path.GetExtension(file.FileName);
                    file.SaveAs(Server.MapPath("/Imgs/") + StoryToEdit.CoverArt);
                }

                StoryToEdit.Title = viewModel.Title;
                StoryToEdit.Content = viewModel.Content;
                StoryToEdit.GenreId = viewModel.Genre;
                StoryToEdit.StoryAgeRangeId = viewModel.StoryAgeRange;
                StoryToEdit.StoryTypeId = viewModel.StoryType;
                StoryToEdit.VisibilityId = viewModel.Visibility;
                StoryToEdit.WordCount = viewModel.WordCount;
                StoryToEdit.UpdatedAt = DateTime.Now;

                dbContext.Entry(StoryToEdit).State = EntityState.Modified;
                dbContext.SaveChanges();

                var redirectUrl = new UrlHelper(Request.RequestContext).Action("Details", "Story", new { id = StoryToEdit.Id });

                return Json(new { Url = redirectUrl });
            }
            else
            {
                return View(viewModel);
            }
        }

出了什么问题,因为文件从未被保存(其他一切正常)。

【问题讨论】:

标签: c# asp.net asp.net-mvc


【解决方案1】:

当您想使用XMLHttpRequest 或使用它的包装器(如jQuery)发布多部分表单数据时。您需要创建一个FormData 对象并添加要发送到服务器的文件和表单数据。只有这样数据才会相应地发送到服务器。

已经有一些关于如何使用FormData对象的答案

Sending multipart/formdata with jQuery.ajax

https://www.mkyong.com/jquery/jquery-ajax-submit-a-multipart-form/

【讨论】:

    猜你喜欢
    • 2012-01-23
    • 2016-04-08
    • 1970-01-01
    • 2019-09-17
    • 2014-06-29
    • 2019-02-07
    • 2020-03-04
    • 1970-01-01
    • 2017-10-22
    相关资源
    最近更新 更多