如何在文件下载后重定向 ASP.NET 核心 MVC 局部视图

How to redirect a ASP.NET Core MVC partial view after file download

我有一个名为 ExportPagePartial 的 asp.net 核心 MVC 局部视图,允许用户从系统导出页面并下载。在 HttpGet 控制器操作中,我显示部分视图(作为模态弹出窗口)以获取用户输入。

模态弹出

<a class="dropdown-item" asp-action="ExportPagePartial" asp-route-userId="@Model.UserId" asp-route-businessAccountId="@Model.BusinessAccountId" asp-route-projectId="@Model.ProjectId" asp-route-pageId="@Model.PageId" data-toggle="modal" data-target="#ModalPlaceholder" title="Export page."><i class="fas fa-cloud-download-alt"></i> &nbsp; Export</a>

控制器获取操作

[HttpGet]
public IActionResult ExportPagePartial(string userId, string businessAccountId, string projectId, string pageId)
{       
    ExportPageViewModel model = new ExportPageViewModel()
    {
       // Set properties
    };

    return PartialView(nameof(ExportPagePartial), model);
}

一旦用户点击模态弹出部分视图中的“导出”按钮(这是一个表单提交操作),就会正确调用以下 HTTPPost 操作。 在此操作中,我必须从 Web Api 获取文件,然后通过浏览器下载它,但是在下载完成后我想关闭局部视图。下载完成后,部分视图仍然可见。

return 操作永远不会起作用,部分模态弹出视图不会关闭 return RedirectToAction(nameof(BlahRedirectAction));

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ExportPagePartial(ExportPageViewModel model)
 {
            // Call Web API to get the file              
            string downloadUrl = "blah_blah_url";
            using (HttpResponseMessage httpResponse = await WebApiClient.HttpClient.PostAsJsonAsync(downloadUrl, unprotectedExportInput))
                {
                    if (!httpResponse.IsSuccessStatusCode)
                    {
                        throw new InvalidOperationException(await httpResponse.Content.ReadAsStringAsync());
                    }

                    // Download the file now.
                    ActionContext actionContext = new ActionContext(HttpContext, ControllerContext.RouteData, ControllerContext.ActionDescriptor, ModelState);
                    FileStreamResult fileContent = File(await httpResponse.Content.ReadAsStreamAsync(), httpResponse.Content.Headers.ContentType.MediaType, httpResponse.Content.Headers.ContentDisposition.FileName);
                    await fileContent.ExecuteResultAsync(actionContext);
                }

            // Redirect to main pain
            // The view never redirects and partial view is still visible
            return RedirectToAction(nameof(BlahRedirectAction));
 }

fileContent.ExecuteResultAsync(actionContext);

这是因为你下载文件的时候,ExportPagePartial已经确定了return流程,不会执行RedirectToAction.

建议大家把触发ExportPagePartial的post方法改成ajax来实现,这样就可以成功执行ExportPagePartial和方法后, 将页面重定向到你想要的 js.

这是我根据您的代码制作的完整演示代码:

  public class ExportTestController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        [HttpGet]
        public IActionResult ExportPagePartial(string userId, string businessAccountId, string projectId, string pageId)
        {
            ExportPageViewModel model = new ExportPageViewModel()
            {
                Id = 1,
                Gender = "male",
                Name = "aaa",
                Number = "1231244"
            };
            return PartialView(nameof(ExportPagePartial), model);
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> ExportPagePartial(ExportPageViewModel model)
        {
            // Call Web API to get the file              
            string downloadUrl = "blah_blah_url";

              using (HttpResponseMessage httpResponse = await WebApiClient.HttpClient.PostAsJsonAsync(downloadUrl, unprotectedExportInput))
                {
                    if (!httpResponse.IsSuccessStatusCode)
                    {
                        throw new InvalidOperationException(await httpResponse.Content.ReadAsStringAsync());
                    }

                    // Download the file now.
                    ActionContext actionContext = new ActionContext(HttpContext, ControllerContext.RouteData, ControllerContext.ActionDescriptor, ModelState);
                    FileStreamResult fileContent = File(await httpResponse.Content.ReadAsStreamAsync(), httpResponse.Content.Headers.ContentType.MediaType, httpResponse.Content.Headers.ContentDisposition.FileName);
                    await fileContent.ExecuteResultAsync(actionContext);
                }

            // Redirect to main pain
            // The view never redirects and partial view is still visible
            return RedirectToAction(nameof(BlahRedirectAction));
        }

Index.cshtml:

@{
    ViewData["Title"] = "Index";
    Layout = null;
}

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script>
    $(function () {
        $("a").click(function () {
            var route = $(this).attr("href");
            $('#partial').load(route);
        })

        $("form").submit(function () {
            $.ajax({
                url: $("form").attr('action'),
                type: 'Post',
                data: $("form").serializeArray(),
                success: function () {
                    //$("#ModalPlaceholder").hide();
                    window.location.href = "/ExportTest/BlahRedirectAction";
                }
            });
        })
    })

</script>
<a class="dropdown-item" asp-action="ExportPagePartial"
   asp-route-userId="1" asp-route-businessAccountId="1"
   asp-route-projectId="1" asp-route-pageId="1"
   data-toggle="modal" data-target="#ModalPlaceholder" title="Export page."><i class="fas fa-cloud-download-alt"></i> &nbsp; Export</a>

<div class="modal fade" id="ModalPlaceholder" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
    <form asp-action="ExportPagePartial" method="post">
        <div id="partial">
        </div>
    </form>
</div>

ExportPagePartial.cshtml:

@model ExportPageViewModel
<div class="modal-dialog" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
            <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                <span aria-hidden="true">&times;</span>
            </button>
        </div>
        <div class="modal-body">
            <div class="form-group">
                <label asp-for="Id" class="control-label">@Model.Id</label>
                <input asp-for="Id" class="form-control" hidden />
            </div>
            <div class="form-group">
                <label asp-for="Name" class="control-label"></label>
                <input asp-for="Name" class="form-control" />
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Gender" class="control-label"></label>
                <input asp-for="Gender" class="form-control" />
                <span asp-validation-for="Gender" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Number" class="control-label"></label>
                <input asp-for="Number" class="form-control" />
                <span asp-validation-for="Number" class="text-danger"></span>
            </div>
        </div>
        <div class="modal-footer">
            <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
            <button type="submit" class="btn btn-primary" >Save changes</button>
        </div>
    </div>
</div> 

测试结果如下: