HttpPostedFileBase从ASP.NET MVC App中的AJAX帖子返回null

时间:2018-08-15 20:49:48

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

我对此进行了一些研究,它总是说同样的话,请确保在尝试将带有文件的ajax发布到mvc控制器时,已将“ 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);
            }
        }

出了什么问题,因为文件从未被保存过(其他所有方法都起作用)。

1 个答案:

答案 0 :(得分:0)

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

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

Sending multipart/formdata with jQuery.ajax

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