HowTo: Excel Export mit ASP.NET MVC und "Render View To String"

imageMan kann relativ einfach auf seiner Seite einen Excel-Export bei tabellarischen Daten anbieten ohne großartige SDKs zu wälzen. Excel versteht von Haus aus auch HTML Tabellen. Man ist zwar eingeschränkt, aber es ist schnell gemacht. Bei einer ASP.NET MVC Anwendung wäre es nun noch schön, dass man das Markup der HTML Tabelle als View speichert. Über eine kleine Extension kann man sich den View auch als String ausgeben lassen.

Unser Ziel: Excel Export

Wir möchten auf unserer Webseite einen Excelexport anbieten. Etwas ähnliches, nur etwas kurioser gemacht, habe ich auch schonmal auf dem Blog geschrieben.

Was muss man dafür tun?

Im Grunde reicht es aus, wenn man in die Response eine HTML Tabelle rendert und als Contenttype “application/ms-excel” angibt. Wir möchten aber die Tabelle als View speichern um Sie einfacher editieren zu können und nicht hardcoded im Source Code zu pflegen.

RenderViewToString

Wir benötigen zu aller erst eine Komponente die einen View als String uns zurückgibt. Wichtig dabei ist, dass die Response während des Vorgangs nicht schon zum Client geschickt wird (Response.Flush()), da man ansonsten den Contenttyp nicht mehr ändern kann! Eine der Lösungen in diesem Thread hat auch funktioniert – in ASP.NET MVC 2.0 muss man allerdings eine kleine Sache ändern -> Siehe Stackoverflow.

/// <summary>Renders a view to string.</summary>
public static string RenderViewToString(this Controller controller,
                                        string viewName, object viewData) {
    //Create memory writer
    var sb = new StringBuilder();
    var memWriter = new StringWriter(sb);

    //Create fake http context to render the view
    var fakeResponse = new HttpResponse(memWriter);
    var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
    var fakeControllerContext = new ControllerContext(
        new HttpContextWrapper(fakeContext),
        controller.ControllerContext.RouteData,
        controller.ControllerContext.Controller);

    var oldContext = HttpContext.Current;
    HttpContext.Current = fakeContext;

    //Use HtmlHelper to render partial view to fake context
    var html = new HtmlHelper(new ViewContext(fakeControllerContext,
        new FakeView(), new ViewDataDictionary(), new TempDataDictionary()),
        new ViewPage());
    html.RenderPartial(viewName, viewData);

    //Restore context
    HttpContext.Current = oldContext;    

    //Flush memory and return output
    memWriter.Flush();
    return sb.ToString();
}

/// <summary>Fake IView implementation used to instantiate an HtmlHelper.</summary>
public class FakeView : IView {
    #region IView Members

    public void Render(ViewContext viewContext, System.IO.TextWriter writer) {
        throw new NotImplementedException();
    }

    #endregion
}

Nun können wir über diese Methode einen String aus einem View erzeugen – schonmal nicht schlecht.

Jetzt kann man entweder direkt das ContentResult nutzen oder man baut sich sein eigens ExcelResult:

public class ExcelResult : ActionResult
    {
        public string FileName { get; set; }
        public string Content { get; set; }

        public ExcelResult(string filename, string content)
        {
            this.FileName = filename;
            this.Content = content;
        }

        public override void ExecuteResult(ControllerContext context)
        {
            WriteFile(this.FileName, "application/ms-excel", this.Content);
        }

        private static void WriteFile(string fileName, string contentType, string content)
        {

            HttpContext context = HttpContext.Current;
            context.Response.Clear();
            context.Response.AddHeader("content-disposition", "attachment;filename=" + fileName);
            context.Response.Charset = "";
            context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
            context.Response.ContentType = contentType;
            context.Response.Write(content);
            context.Response.End();
        }
    }

Die Anwendung

Folgender View ist unser Exceltemplate (mit einem ViewModel)

%@ Import Namespace="MvcRenderToString.Models"%>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IList<ExcelData>>" %>

<table>
    <tr>
        <% foreach(ExcelData excel in Model) {%>
        <td><%=excel.Foobar %></td>
        <% } %>
    </tr>
</table>

Und der Controller:

        public ExcelResult Excel()
        {
            List<ExcelData> foobars = new List<ExcelData>();
            foobars.Add(new ExcelData() { Foobar = "HelloWorld!"});
            foobars.Add(new ExcelData() { Foobar = "HelloWorld!" });
            foobars.Add(new ExcelData() { Foobar = "HelloWorld!" });
            foobars.Add(new ExcelData() { Foobar = "HelloWorld!" });

            string content = this.RenderViewToString("Excel", foobars);
            return new ExcelResult("Foobar.xls", content);
        }

Das Ergebnis:

image

Einziges Manko ist, dass Excel dem nicht ganz vertraut. Leider ist das ByDesign so:

