将文件名传递给视图
Passing a filename to a view
我正在尝试构建一个简单的 CMS,它允许作者上传文件(特别是图像,但文件类型目前并不重要)。
文件上传正常。但是我想提供列出并随后删除文件的功能(以后可能会删除多个文件,但现在一次一个文件就可以了)。
我在网上看了一圈。我看到很多使用 EF 将文件位置存储在数据库中的示例,因为它们具有权限和角色等。虽然这是我将来可能需要解决的问题,但它不是我愿意添加的复杂层现在。
我只想简单地按下删除键 link(就像您要删除数据库中的记录一样)。触发调用删除确认视图的操作。然后在那个视图上,一个删除按钮实际删除文件和 return 用户到列表。以下是我目前的代码:
这将是列出文件的视图:
@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>
我不会显示此视图的控制器,因为它相对简单而且不是我遇到问题的地方(我认为)。我只展示了这个所以你可以看到删除 link 并告诉我是否有任何问题。
下面是删除确认视图:
@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 获得的。
我遇到的问题是将文件名输入到删除确认视图中,并将文件名输入到删除按钮中,后者会将其传递给删除操作以完成这项工作。
感谢您的帮助。
在您的主视图中(我假设 Index.cshtml
),您正确地为 fileName
生成了一个查询字符串值,但是 GET 方法没有接受它的参数。需要
// GET: FileManagement/Delete/filename
public ActionResult Delete(string fileName)
并且在该方法中,您需要根据 fileName
初始化一个新的 FileInfo
class 并将该模型传递给视图。
下一个问题是您在确认页面中的表单没有将文件名传递回 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 提交表单(并在成功回调中删除按钮及其关联的 table 行)。一个典型的实现可能看起来像
@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
}
我正在尝试构建一个简单的 CMS,它允许作者上传文件(特别是图像,但文件类型目前并不重要)。
文件上传正常。但是我想提供列出并随后删除文件的功能(以后可能会删除多个文件,但现在一次一个文件就可以了)。
我在网上看了一圈。我看到很多使用 EF 将文件位置存储在数据库中的示例,因为它们具有权限和角色等。虽然这是我将来可能需要解决的问题,但它不是我愿意添加的复杂层现在。
我只想简单地按下删除键 link(就像您要删除数据库中的记录一样)。触发调用删除确认视图的操作。然后在那个视图上,一个删除按钮实际删除文件和 return 用户到列表。以下是我目前的代码:
这将是列出文件的视图:
@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>
我不会显示此视图的控制器,因为它相对简单而且不是我遇到问题的地方(我认为)。我只展示了这个所以你可以看到删除 link 并告诉我是否有任何问题。
下面是删除确认视图:
@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 获得的。
我遇到的问题是将文件名输入到删除确认视图中,并将文件名输入到删除按钮中,后者会将其传递给删除操作以完成这项工作。
感谢您的帮助。
在您的主视图中(我假设 Index.cshtml
),您正确地为 fileName
生成了一个查询字符串值,但是 GET 方法没有接受它的参数。需要
// GET: FileManagement/Delete/filename
public ActionResult Delete(string fileName)
并且在该方法中,您需要根据 fileName
初始化一个新的 FileInfo
class 并将该模型传递给视图。
下一个问题是您在确认页面中的表单没有将文件名传递回 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 提交表单(并在成功回调中删除按钮及其关联的 table 行)。一个典型的实现可能看起来像
@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
}