通过使用一个将HttpPostedFileBase
属性绑定到视图的视图模型来解决,这样表单只需要一个post方法来上传图像,然后将实体添加到数据库。
下面是表单标签:
@using (Html.BeginForm("Create", "Lessons", FormMethod.Post, new {enctype = "multipart/form-data" }))
和绑定到视图模型属性的视图控件(如果名称匹配,默认情况下会发生),在我的情况下,属性是HttpPostedFileBase
文件:
<input type="file" name="file" />
这比我在下面的路径要容易得多,试图为单个视图提供两个不同的后动作(这应该是可能的,从我读到的一切,但我认为我的问题是试图在一个表单中有一个表单):
我的controller for Lesson有两个post方法可以调用:
第一个是创建一个新的Lesson:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Create(Lesson lesson)//, WebImage Photo)
{
if (ModelState.IsValid && Request.Form["Create"]!=null)
//Request.Form check because the image file function is calling back to this handler
//Once that is sorted out the check can be removed and simply use ModelState.IsValid
{
db.Lessons.Add(lesson);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewBag.DivID = new SelectList(db.Divisions, "ID", "DivName", lesson.DivID);
ViewBag.ProjectID = new SelectList(db.Projectinformations, "ID", "Code", lesson.ProjectID);
ViewBag.PeopleID = new SelectList(db.Peoples, "ID", "Firstname", lesson.PeopleID);
return View(lesson);
}
在页面上,这是带有提交按钮的表单(简称),该按钮调用控制器。create()操作:
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
//. . . for each Lesson property there is a form group with @Html Label
//@Html.EditorFor, etc. and then at the bottom is this:
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" name="Create" class="btn btn-default" />
</div>
</div>
图像路径字段是主表单的一部分,我为它的文本框等留下了生成的代码。这是表单的一部分,我试图插入一个图像上传调用不同的控制器动作:
<div class="form-group">
<div class="col-md-10">
<form action="UploadImage" name="ImageFileForm" id="imageForm" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="OK" name="OK" />
</form>
</div>
@Html.LabelFor(model => model.Image, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Image, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Image, "", new { @class = "text-danger" })
</div>
</div>
这是UploadImage
的控制器动作[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UploadImage(HttpPostedFileBase file)
{
string imagePath ="";
if (file != null)
{
var newFileName = Path.GetFileName(file.FileName);
imagePath = @"LessonsLearnedImages" + newFileName;
file.SaveAs(@"~" + imagePath);
}
ViewBag.DivID = new SelectList(db.Divisions, "ID", "DivName", lesson.DivID);
ViewBag.ProjectID = new SelectList(db.Projectinformations, "ID", "Code", lesson.ProjectID);
ViewBag.MOAPeopleID = new SelectList(db.MOApeoples, "ID", "Firstname", lesson.MOAPeopleID);
ViewBag.Image = imagePath;
return View();
}
当我按下ImageUpload按钮,然而,控制器创建(表单默认)函数被调用。我可能会使用控制器中的Create操作来处理Request中的所有事情。表单检查,但这已经失败了,当我添加一个HttpPostedFileBase参数给它。
对于图片上传,有两件事需要保存。第一部分是保存实际图像,例如。保存到计算机上的文件夹中。第二部分是保存有关图像的信息。将其完整路径保存在数据库中。完成这两部分是必要的,这样您就可以稍后检索图像。
捕获图像(或上传文件)的一种方法是使用HttpPostedFileBase
作为参数类型:
[HttpPost]
public async Task<ActionResult> Upload(HttpPostedFileBase myFile)
{
// myFile contains several properties which you need to be able to save the file
}
myFile
参数有几个需要保存的属性。例如,您上传图像的路径和您可以提取为byte[]
的实际图像内容。
网页上相应的形式,删减到必要的部分,将是:
<form action="Upload" method="post" enctype="multipart/form-data">
<input type="file" name="myFile" />
<input type="submit" value="Click me to upload" />
</form>
您需要确保以下行,以便调用正确的控制器动作:
- 表单的方法应该匹配控制器方法的动词(表单中的
post
对应于控制器中的HttpPost
) - 表单的动作应该匹配控制器方法的名称(在本例中为
Upload
) - 输入的名称应该与控制器方法的参数(本例中为
myFile
)的名称相匹配
您还需要确保enctype是multipart/form-data
,以便myFile
参数实际具有值。如果不是,可以执行正确的控制器方法,但参数可能为空。
在所有这些之后,您应该有一个合适的myFile
参数,您可以使用其属性来保存。例如,在保存图像之后,您可以将其完整路径存储在Lessons
表的ImagePath
列中。
正如您所提到的,一旦控制器方法完成执行,图像(以及与此相关的任何其他内容)就会丢失。但这没关系,因为我们已经在持久存储中保存了图像和图像路径。要在以后检索图像,您可以查看相关的课程。例如,假设您有一个Model
对象,对应于您从数据库中获得的课程,则显示图像可能如下所示:
<img src="@Model.ImagePath" />
编辑
似乎你想在创建页面上保存多个字段,而图像文件只是其中一个字段。在这种情况下,控制器上只需要一个方法,页面上只需要一个表单元素。
要捕获文件,将HttpPostedFileBase
添加为课程视图模型中的属性,例如:
public class Lesson
{
public HttpPostedFileBase File { get; set; }
}