Return XML from a controller ' s action in as an ActionResult?

Jaki jest najlepszy sposób na zwrócenie XML z akcji kontrolera w ASP.NET MVC? Jest dobry sposób na zwrócenie JSON, ale nie dla XML. Czy naprawdę muszę przekierowywać XML przez Widok, czy powinienem zrobić nie najlepszy sposób odpowiedzi.Piszesz?

Author: Erik Philips, 2008-09-25

11 answers

Użyj MVCContrib'S Xmlresult Action.

Dla odniesienia tutaj jest ich kod:

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);
        }
    }
}
 115
Author: Luke Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-23 10:57:10
return this.Content(xmlString, "text/xml");
 138
Author: Petr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-23 10:58:12

Jeśli budujesz XML przy użyciu doskonałego frameworka Linq-to-XML, to takie podejście będzie pomocne.

Tworzę XDocument w metodzie action.

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

To wielokrotnego użytku, niestandardowe ActionResult serializuje XML dla Ciebie.

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

Możesz określić typ MIME (np. application/rss+xml) i czy wyjście powinno być wcięte, jeśli zajdzie taka potrzeba. Obie właściwości mają rozsądne wartości domyślne.

Jeśli potrzebujesz kodowania innego niż UTF8, łatwo jest dodać właściwość dla tego też.

 32
Author: Drew Noakes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-07 13:26:25

Jeśli jesteś zainteresowany tylko zwróceniem xml poprzez żądanie, a masz swój XML "chunk", możesz po prostu zrobić (jako akcję w kontrolerze):

public string Xml()
{
    Response.ContentType = "text/xml";
    return yourXmlChunk;
}
 27
Author: Erik,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-16 14:11:35

Jest XmlResult (i wiele więcej) w MVC Contrib. Spójrz na http://www.codeplex.com/MVCContrib

 17
Author: Mahdi Taghizadeh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-19 18:35:11

Ostatnio musiałem to zrobić dla projektu Sitecore, który używa metody do tworzenia XmlDocument z elementu Sitecore i jego potomków i zwraca go z kontrolera ActionResult jako plik. Moje rozwiązanie:

public virtual ActionResult ReturnXml()
{
    return File(Encoding.UTF8.GetBytes(GenerateXmlFeed().OuterXml), "text/xml");
}
 5
Author: Matthew Price,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-26 16:40:36

W końcu udało się zdobyć tę pracę i pomyślałem, że udokumentuję jak tutaj w nadziei na uratowanie innym bólu.

Środowisko

  • VS2012
  • SQL Server 2008R2
  • . NET 4.5
  • ASP.NET MVC4 (Razor)
  • Windows 7

Obsługiwane Przeglądarki Internetowe

  • FireFox 23
  • IE 10
  • Chrome 29
  • Opera 16
  • Safari 5.1.7 (ostatnia Dla Windows?)

Moje zadanie polegało na kliknięciu przycisku ui, wywołaniu metody na moim kontrolerze (z kilkoma paramami), a następnie zwróć MS-Excel XML poprzez transformację xslt. Zwracany MS-Excel XML spowoduje, że przeglądarka wyskakuje okno dialogowe Otwórz/Zapisz. To musiało działać we wszystkich przeglądarkach (wymienionych powyżej).

Na początku próbowałem z Ajax i stworzyć dynamiczny Anchor z atrybutem "download" dla nazwy pliku, ale to działało tylko dla około 3 z 5 przeglądarek (FF, Chrome, Opera), a nie dla IE czy Safari. I były problemy z próbowaniem programowo Uruchom Zdarzenie kliknięcia kotwicy, aby spowodować rzeczywiste "pobieranie".

To, co zrobiłem, to użycie "niewidzialnego" IFRAME i działało we wszystkich 5 przeglądarkach!

Oto, co wymyśliłem: [proszę zauważyć, że w żadnym wypadku nie jestem guru html / javascript i dodałem tylko odpowiedni kod]

HTML (fragment odpowiednich bitów)

<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 (fragment kodu) @Drew stworzył niestandardową akcję o nazwie XmlActionResult, który zmodyfikowałem do swojego celu.

Return XML from a controller ' s action in as an ActionResult?

Moja metoda kontrolera (zwraca ActionResult)

  • przekazuje parametr keys do przechowywanego proc serwera SQL, który generuje XML
  • XML jest następnie przekształcany przez xslt w MS-Excel xml (XmlDocument)
  • Tworzy instancję zmodyfikowanego XmlActionResult i zwraca ją

    Xmlactionresult result = new XmlActionResult (excelXML, " aplikacja / vnd. ms-excel"); string version = DateTime.Teraz.ToString ("dd_mmm_yyy_hhmmsstt"); string fileMask = " LabelExport_{0}.xml";
    wynik.DownloadFilename = string.Format (fileMask, wersja); return result;

Główna modyfikacja klasy xmlactionresult, którą stworzył @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);
}
To było w zasadzie to. Mam nadzieję, że pomoże innym.
 2
Author: sheir,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:06

Prosta opcja, która pozwoli Ci używać strumieni i wszystkiego, co jest return File(stream, "text/xml");.

 1
Author: Casey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-10 20:54:21

Oto prosty sposób na zrobienie tego:

        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");
 0
Author: user2670714,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-02-25 19:22:37

Mała odmiana odpowiedzi od Drew Noakes , która używa metody Save () z 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)
    }
}
 0
Author: Nelson Lopez Centeno,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:32:20

Użyj jednej z tych metod

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

Lub

    public string GetXml()
    {
        string xmlString = "your xml data";
        Response.ContentType = "text/xml";
        return xmlString;
    }
 0
Author: Hamid Jolany,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-05 19:51:12