将控制器操作中的 XML 作为 ActionResult 返回?

在 ASP.NET MVC 中,从控制器操作返回 XML 的最佳方法是什么?有一种返回 JSON 的好方法,但不适用于 XML。我真的需要通过视图路由 XML 吗? 还是应该采用非最佳实践的响应方式。写?

103056 次浏览

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

在 MVC Contrib 中有一个 XmlResult (还有更多)

如果您只对通过请求返回 xml 感兴趣,并且您有 xml“块”,那么您可以这样做(作为控制器中的一个操作) :

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

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

我在 action 方法中创建了一个 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以外的编码,那么也可以简单地为其添加一个属性。

最后设法得到这项工作,并认为我会记录如何在这里,希望拯救其他人的痛苦。

环境

  • VS2012
  • SQLServer2008R2
  • .NET 4.5
  • NET MVC4(Razor)
  • 视窗7

支持的 Web 浏览器

  • 火狐23
  • IE10
  • Chrome 29
  • 歌剧16
  • Safari 5.1.7(Windows 的最后一个版本?)

我的任务是单击 ui 按钮,在 Controller 上调用一个方法(使用一些参数) ,然后让它通过 xslt 转换返回一个 MS-Excel XML。然后,返回的 MS-Excel XML 将导致浏览器弹出“打开/保存”对话框。这必须适用于所有的浏览器(上面列出的)。

起初,我尝试用 Ajax 创建一个动态 Anchor,其中包含文件名的“ download”属性, 但这只适用于5款浏览器中的3款(FF、 Chrome、 Opera) ,而不适用于 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 (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 创建了一个名为 XmlActionResult 的自定义 ActionResult,我为此进行了修改。

从控制器的操作中返回 XML 作为 ActionResult?

MyController 方法(返回 ActionResult)

  • 将 key 参数传递给生成 XML 的 SQLServer 存储过程
  • 然后通过 xslt 将 XML 转换为 MS-Excel XML (XmlDocument)
  • 创建修改后的 XmlActionResult 的实例并返回它

    XmlActionResult = new XmlActionResult (excelXML,“ application/vnd.ms-excel”) ; String version = DateTime. Now.ToString (“ dd _ MMM _ yyyy _ hhmmsstt”) ; 字符串 fileMask = “ LabelExport _ {0} . xml”;
    格式(fileMask,版本) ; 返回结果

@ Drew 创建的 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);
}

基本上就是这样。 希望能帮到别人。

一个简单的选项,让您使用流和所有的 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");

我最近不得不为一个 Sitecore 项目这样做,该项目使用一个方法从 Sitecore Item 及其子元素创建 XmlDocument,并从控制器 ActionResult 作为 File 返回它。我的解决办法是:

public virtual ActionResult ReturnXml()
{
return File(Encoding.UTF8.GetBytes(GenerateXmlFeed().OuterXml), "text/xml");
}

使用 XDocument 的 Save ()方法的 德鲁 · 诺克斯的回答的一个小变体。

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

使用这些方法之一

    public ContentResult GetXml()
{
string xmlString  = "your xml data";
return Content(xmlString, "text/xml");
}

或者

    public string GetXml()
{
string xmlString = "your xml data";
Response.ContentType = "text/xml";
return xmlString;
}