Akhirnya berhasil mendapatkan pekerjaan ini dan berpikir saya akan mendokumentasikan bagaimana di sini dengan harapan menyelamatkan orang lain dari rasa sakit.
Lingkungan Hidup
- VS2012
- SQL Server 2008R2
- .NET 4.5
- ASP.NET MVC4 (Razor)
- Windows 7
Browser Web yang didukung
- FireFox 23
- IE 10
- Chrome 29
- Opera 16
- Safari 5.1.7 (yang terakhir untuk Windows?)
Tugas saya adalah klik tombol ui, panggil metode pada Kontroler saya (dengan beberapa params) dan kemudian kembalikan XML MS-Excel melalui transformasi xslt. MS-Excel XML yang dikembalikan kemudian akan menyebabkan browser popup dialog Open / Save. Ini harus berfungsi di semua browser (tercantum di atas).
Pada awalnya saya mencoba dengan Ajax dan membuat Anchor dinamis dengan atribut "unduh" untuk nama file, tetapi itu hanya bekerja untuk sekitar 3 dari 5 browser (FF, Chrome, Opera) dan bukan untuk IE atau Safari. Dan ada masalah dengan mencoba memrogram acara Click jangkar secara terprogram untuk menyebabkan "unduhan" yang sebenarnya.
Apa yang akhirnya saya lakukan adalah menggunakan IFRAME "tidak terlihat" dan bekerja untuk semua 5 browser!
Jadi inilah yang saya kemukakan: [harap dicatat bahwa saya tidak berarti guru html / javascript dan hanya menyertakan kode yang relevan]
HTML (potongan bit yang relevan)
<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 (potongan kode) @Drew membuat ActionResult kustom yang disebut XmlActionResult yang saya modifikasi untuk tujuan saya.
Kembalikan XML dari tindakan pengontrol sebagai ActionResult?
Metode Pengontrol Saya (mengembalikan ActionResult)
- melewati parameter kunci ke proc SQL Server tersimpan yang menghasilkan XML
- XML itu kemudian ditransformasikan melalui xslt menjadi MS-Excel xml (XmlDocument)
menciptakan instance XmlActionResult yang dimodifikasi dan mengembalikannya
Hasil XmlActionResult = XmlActionResult baru (excelXML, "application / vnd.ms-excel"); versi string = DateTime.Now.ToString ("dd_MMM_yyyy_hhmmsstt"); string fileMask = "LabelExport_ {0} .xml";
result.DownloadFilename = string.Format (fileMask, versi); hasil pengembalian;
Modifikasi utama ke kelas XmlActionResult yang dibuat @Drew.
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);
}
Itu pada dasarnya itu. Semoga ini bisa membantu orang lain.