以ActionResult方式从控制器的操作返回XML?

在ASP.NET MVC中从控制器的操作返回XML的最佳方式是什么? 有一个很好的方法来返回JSON,但不是用于XML。 我是否真的需要通过一个视图路由XML,或者我应该做的Response.Write – 它不是最好的做法?

使用MVCContrib的XmlResult操作。

这里供参考是他们的代码:

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); } } } 
 return this.Content(xmlString, "text/xml"); 

如果您使用优秀的Linq-to-XML框架构buildXML,那么这种方法将会很有帮助。

我在操作方法中创build一个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); } } 

您可以指定一个MIMEtypes(如application/rss+xml )以及是否需要缩进输出。 这两个属性都有明智的默认值。

如果你需要UTF8以外的编码,那么添加一个属性也很简单。

如果你只想通过请求返回xml,并且你有xml“chunk”,你可以做(​​作为你的控制器中的一个动作):

 public string Xml() { Response.ContentType = "text/xml"; return yourXmlChunk; } 

在MVC Contrib中有一个XmlResult(以及更多)。 看看http://www.codeplex.com/MVCContrib

最后设法得到这个工作,并认为我将logging如何在这里拯救他人的痛苦的希望。

环境

  • VS2012
  • SQL Server 2008R2
  • .NET 4.5
  • ASP.NET MVC4(剃刀)
  • Windows 7的

支持的Web浏览器

  • 火狐23
  • IE 10
  • Chrome 29
  • 歌剧16
  • Safari 5.1.7(最后一个用于Windows?)

我的任务是在一个单击button,调用我的控制器上的方法(带有一些参数),然后通过xslt转换返回一个MS-Excel XML。 返回的MS-Excel XML会导致浏览器popup打开/保存对话框。 这必须在所有浏览器(上面列出)中工作。

起初,我尝试了使用Ajax,并创build一个dynamic锚与文件名的“下载”属性,但只适用于5浏览器(FF,铬,歌剧)中的约3,而不是IE或Safari。 并试图以编程方式触发锚点的Click事件,导致实际的“下载”的问题。

我最终做的是使用“隐形”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(代码片段)@Drew创build了一个名为XmlActionResult的自定义ActionResult,我修改了它的目的。

以ActionResult方式从控制器的操作返回XML?

我的控制器方法(返回ActionResult)

  • 将keysparameter passing给生成XML的SQL Server存储过程
  • 该XML然后通过xslt转换成MS-Excel xml(XmlDocument)
  • 创build修改的XmlActionResult的实例并返回它

    XmlActionResult result = new XmlActionResult(excelXML,“application / vnd.ms-excel”); string version = DateTime.Now.ToString(“dd_MMM_yyyy_hhmmsstt”); stringfileMask =“LabelExport_ {0} .xml”;
    result.DownloadFilename = string.Format(fileMask,version); 返回结果;

@Drew创build的XmlActionResult类的主要修改。

 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); } 

基本上就是这样。 希望它可以帮助别人。

一个简单的选项,可以让你使用stream和所有return File(stream, "text/xml");

我最近不得不这样做一个Sitecore项目,它使用一个方法从Sitecore项目及其子项创build一个XmlDocument,并从控制器ActionResult返回它作为一个文件。 我的解决scheme

 public virtual ActionResult ReturnXml() { return File(Encoding.UTF8.GetBytes(GenerateXmlFeed().OuterXml), "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"); 

使用XDocument的Save()方法的Drew Noakes答案的一小部分变体。

 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) } }