【发布时间】: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);
}
}
出了什么问题,因为文件从未被保存(其他一切正常)。
【问题讨论】:
-
你需要使用
FormData参考这个帖子How to upload files using ajax to asp.net mvc controller action -
enctype与使用ajax上传文件完全没有关系
标签: c# asp.net asp.net-mvc