使用 HttpContext.Current.Response 导出会导致问题
Exporting Using HttpContext.Current.Response is Causing Issues
我正在使用 asp.net/C#/HTML5/bootstrap 开发网站。其中一项要求是将文档导出为 Excel and/or PDF。我能够使用以下代码段(这是 Excel 代码段)导出(成功):
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + filename);
HttpContext.Current.Response.BinaryWrite(xlsBytes);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
我遇到的问题是,在此运行之后,它似乎停止了页面生命周期的轨道。例如,用户单击导出按钮,调用 javascript 抛出 "Please wait" 模式对话框并提交表单:
<script src="../Scripts/waitingFor.js"></script>
<script type="text/javascript">
function pleaseWait() {
waitingDialog.show("Building File<br/>...this could take a minute", { dialogSize: "sm", progressType: "warning" });
form = document.getElementById("frm_contentMaster");
form.submit();
}
</script>
javascript 包含文件:
/**
* Module for displaying "Waiting for..." dialog using Bootstrap
*
* @author Eugene Maslovich <ehpc@em42.ru>
*/
(function (root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(['jquery'], function ($) {
return (root.waitingDialog = factory($));
});
}
else {
root.waitingDialog = root.waitingDialog || factory(root.jQuery);
}
}(this, function ($) {
'use strict';
/**
* Dialog DOM constructor
*/
function constructDialog($dialog) {
// Deleting previous incarnation of the dialog
if ($dialog) {
$dialog.remove();
}
return $(
'<div id="waitingFor" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog" aria-hidden="true" style="padding-top:15%; overflow-y:visible;">' +
'<div class="modal-dialog modal-m">' +
'<div class="modal-content">' +
'<div class="modal-header" style="display: none;"></div>' +
'<div class="modal-body">' +
'<div class="progress progress-striped active" style="margin-bottom:0;">' +
'<div class="progress-bar" style="width: 100%"></div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
}
// Dialog object
var $dialog;
return {
/**
* Opens our dialog
* @param message Custom message
* @param options Custom options:
* options.headerText - if the option is set to boolean false,
* it will hide the header and "message" will be set in a paragraph above the progress bar.
* When headerText is a not-empty string, "message" becomes a content
* above the progress bar and headerText string will be set as a text inside the H3;
* options.headerSize - this will generate a heading corresponding to the size number. Like <h1>, <h2>, <h3> etc;
* options.headerClass - extra class(es) for the header tag;
* options.dialogSize - bootstrap postfix for dialog size, e.g. "sm", "m";
* options.progressType - bootstrap postfix for progress bar type, e.g. "success", "warning";
* options.contentElement - determines the tag of the content element.
* Defaults to "p", which will generate a <p> tag;
* options.contentClass - extra class(es) for the content tag.
*/
show: function (message, options) {
// Assigning defaults
if (typeof options === 'undefined') {
options = {};
}
if (typeof message === 'undefined') {
message = 'Loading';
}
var settings = $.extend({
headerText: '',
headerSize: 3,
headerClass: '',
dialogSize: 'm',
progressType: '',
contentElement: 'p',
contentClass: 'content',
onHide: null // This callback runs after the dialog was hidden
}, options),
$headerTag, $contentTag;
$dialog = constructDialog($dialog);
// Configuring dialog
$dialog.find('.modal-dialog').attr('class', 'modal-dialog').addClass('modal-' + settings.dialogSize);
$dialog.find('.progress-bar').attr('class', 'progress-bar');
if (settings.progressType) {
$dialog.find('.progress-bar').addClass('progress-bar-' + settings.progressType);
}
// Generate header tag
$headerTag = $('<h' + settings.headerSize + ' />');
$headerTag.css({ 'margin': 0 });
if (settings.headerClass) {
$headerTag.addClass(settings.headerClass);
}
// Generate content tag
$contentTag = $('<' + settings.contentElement + ' />');
if (settings.contentClass) {
$contentTag.addClass(settings.contentClass);
}
if (settings.headerText === false) {
$contentTag.html(message);
$dialog.find('.modal-body').prepend($contentTag);
}
else if (settings.headerText) {
$headerTag.html(settings.headerText);
$dialog.find('.modal-header').html($headerTag).show();
$contentTag.html(message);
$dialog.find('.modal-body').prepend($contentTag);
}
else {
$headerTag.html(message);
$dialog.find('.modal-header').html($headerTag).show();
}
// Adding callbacks
if (typeof settings.onHide === 'function') {
$dialog.off('hidden.bs.modal').on('hidden.bs.modal', function () {
settings.onHide.call($dialog);
});
}
// Opening dialog
$dialog.modal();
},
/**
* Closes dialog
*/
hide: function () {
if (typeof $dialog !== 'undefined') {
$dialog.modal('hide');
}
}
};
}));
我正在使用 NPOI 在代码隐藏(简化功能)中创建 Excel 文件:
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
protected void exportExcel()
{
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sh = (XSSFSheet)wb.CreateSheet("Legend");
//*****************************************
//* Workbook Download & Cleanup
//*****************************************
MemoryStream stream = new MemoryStream();
wb.Write(stream);
stream.Dispose();
var xlsBytes = stream.ToArray();
string filename = "Behavior Stats YTD.xlsx";
MemoryStream newStream = new MemoryStream(xlsBytes);
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + filename);
HttpContext.Current.Response.BinaryWrite(xlsBytes);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
这会创建 Excel 文件并将其推送给用户,但后面代码的生命周期不会继续——它会在 End 命令后立即停止。如果我注释掉 HttpContext 行,显然 Excel sheet 不会被创建,但页面的生命周期仍在继续——后面的其余代码运行、页面刷新和模态请稍候对话框消失。
我是不是用错了?我见过的大多数关于如何导出的示例都使用此方法。有没有其他更干净 and/or 更安全的导出方式?我需要对此做一个简单的调整,让生命周期继续下去吗?谁创造了液体肥皂,为什么?
如果您能提供任何帮助,我们将不胜感激。
一切正常。您告诉浏览器响应是一个文件。响应一次只能是一件事。您不能在同一响应中包含页面内容和文件。
您可以通过在 IFrame 中下载文件来将两者分开。首先将您的文件下载 C# 代码放在其自己的页面中。然后使用 JavaScript 函数从 IFrame 调用该页面。
function DownloadExcel() {
var downloadFrame = document.createElement("IFRAME");
if (downloadFrame != null) {
downloadFrame.setAttribute("src", '/DownloadExcel.aspx');
downloadFrame.style.width = "0px";
downloadFrame.style.height = "0px";
document.body.appendChild(downloadFrame);
}
}
我正在使用 asp.net/C#/HTML5/bootstrap 开发网站。其中一项要求是将文档导出为 Excel and/or PDF。我能够使用以下代码段(这是 Excel 代码段)导出(成功):
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + filename);
HttpContext.Current.Response.BinaryWrite(xlsBytes);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
我遇到的问题是,在此运行之后,它似乎停止了页面生命周期的轨道。例如,用户单击导出按钮,调用 javascript 抛出 "Please wait" 模式对话框并提交表单:
<script src="../Scripts/waitingFor.js"></script>
<script type="text/javascript">
function pleaseWait() {
waitingDialog.show("Building File<br/>...this could take a minute", { dialogSize: "sm", progressType: "warning" });
form = document.getElementById("frm_contentMaster");
form.submit();
}
</script>
javascript 包含文件:
/**
* Module for displaying "Waiting for..." dialog using Bootstrap
*
* @author Eugene Maslovich <ehpc@em42.ru>
*/
(function (root, factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(['jquery'], function ($) {
return (root.waitingDialog = factory($));
});
}
else {
root.waitingDialog = root.waitingDialog || factory(root.jQuery);
}
}(this, function ($) {
'use strict';
/**
* Dialog DOM constructor
*/
function constructDialog($dialog) {
// Deleting previous incarnation of the dialog
if ($dialog) {
$dialog.remove();
}
return $(
'<div id="waitingFor" class="modal fade" data-backdrop="static" data-keyboard="false" tabindex="-1" role="dialog" aria-hidden="true" style="padding-top:15%; overflow-y:visible;">' +
'<div class="modal-dialog modal-m">' +
'<div class="modal-content">' +
'<div class="modal-header" style="display: none;"></div>' +
'<div class="modal-body">' +
'<div class="progress progress-striped active" style="margin-bottom:0;">' +
'<div class="progress-bar" style="width: 100%"></div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>' +
'</div>'
);
}
// Dialog object
var $dialog;
return {
/**
* Opens our dialog
* @param message Custom message
* @param options Custom options:
* options.headerText - if the option is set to boolean false,
* it will hide the header and "message" will be set in a paragraph above the progress bar.
* When headerText is a not-empty string, "message" becomes a content
* above the progress bar and headerText string will be set as a text inside the H3;
* options.headerSize - this will generate a heading corresponding to the size number. Like <h1>, <h2>, <h3> etc;
* options.headerClass - extra class(es) for the header tag;
* options.dialogSize - bootstrap postfix for dialog size, e.g. "sm", "m";
* options.progressType - bootstrap postfix for progress bar type, e.g. "success", "warning";
* options.contentElement - determines the tag of the content element.
* Defaults to "p", which will generate a <p> tag;
* options.contentClass - extra class(es) for the content tag.
*/
show: function (message, options) {
// Assigning defaults
if (typeof options === 'undefined') {
options = {};
}
if (typeof message === 'undefined') {
message = 'Loading';
}
var settings = $.extend({
headerText: '',
headerSize: 3,
headerClass: '',
dialogSize: 'm',
progressType: '',
contentElement: 'p',
contentClass: 'content',
onHide: null // This callback runs after the dialog was hidden
}, options),
$headerTag, $contentTag;
$dialog = constructDialog($dialog);
// Configuring dialog
$dialog.find('.modal-dialog').attr('class', 'modal-dialog').addClass('modal-' + settings.dialogSize);
$dialog.find('.progress-bar').attr('class', 'progress-bar');
if (settings.progressType) {
$dialog.find('.progress-bar').addClass('progress-bar-' + settings.progressType);
}
// Generate header tag
$headerTag = $('<h' + settings.headerSize + ' />');
$headerTag.css({ 'margin': 0 });
if (settings.headerClass) {
$headerTag.addClass(settings.headerClass);
}
// Generate content tag
$contentTag = $('<' + settings.contentElement + ' />');
if (settings.contentClass) {
$contentTag.addClass(settings.contentClass);
}
if (settings.headerText === false) {
$contentTag.html(message);
$dialog.find('.modal-body').prepend($contentTag);
}
else if (settings.headerText) {
$headerTag.html(settings.headerText);
$dialog.find('.modal-header').html($headerTag).show();
$contentTag.html(message);
$dialog.find('.modal-body').prepend($contentTag);
}
else {
$headerTag.html(message);
$dialog.find('.modal-header').html($headerTag).show();
}
// Adding callbacks
if (typeof settings.onHide === 'function') {
$dialog.off('hidden.bs.modal').on('hidden.bs.modal', function () {
settings.onHide.call($dialog);
});
}
// Opening dialog
$dialog.modal();
},
/**
* Closes dialog
*/
hide: function () {
if (typeof $dialog !== 'undefined') {
$dialog.modal('hide');
}
}
};
}));
我正在使用 NPOI 在代码隐藏(简化功能)中创建 Excel 文件:
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
protected void exportExcel()
{
XSSFWorkbook wb = new XSSFWorkbook();
XSSFSheet sh = (XSSFSheet)wb.CreateSheet("Legend");
//*****************************************
//* Workbook Download & Cleanup
//*****************************************
MemoryStream stream = new MemoryStream();
wb.Write(stream);
stream.Dispose();
var xlsBytes = stream.ToArray();
string filename = "Behavior Stats YTD.xlsx";
MemoryStream newStream = new MemoryStream(xlsBytes);
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.UTF8;
HttpContext.Current.Response.AddHeader("content-disposition", "attachment; filename=" + filename);
HttpContext.Current.Response.BinaryWrite(xlsBytes);
HttpContext.Current.Response.Flush();
HttpContext.Current.Response.End();
}
这会创建 Excel 文件并将其推送给用户,但后面代码的生命周期不会继续——它会在 End 命令后立即停止。如果我注释掉 HttpContext 行,显然 Excel sheet 不会被创建,但页面的生命周期仍在继续——后面的其余代码运行、页面刷新和模态请稍候对话框消失。
我是不是用错了?我见过的大多数关于如何导出的示例都使用此方法。有没有其他更干净 and/or 更安全的导出方式?我需要对此做一个简单的调整,让生命周期继续下去吗?谁创造了液体肥皂,为什么?
如果您能提供任何帮助,我们将不胜感激。
一切正常。您告诉浏览器响应是一个文件。响应一次只能是一件事。您不能在同一响应中包含页面内容和文件。
您可以通过在 IFrame 中下载文件来将两者分开。首先将您的文件下载 C# 代码放在其自己的页面中。然后使用 JavaScript 函数从 IFrame 调用该页面。
function DownloadExcel() {
var downloadFrame = document.createElement("IFRAME");
if (downloadFrame != null) {
downloadFrame.setAttribute("src", '/DownloadExcel.aspx');
downloadFrame.style.width = "0px";
downloadFrame.style.height = "0px";
document.body.appendChild(downloadFrame);
}
}