如何在文件下载后重定向 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> 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> 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">×</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>
测试结果如下:
我有一个名为 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> 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> 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">×</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>
测试结果如下: