วิธีที่ดีที่สุดในการคืน XML จากการกระทำของตัวควบคุมใน ASP.NET MVC คืออะไร? มีวิธีที่ดีในการส่งคืน JSON แต่ไม่ใช่สำหรับ XML ฉันจำเป็นต้องกำหนดเส้นทาง XML ผ่านมุมมองจริง ๆ หรือฉันควรทำวิธีการที่ไม่เหมาะสมที่สุดในการเผชิญเหตุตอบกลับหรือไม่
วิธีที่ดีที่สุดในการคืน XML จากการกระทำของตัวควบคุมใน ASP.NET MVC คืออะไร? มีวิธีที่ดีในการส่งคืน JSON แต่ไม่ใช่สำหรับ XML ฉันจำเป็นต้องกำหนดเส้นทาง XML ผ่านมุมมองจริง ๆ หรือฉันควรทำวิธีการที่ไม่เหมาะสมที่สุดในการเผชิญเหตุตอบกลับหรือไม่
คำตอบ:
ใช้การกระทำ XmlResult ของMVCContrib
สำหรับการอ้างอิงนี่คือรหัสของพวกเขา:
public class XmlResult : ActionResult { private object objectToSerialize; /// <summary> /// Initializes a new instance of the <see cref="XmlResult"/> class. /// </summary> /// <param name="objectToSerialize">The object to serialize to XML.</param> public XmlResult(object objectToSerialize) { this.objectToSerialize = objectToSerialize; } /// <summary> /// Gets the object to be serialized to XML. /// </summary> public object ObjectToSerialize { get { return this.objectToSerialize; } } /// <summary> /// Serialises the object that was passed into the constructor to XML and writes the corresponding XML to the result stream. /// </summary> /// <param name="context">The controller context for the current request.</param> public override void ExecuteResult(ControllerContext context) { if (this.objectToSerialize != null) { context.HttpContext.Response.Clear(); var xs = new System.Xml.Serialization.XmlSerializer(this.objectToSerialize.GetType()); context.HttpContext.Response.ContentType = "text/xml"; xs.Serialize(context.HttpContext.Response.Output, this.objectToSerialize); } } }
XmlSerialiser
และการเพิ่มความคิดเห็นของสมาชิกอาจทำได้ยาก ตั้งแต่ลุคโพสต์คำตอบนี้ (ประมาณสี่ปีที่แล้ว) Linq เป็น XML ได้พิสูจน์ตัวเองว่าเป็นสิ่งทดแทนที่หรูหราและทรงพลังสำหรับสถานการณ์ที่พบบ่อยที่สุด ตรวจสอบคำตอบของฉันสำหรับตัวอย่างของวิธีการทำเช่นนี้
return this.Content(xmlString, "text/xml");
application/xml
mime แทน
หากคุณกำลังสร้าง XML โดยใช้กรอบ Linq-to-XML ที่ยอดเยี่ยมแนวทางนี้จะเป็นประโยชน์
ฉันสร้างXDocument
ในวิธีการดำเนินการ
public ActionResult MyXmlAction()
{
// Create your own XDocument according to your requirements
var xml = new XDocument(
new XElement("root",
new XAttribute("version", "2.0"),
new XElement("child", "Hello World!")));
return new XmlActionResult(xml);
}
ActionResult
XML ที่กำหนดเองนี้สามารถใช้ซ้ำได้สำหรับคุณ
public sealed class XmlActionResult : ActionResult
{
private readonly XDocument _document;
public Formatting Formatting { get; set; }
public string MimeType { get; set; }
public XmlActionResult(XDocument document)
{
if (document == null)
throw new ArgumentNullException("document");
_document = document;
// Default values
MimeType = "text/xml";
Formatting = Formatting.None;
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.ContentType = MimeType;
using (var writer = new XmlTextWriter(context.HttpContext.Response.OutputStream, Encoding.UTF8) { Formatting = Formatting })
_document.WriteTo(writer);
}
}
คุณสามารถระบุประเภท MIME (เช่นapplication/rss+xml
) และระบุว่าควรจะเยื้องเอาต์พุตหรือไม่หากคุณต้องการ คุณสมบัติทั้งสองมีค่าเริ่มต้นที่สมเหตุสมผล
หากคุณต้องการการเข้ารหัสที่นอกเหนือจาก UTF8 คุณสามารถเพิ่มคุณสมบัติสำหรับสิ่งนั้นได้ง่าย
application/octet-stream
บังคับให้ดาวน์โหลด ฉันไม่รู้ว่า MIME ชนิดใดเปิดตัว Excel แต่คุณควรจะหามันออนไลน์ได้ง่ายพอ
หากคุณสนใจที่จะคืนค่า xml ผ่านการร้องขอและคุณมี "chunk" xml ของคุณคุณสามารถทำได้ (เป็นการกระทำในคอนโทรลเลอร์ของคุณ):
public string Xml()
{
Response.ContentType = "text/xml";
return yourXmlChunk;
}
มี XmlResult (และอีกมากมาย) ใน MVC Contrib ลองดูที่http://www.codeplex.com/MVCContrib
ฉันต้องทำสิ่งนี้เมื่อเร็ว ๆ นี้สำหรับโครงการ Sitecore ซึ่งใช้วิธีการสร้าง XmlDocument จากรายการ Sitecore และลูก ๆ และส่งคืนจากตัวควบคุม ActionResult เป็นไฟล์ ทางออกของฉัน:
public virtual ActionResult ReturnXml()
{
return File(Encoding.UTF8.GetBytes(GenerateXmlFeed().OuterXml), "text/xml");
}
ในที่สุดก็จัดการเพื่อให้ได้งานนี้และคิดว่าฉันจะบันทึกว่าที่นี่ด้วยความหวังที่จะช่วยคนอื่นให้เจ็บปวด
สิ่งแวดล้อม
เว็บเบราเซอร์ที่รองรับ
งานของฉันอยู่ที่การคลิกปุ่ม ui เรียกวิธีการในคอนโทรลเลอร์ของฉัน (มี params บางส่วน) จากนั้นให้ส่งคืน MS-Excel XML ผ่านการแปลง xslt MS-Excel XML ที่ส่งคืนจะทำให้เบราว์เซอร์ป๊อปอัพโต้ตอบเปิด / บันทึก สิ่งนี้ต้องใช้กับเบราว์เซอร์ทั้งหมด (ตามที่แสดงไว้ด้านบน)
ตอนแรกฉันลองกับ Ajax และสร้าง Anchor แบบไดนามิกด้วยคุณสมบัติ "ดาวน์โหลด" สำหรับชื่อไฟล์ แต่ใช้งานได้กับเบราว์เซอร์เพียง 3 ใน 5 (FF, Chrome, Opera) และไม่ใช่ IE หรือ Safari และมีปัญหาในการพยายามไฟเหตุการณ์คลิกของจุดยึดโดยทางโปรแกรมเพื่อให้เกิด "ดาวน์โหลด" จริง
สิ่งที่ฉันทำคือใช้ IFRAME แบบ "ล่องหน" และใช้งานได้กับเบราว์เซอร์ทั้ง 5!
ดังนั้นนี่คือสิ่งที่ฉันมาด้วย: [โปรดทราบว่าฉันไม่เคยเป็นกูรู html / javascript และรวมรหัสที่เกี่ยวข้องเท่านั้น]
HTML (ตัวอย่างของบิตที่เกี่ยวข้อง)
<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 (code snippet) @Drew สร้าง ActionResult แบบกำหนดเองชื่อ XmlActionResult ซึ่งฉันแก้ไขเพื่อวัตถุประสงค์ของฉัน
ส่งคืน XML จากการกระทำของตัวควบคุมในฐานะที่เป็น ActionResult?
วิธีการควบคุมของฉัน (ผลตอบแทน ActionResult)
สร้างตัวอย่างของ XmlActionResult ที่แก้ไขแล้วส่งคืน
XmlActionResult result = new XmlActionResult (excelXML, "application / vnd.ms-excel"); รุ่นสตริง = DateTime.Now.ToString ("dd_MMM_yyyy_hhmmsstt"); string fileMask = "LabelExport_ {0} .xml";
result.DownloadFilename = string.Format (fileMask, version); ผลตอบแทน;
การแก้ไขหลักกับคลาส XmlActionResult ที่ @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);
}
นั่นเป็นพื้นมัน หวังว่ามันจะช่วยให้ผู้อื่น
return File(stream, "text/xml");
ตัวเลือกที่ง่ายที่จะช่วยให้คุณใช้ลำธารและสิ่งที่อยู่
นี่เป็นวิธีง่ายๆในการทำ:
var xml = new XDocument(
new XElement("root",
new XAttribute("version", "2.0"),
new XElement("child", "Hello World!")));
MemoryStream ms = new MemoryStream();
xml.Save(ms);
return File(new MemoryStream(ms.ToArray()), "text/xml", "HelloWorld.xml");
ms
โดยตรงแทนที่จะคัดลอกไปที่ใหม่ วัตถุทั้งสองจะมีอายุการใช้งานเท่ากัน
ms.Position=0
และคุณสามารถคืนค่าหน่วยความจำดั้งเดิม จากนั้นคุณสามารถreturn new FileStreamResult(ms,"text/xml");
ชุดรูปแบบขนาดเล็กของคำตอบจาก Drew Noakesที่ใช้เมธอด Save () ของ XDocument
public sealed class XmlActionResult : ActionResult
{
private readonly XDocument _document;
public string MimeType { get; set; }
public XmlActionResult(XDocument document)
{
if (document == null)
throw new ArgumentNullException("document");
_document = document;
// Default values
MimeType = "text/xml";
}
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.Clear();
context.HttpContext.Response.ContentType = MimeType;
_document.Save(context.HttpContext.Response.OutputStream)
}
}