我正在尝试构建一个简单的CMS,允许作者上传文件(特别是图片,但文件类型现在并不重要)。
上传文件工作正常。但是,我想提供列出并随后删除文件的功能(可能是以后的多个文件,但现在一次只能保存一个文件)。
我环顾四周。我看到很多使用EF将文件的位置存储在数据库中的例子,因为它们具有权限和角色等等。虽然这是我将来可能需要解决的问题,但它不是一个复杂的层,我愿意添加正确的现在
我只想按一下删除链接(就像删除数据库中的记录一样)。触发调用删除确认视图的操作。然后在该视图上,删除按钮以实际删除文件并将用户返回到列表。以下是我目前的代码:
这将是列出文件的视图:
@model IEnumerable<FileInfo>
@{
ViewBag.Title = "File List";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Upload", "Upload")
</p>
<table class="table">
<tr>
<th>File Name</th>
<th>Actions</th>
</tr>
@foreach (FileInfo file in Model)
{
<tr>
<td>@file.Name</td>
<td>@Html.ActionLink("Delete", "Delete", new { fileName = @file.Name })</td>
</tr>
}
</table>
我不会为这个视图显示控制器,因为它相对简单,而不是我遇到问题的地方(我认为)。我只是展示了这个,所以你可以看到删除链接并告诉我是否有任何错误。
以下是删除确认视图:
@model FileInfo
@{
ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.FullName)
</dt>
<dd>
@Html.DisplayFor(model => model.FullName)
</dd>
</dl>
@using (Html.BeginForm("Delete", "FileManagement", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
@Html.AntiForgeryToken()
<div class="form-actions no-color">
@Html.ActionLink("Back to list of views", "Index", null, new { @class = "btn btn-success" })
|
@*@Html.ActionLink("Delete", "Delete", null, new { @class = "btn btn-danger" })*@
<input type="submit" value="Delete file" formaction="Delete" formmethod="delete" class="btn btn-danger" />
</div>
}
以下是两个删除操作(GET和POST / DELETE)
// GET: FileManagement/Delete/filename
public ActionResult Delete()
{
return View();
}
// POST: FileManagement/Delete/filename
[HttpDelete]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
{
var path = Path.Combine(Server.MapPath("~/UserFiles"), fileName);
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
else
return HttpNotFound();
return RedirectToAction("Index");
}
我没有查看模型,因为我还没有连接到数据库。这些文件只是上传到文件夹〜/ UserFiles / someFileName.ext,并且通过正常方式将此文件附加到server.mappath来获取完整路径。
我遇到的问题是将文件名放入删除确认视图,并进入删除按钮,将其传递给删除操作以完成工作。
感谢您的帮助。
答案 0 :(得分:1)
在主视图中(我假设Index.cshtml
),您正确生成fileName
的查询字符串值,但GET方法没有接受它的参数。它需要
// GET: FileManagement/Delete/filename
public ActionResult Delete(string fileName)
并且在该方法中,您需要基于FileInfo
初始化新的fileName
类,并将该模型传递给视图。
下一个问题是您的确认页面中的表单没有将文件名传递回POST方法,但这引发了另一个问题,即您不能使用具有相同签名的GET和POST方法,因此您需要更改其中一个方法的名称,例如
[HttpGet]
public ActionResult ConfirmDelete(string fileName)
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
并在确认删除页面中,将表单更改为
@using (Html.BeginForm("Delete", "FileManagement", new { fileName = Model.Name })) // enctype not required
{
@Html.AntiForgeryToken()
<input type="submit" value="Delete file" class="btn btn-danger" />
}
但是,您可以通过在Index
视图中生成表单并显示确认对话框(不再需要GET方法)来大大提高性能。
@foreach (FileInfo file in Model)
{
....
@using(Html.BeginForm("Delete", "FileManagement", new { fileName = file.Name }))
{
@Html.AntiForgeryToken()
<input type="submit" value="delete" />
}
}
并添加脚本以显示对话框
$('form').submit(function() {
return conform("Are your sure .... ");
});
将显示浏览器的javascript确认对话框。您可以通过在确认对话框中使用jquery插件来进一步增强UI(或实现您自己的,如this article中所述)
您还应该考虑使用ajax来提交表单(并在成功回调中,删除按钮及其关联的表行)。典型的实现可能看起来像
@foreach (FileInfo file in Model)
{
<tr>
<td>@file.Name</td>
<td>
<form class="deleteform">
@Html.AntiForgeryToken()
<input type="hidden" name="fileName" value="@file.Name" />
<input type="submit" value="delete" />
</form>
</td>
</tr>
}
var url = '@Url.Action("Delete", "FileManagement")';
$('.deleteform').submit(function() {
var formData = $(this).serialize();
var row = $(this).closest('tr');
$.post(url, formData, function(response) {
if (response) {
row.remove();
} else {
// Oops - display message?
}
}).fail(function (response) {
// Oops
});
return false; // cancel the default submit
});
和控制器方法
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(string fileName)
{
.... // delete the file
return Json(true); // indicate success
// or return Json(null); to indicate failure
}