Sonunda bu işi almayı başar ve burada başkalarını acıyı kurtarmak umuduyla nasıl belgeleyeceğimi düşündüm.
çevre
- VS2012
- SQL Server 2008R2
- .NET 4.5
- ASP.NET MVC4 (Jilet)
- Windows 7
Desteklenen Web Tarayıcıları
- FireFox 23
- IE 10
- Chrome 29
- Opera 16
- Safari 5.1.7 (Windows için sonuncusu?)
Görevim bir ui düğmesine tıklamaktı, Denetleyicimde bir yöntem çağırın (bazı parametrelerle) ve ardından bir xslt dönüşümü yoluyla bir MS-Excel XML döndürmesini sağlayın. Döndürülen MS-Excel XML, tarayıcının Aç / Kaydet iletişim kutusunu açmasına neden olur. Bu, tüm tarayıcılarda (yukarıda listelenmiştir) çalışmak zorundaydı.
İlk başta Ajax ile denedim ve dosya adı için "download" özniteliğine sahip dinamik bir Anchor oluşturmaya çalıştım, ancak bu IE veya Safari için değil, 5 tarayıcıdan (FF, Chrome, Opera) sadece 3 tanesinde çalıştı. Ve gerçek "indirmeye" neden olmak için çapanın Click olayını programlı olarak tetiklemeye çalışırken sorunlar vardı.
Yaptığım şey "görünmez" bir IFRAME kullanmaktı ve 5 tarayıcıda da işe yaradı!
İşte burada ne ile geldi: [ben hiçbir şekilde bir html / javascript guru olduğumu ve sadece ilgili kodu dahil unutmayın lütfen]
HTML (alakalı bitlerin snippet'i)
<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 (kod snippet) @Drew, amacım için değiştirdiğim XmlActionResult adlı özel bir ActionResult oluşturdu.
ActionResult olarak bir denetleyicinin eyleminden XML döndürülsün mü?
Denetleyicim yöntemi (ActionResult döndürür)
- keys parametresini XML üreten SQL Server'da saklanan bir proc'a geçirir
- bu XML daha sonra xslt aracılığıyla bir MS-Excel xml (XmlDocument) biçimine dönüştürülür.
değiştirilmiş XmlActionResult örneğini oluşturur ve döndürür
XmlActionResult sonucu = yeni XmlActionResult (excelXML, "application / vnd.ms-excel"); string version = DateTime.Now.ToString ("dd_MMM_yyyy_hhmmsstt"); string fileMask = "LabelExport_ {0} .xml";
results.DownloadFilename = string.Format (fileMask, sürüm); sonuç;
@Drew tarafından oluşturulan XmlActionResult sınıfında ana değişiklik.
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);
}
Temelde buydu. Umarım başkalarına yardımcı olur.