image

Bei Bestätigung auf “Ja”:

image

Fetzt, oder?

Weitere Anwendungsmöglichkeiten

Dadurch das wir eine HTML Tabelle benutzen, können wir die Tabelle auch genauso auf unserer normalen Webseite benutzen. Hierbei Rufe ich dann einfach RenderPartial etc. auf.

Man könnte so auch Email Templates als View ablegen. Die Möglichkeiten sind jedenfalls da :)

[ Download Democode ]


Kick It auf dotnet-kicks.de
Wenn dir der Blogpost gefallen hat, dann hinterlasse doch einen Kommentar. Wenn du auf dem Laufenden bleiben willst, abonniere unseren RSS Feed oder folge uns auf Twitter.

About the author

Written by Robert Mühsig

Robert Mühsig (@robert0muehsig) ist Webentwickler und beschäftigt sich mit Web-Frameworks (vor allem dem ASP.NET MVC Framework) und scheut sich auch nicht vor Javascript. Ansonsten bloggt er über all jene Probleme, die ihm über den Weg laufen. Seit 2008 ist er Microsoft MVP für ASP.NET und er arbeitet bei der T-Systems Multimedia Solutions GmbH in Dresden. Treffen kann man ihn online via Twitter (@robert0muehsig) oder dieser Seite oder bei der .NET User Group Dresden.

4 Responses

  1. Im IE kann es zu Problemen mit dem Excelresult kommen. Wenn man direkt per GET auf die URL des Controllers geht mag der IE das File nicht runterladen.

    Lösung des Problems: Diese Zeile entfernen:
    context.Response.Cache.SetCacheability(HttpCacheability.NoCache);

    Reply
  2. YOu don’t understand POO of ASP MVC,

    public class ExcelResult : ActionResult
    {
    public ViewResult _result { get; set; }

    public ExcelResult(ViewResult result)
    {
    _result = result;
    }

    public override void ExecuteResult(ControllerContext context)
    {
    context.HttpContext.Response.AppendHeader(“content-disposition”, “attachment;filename=export.xls”);
    context.HttpContext.Response.ContentType = “application/ms-excel”;
    context.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    _result.ExecuteResult(context);
    }
    }

    Reply
  3. Thanks for the config httpReponse ;)

    Reply

Comment on this post

Letzte Posts

  • Carriage Return / Neue Zeile in Textareas

    Eine kleine Aufgabe: Jede neue Textzeile (Carriage Return/Wenn man Enter drückt ) in einer Textarea soll ein Element in einer Auflistung sein – wie mach ich das jetzt am einfachsten? Eigentlich ein grundlegendes Element im Web und der Nutzer macht bewusst Absätze – daher wäre es nur gerecht, wenn man das auch entsprechend würdigt. Kleine ...

  • image.png
    Doom, Quake, Wolfenstein & co. Source Code auf GitHub

    id Software, die Macher von Doom, Quake, Wolfenstein & co., stellen regelmäßig ihre älteren Spieltitle als Open Source zur Verfügung. Das Ganze runterzuladen fand ich bisher immer recht mühselig, allerdings gibt es seit kurzer Zeit die Sourcen auch auf GitHub. Darunter Spiele wie Doom 3, Quake 3, Wolfenstein für iOS. Wer also schon immer mal ...

  • image.png
    Twitter Bootstrap 2.0 released & “Release Präsentation”

    Wie bereits vom Twitter Bootstrap Team angekündigt wurde offiziel die Version 2.0 des UI Toolskits “Twitter Bootstrap” veröffentlich. Zudem wurden die Slides, welche bei der Release Party gezeigt wurden auch veröffentlicht: Downloads finden sich auf der Twitter Bootstrap Seite auf GitHub. Wenn dir der Blogpost gefallen hat, dann hinterlasse doch einen Kommentar. Wenn du auf ...

  • image.png
    Javascript zu Dart Translator

    Dart, Google Javascript Alternative, wurde vor ein paar Monaten vorgestellt und die Webentwickler Szene ist noch etwas gespalten, ob Dart nun überflüssig ist oder einfach nur cool und längst überfällig ist. Um die Sprache näher zu erläutern hat Google die grundlegenden Javascript Basics nach Dart übersetzt. Das Ergebnis ist der “Translator”. Der Name mag momentan ...

  • Twitter Bootstrap 2.0–“Beta”

    Twitter Bootstrap, ein UI-Toolkit für Web-Applikationen von Twitter, erscheint (wie bereits berichtet) demnächst in der Version 2.0. Der offizielle Release ist am 31. Januar, allerdings beginnt jetzt laut Mark Otto (einer der Hauptentwickler von Twitter Bootstrap) die intensive Test-Phase. Das heisst, das es nun offiziel auch die 2.0 Dokumentation online gibt. Im Vergleich zur aktuellen ...

Support us!

Facebook