【问题标题】:Exception handling for file deletion and showing a message using ValidationMessage()使用 ValidationMessage() 处理文件删除和显示消息的异常处理
【发布时间】:2016-09-05 10:53:37
【问题描述】:

这个问题是我在以下链接中发布的上一个问题的延续:

Passing a filename to a view

总结:我正在尝试删除一个文件。由于上述帖子中的答案,我现在拥有所有必要的功能。但是,偶尔,如果文件正在使用中(例如,如果我在删除之前下载了文件,就会发生这种情况),我会收到 IOException。

我想处理这个异常并在发生这种情况时向用户显示一条消息。

我尝试调试 jQuery 代码,但每当我在其上设置断点时,我就会开始跳过 1000 行 jQuery 库。因此,作为一种快速的替代方案,我只是在各处放置警报。

我发现大部分代码都没有被执行 - 所以我把 cmets 放在我认为我应该看到消息但没有看到的地方。因此,我无法调试或弄清楚代码应该做什么。

所以我的第一个问题是如何让异常显示。似乎即使这是 Ajax,整个页面仍然会刷新,这对我来说不是 Ajax 调用的预期行为(因此,如果显示错误,它可能会在页面刷新时丢失)。但是,对于所有警报,我应该在某处看到错误,但我没有。我有目的地改变了工作代码,现在总是抛出异常。同样,删除功能有效,但错误报告失败。

我的下一个问题是简要解释为什么需要代码的每个部分(突出显示),因为我不知道为什么这些部分存在,我无法弄清楚,因为我无法调试或显示警报他们。

下面是索引视图和相关代码:

@model IEnumerable<FileInfo>

@{
    ViewBag.Title = "File List";
}

<h2>Index</h2>

<p>@Html.ActionLink("Upload", "Upload")</p>
<p>@Html.ValidationSummary(true, "", new { @class = "text-danger" })</p>
<p>@Html.ValidationMessage("Name", new { @class = "text-danger" })</p>
<span class="message text-danger"></span>
<table class="table">
    <tr>
        <th>File Name</th>
        <th>Actions</th>
    </tr>

    @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>
            <td>@Html.ActionLink("Download", "Download", new { fileName = file.Name })</td>
        </tr>
    }
</table>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")

    <script type="text/javascript">
        $(document).ready()
        {
            var url = '@Url.Action("Delete", "FileManagement")';

            $('.deleteform').submit(function ()
            {
                alert(".deleteform.submit entered...");//This alert shows

                return confirm("are you sure ...");//This alert shows

                var formData = $(this).serialize();
                alert(formData);//This does NOT show.

                var row = $(this).closest('tr');
                alert(row);//This does NOT show.

                $.post(url, formData, function (response)
                {
                    alert("$.post() entered...");//This does NOT show.
                    alert(response);//This does NOT show.
                    if (response)
                    {
                        alert("response true");//This does NOT show.
                        alert(response);//This does NOT show.
                        //row.remove(); //This code actually works even though the alert above does not show.
                    } else
                    {
                        alert("response false");//This does NOT show. - I dont know what this section of code is for.
                        //alert("Error 1 - display message");
                        // Oops - display message?
                    }
                    alert("$.post() finished...");//This does NOT show.

                }).fail(function (response)
                {
                    alert("$.fail() entered...");//This does NOT show. - I dont know what this section of code is for.
                    alert("Error 2 - display another message");//This does NOT show.
                    // Oops

                    alert("$.fail() finished...");//This does NOT show.
                });
                return false; // cancel the default submit

                alert(".deleteform.submit finished...");//This does NOT show.
            });
        }
    </script>
}

