Cuối cùng quản lý để có được công việc này và nghĩ rằng tôi sẽ ghi lại làm thế nào ở đây với hy vọng cứu người khác nỗi đau.
Môi trường
- VS2012
- Máy chủ SQL 2008R2
- .NET 4.5
- ASP.NET MVC4 (Dao cạo)
- Windows 7
Trình duyệt web được hỗ trợ
- Lửa chữa cháy 23
- IE 10
- Chrome 29
- Opera 16
- Safari 5.1.7 (cái cuối cùng cho Windows?)
Nhiệm vụ của tôi là nhấp chuột vào nút ui, gọi một phương thức trên Trình điều khiển của tôi (với một số thông số) và sau đó nó sẽ trả về một MS-Excel XML thông qua một biến đổi xslt. MS-Excel XML được trả lại sau đó sẽ khiến trình duyệt bật lên hộp thoại Mở / Lưu. Điều này đã phải làm việc trong tất cả các trình duyệt (được liệt kê ở trên).
Lúc đầu, tôi đã thử với Ajax và để tạo một Anchor động với thuộc tính "download" cho tên tệp, nhưng nó chỉ hoạt động với khoảng 3 trong số 5 trình duyệt (FF, Chrome, Opera) chứ không phải cho IE hoặc Safari. Và đã có vấn đề với việc cố gắng lập trình kích hoạt sự kiện Click của neo để gây ra "tải xuống" thực sự.
Điều cuối cùng tôi đã làm là sử dụng IFRAME "vô hình" và nó hoạt động cho cả 5 trình duyệt!
Vì vậy, đây là những gì tôi nghĩ ra: [xin lưu ý rằng tôi không phải là một guru html / javascript và chỉ bao gồm các mã có liên quan]
HTML (đoạn mã liên quan)
<div id="docxOutput">
<iframe id="ifOffice" name="ifOffice" width="0" height="0"
hidden="hidden" seamless='seamless' frameBorder="0" scrolling="no"></iframe></div>
JAVASCRIPT
//url to call in the controller to get MS-Excel xml
var _lnkToControllerExcel = '@Url.Action("ExportToExcel", "Home")';
$("#btExportToExcel").on("click", function (event) {
event.preventDefault();
$("#ProgressDialog").show();//like an ajax loader gif
//grab the basket as xml
var keys = GetMyKeys();//returns delimited list of keys (for selected items from UI)
//potential problem - the querystring might be too long??
//2K in IE8
//4096 characters in ASP.Net
//parameter key names must match signature of Controller method
var qsParams = [
'keys=' + keys,
'locale=' + '@locale'
].join('&');
//The element with id="ifOffice"
var officeFrame = $("#ifOffice")[0];
//construct the url for the iframe
var srcUrl = _lnkToControllerExcel + '?' + qsParams;
try {
if (officeFrame != null) {
//Controller method can take up to 4 seconds to return
officeFrame.setAttribute("src", srcUrl);
}
else {
alert('ExportToExcel - failed to get reference to the office iframe!');
}
} catch (ex) {
var errMsg = "ExportToExcel Button Click Handler Error: ";
HandleException(ex, errMsg);
}
finally {
//Need a small 3 second ( delay for the generated MS-Excel XML to come down from server)
setTimeout(function () {
//after the timeout then hide the loader graphic
$("#ProgressDialog").hide();
}, 3000);
//clean up
officeFrame = null;
srcUrl = null;
qsParams = null;
keys = null;
}
});
C # SERVER-SIDE (đoạn mã) @Drew đã tạo một ActionResult tùy chỉnh có tên XmlActionResult mà tôi đã sửa đổi cho mục đích của mình.
Trả lại XML từ hành động của bộ điều khiển dưới dạng ActionResult?
Phương thức điều khiển của tôi (trả về ActionResult)
- chuyển tham số khóa cho một máy chủ lưu trữ SQL Server tạo ra XML
- XML đó sau đó được chuyển đổi qua xslt thành xml MS-Excel (XmlDocument)
tạo bản sao của XmlActionResult đã sửa đổi và trả về nó
Kết quả XmlActionResult = new XmlActionResult (excelXML, "application / vnd.ms-excel"); chuỗi phiên bản = DateTime.Now.ToString ("dd_MMM_yyyy_hhmmsstt"); chuỗi fileMask = "LabelExport_ {0} .xml";
result.DoadFilename = string.Format (fileMask, phiên bản); kết quả trả về;
Sửa đổi chính cho lớp XmlActionResult mà @Drew đã tạo.
public override void ExecuteResult(ControllerContext context)
{
string lastModDate = DateTime.Now.ToString("R");
//Content-Disposition: attachment; filename="<file name.xml>"
// must set the Content-Disposition so that the web browser will pop the open/save dialog
string disposition = "attachment; " +
"filename=\"" + this.DownloadFilename + "\"; ";
context.HttpContext.Response.Clear();
context.HttpContext.Response.ClearContent();
context.HttpContext.Response.ClearHeaders();
context.HttpContext.Response.Cookies.Clear();
context.HttpContext.Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache);// Stop Caching in IE
context.HttpContext.Response.Cache.SetNoStore();// Stop Caching in Firefox
context.HttpContext.Response.Cache.SetMaxAge(TimeSpan.Zero);
context.HttpContext.Response.CacheControl = "private";
context.HttpContext.Response.Cache.SetLastModified(DateTime.Now.ToUniversalTime());
context.HttpContext.Response.ContentType = this.MimeType;
context.HttpContext.Response.Charset = System.Text.UTF8Encoding.UTF8.WebName;
//context.HttpContext.Response.Headers.Add("name", "value");
context.HttpContext.Response.Headers.Add("Last-Modified", lastModDate);
context.HttpContext.Response.Headers.Add("Pragma", "no-cache"); // HTTP 1.0.
context.HttpContext.Response.Headers.Add("Expires", "0"); // Proxies.
context.HttpContext.Response.AppendHeader("Content-Disposition", disposition);
using (var writer = new XmlTextWriter(context.HttpContext.Response.OutputStream, this.Encoding)
{ Formatting = this.Formatting })
this.Document.WriteTo(writer);
}
Về cơ bản là như vậy. Hy vọng nó sẽ giúp người khác.