下面是这个视图的控制器和删除操作:

    public ActionResult Index()
    {
        DirectoryInfo dirInfo = new DirectoryInfo(Server.MapPath("~/UserFiles"));
        List<FileInfo> files = dirInfo.GetFiles().ToList();

        return View(files);
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Delete(string fileName)
    {
        var path = Path.Combine(Server.MapPath("~/UserFiles"), fileName);

        if (System.IO.File.Exists(path))
        {
            try
            {
                //System.IO.File.Delete(path);
                throw new IOException("Hello - Test Message...");
            }
            catch (IOException e)
            {
                Response.StatusCode = 500;
                Response.StatusDescription = e.Message;
                //ModelState.AddModelError("Name", e.Message);
            }
        }
        else
            return Json(null);
        //return HttpNotFound();

        return Json(true);
        //return RedirectToAction("Index");
    }

我将不胜感激。

【问题讨论】:

  • 您不能使用return confirm("are you sure ...") - 退出该方法(如果您正在处理默认提交,您只会使用它,但在您的情况下,您取消它并改为进行ajax调用)。而是使用if (confirm("....") { // make you ajax call }
  • 我弄清楚了当状态码为 500 时会发生失败,以及如何将消息发送到前端(这样我以后才能弄清楚如何显示它)。我还想出了 if(response) = true 部分,那是一切顺利的时候。我看不到的唯一部分是 if(response)...else 部分。我认为除了 200 之外的任何东西都会将我们发送到 .fail 部分。那么为什么我们需要 else 部分,实际上,没有 else,为什么还要 if(response) 呢?再次感谢您的帮助。
  • 如果您想返回错误的详细信息,则不需要它(我在上一个问题中给出的代码假设如果无法删除文件,您将使用return Json(null);(并且在if(response) 块中,您只会显示一个“无法删除文件” 一般错误 - 公开错误的具体细节通常不好 - 它只会为恶意用户提供有关潜在漏洞的额外信息在您的应用中)
  • @StephenMuecke - 所以...感谢您按照 if(confirm) 的建议更改 return(confirm) 行。我设法找出其余问题并显示错误消息。如果您想在有机会时将其作为答案,我会接受。一如既往,斯蒂芬,再次感谢您的所有帮助和建议。

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


【解决方案1】:

您不能在 .submit() 处理程序中使用 return confirm("are you sure ...");,因为它要么返回 false 取消所有内容,要么返回 true 在这种情况下您将进行正常提交。无论哪种情况,它都会退出函数。

你需要把脚本改成

$('.deleteform').submit(function () {
    if (confirm("....") {
        // make you ajax call here
    }
    return false; 
});

您还需要修改控制器代码。目前你的最后一行 (return Json(true);) 永远无法执行,if 块中的代码总是返回错误,所以总是会转到.fail() 函数。通常,您不应返回代码抛出的异常的具体细节(这只会将其暴露给恶意用户),最好返回更一般的错误,或者返回 null 并在脚本中硬编码错误消息。您可以通过多种方式处理此问题,包括

try
{
   // delete the file
   return Json(true); // to indicate success
}
catch (.... )
{
    return Json(null); // indicate failure
}

脚本中的意思

if (response) { // this will be executed if you returned true
    ... // delete the row
} else { // this will be executed if you returned null
    ... // display a message to the user
}

如果你没有捕获的服务器上抛出异常,.fail()函数将被执行。

或者,您可以返回具有Success 和Message 属性的对象,例如,这使您可以更好地控制消息

return Json(new { Success = true });
// or
return Json(new { Success = false, Message = "The file does not exist"});
// or
retrn Json(new { Success = false, Mesage = "The file is in use, please try again late" });

和脚本中的

$.post(url, formData, function (response) {
    if (response.Success == 'False') {
        var message = response.Message; // display it

【讨论】:

  • 再次感谢斯蒂芬。 - 现在清楚多了。我会尽快根据您的建议实施它。我还开始实施适当的角色和用户管理以更好地处理安全问题。我还没有添加日志以进行正确的错误处理,例如这种情况需要(而不是将所有错误都提供给最终用户)。我取得了很大的进步,很大一部分归功于您的帮助。再次感谢斯蒂芬。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-16
  • 2020-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多