2012-09-07 5 views
11

Ich habe erfolgreich einen Csv Media Type Formatter in meinem ASP.Net Web API Projekt implementiert. Ich bin in der Lage, Ergebnisse im Csv-Format zurück zu bekommen. Der resultierende Dateiname ist jedoch "Teile" ohne eine Erweiterung.Asp.net Web API - Wie man den Dateinamen für einen benutzerdefinierten CSV Media Type Formatter einstellt

Im Idealfall möchte ich in der Lage sein, diesen Dateinamen im Controller zu setzen, aber die Erweiterung global hinzufügen zu können, wäre ein Minimum.

Im Folgenden sind die Beispiele, die ich

Aufschalten OnGetResponseHeaders gefunden haben - ich sehe das nicht als Option in der aktuellen Version. http://forums.asp.net/t/1782973.aspx/1?Setting+response+and+content+headers+esp+ContentDisposition+inside+a+MediaTypeFormatter

Nach diesem Artikel sollte diese Arbeit

public override IEnumerable<KeyValuePair<string, string>> OnGetResponseHeaders(Type objectType, string mediaType, HttpResponseMessage responseMessage) 
{ 
     return new[] { new KeyValuePair<string, string>("Content-Disposition", "attachment; filename=testing.csv") }; 
} 

jedoch Visual Studio sagt: „Es gibt keine geeignete Methode zur Überschreibung ist“ und wird nicht kompiliert, wenn ich das auf meinen eigenen CSV-Formatter hinzufügen.

Rückgabe HttpMessageResponse von Controller - How to set downloading file name in ASP.NET Web API Allerdings scheint dies nur bestehende Server-Dateien schieben, die die Csv-Serialisierung aus dem Mix nehmen würde. Im Folgenden ist ein Versuch, diesen Ansatz funktioniert:

public HttpResponseMessage Get(string id) 
{ 
    var response = new HttpResponseMessage(); 

    if (id == "test") 
    { 
     var data = GetTestData(); 
     response.StatusCode = HttpStatusCode.OK; 
     response.Content = new StreamContent(data); 
     response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
     response.Content.Headers.ContentDisposition.FileName = "testorama.csv"; 
     return response; 
    } 

    return null; 
} 

Das hier Problem ist, dass neuer StreamContent() einen Strom erwartet - ist es eine Möglichkeit, den aktuellen Stream zu erhalten, die eigene CSV-Formatter erstellt?

Bottom line, wie kann ich den Dateinamen für ein Resultset, das zuerst in Csv-Format serialisiert ist, festlegen?

Lösung

Dank Claudio -, die ich in der richtigen Richtung bekamen. Ein paar Änderungen von dem, was Sie auf dem Laufenden:

  1. Ich war von BufferedMediaTypeFormatter für meine Gewohnheit Csv Formatter Ableiten und SetDefaultContentHeaders verwenden musste ich stattdessen von MediaTypeFormatter abzuleiten.

  2. SetDefaultContentHeaders akzeptiert den Parameter mediaType mit dem Typ MediaTypeHeaderValue und nicht string.

Hier ist der endgültige Code:

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) 
{ 
    base.SetDefaultContentHeaders(type, headers, mediaType); 
    headers.Add("Content-Disposition", "attachment; filename=testorama.csv"); 
} 
+0

Warum mussten Sie "MediaTypeFormatter" anstelle von "BufferedMediaTypeFormatter" erben, ich denke beide sollten funktionieren. –

+0

@Tomas, Sieht aus, als ob Sie Recht haben - SetDefaultContentHeaders ist auch mit BufferedMediaTypeFormatter verfügbar. –

Antwort

14

Aufschalten der Methode SetDefaultContentHeaders auf MediaTypeFormatter

public override void SetDefaultContentHeaders(
    Type type, HttpContentHeaders headers, string mediaType) 
{ 
    base.SetDefaultContentHeaders(type, headers, mediaType); 
    headers.Add("Content-Disposition", "attachment; filename=yourname.csv"); 
} 
+0

Als die Lösung markiert, aber sehen Sie meinen ursprünglichen Beitrag für ein paar Änderungen, die ich gemacht habe. –

+1

Kennen Sie eine Möglichkeit, auf das Objekt zuzugreifen, das Sie zurückgeben möchten? Das heißt, ich habe ein Objekt und möchte den Dateinamen auf diesem Objekt basieren. In 'SetDefaultContentHeaders' habe ich keinen Zugriff auf das Objekt, das ich zurückgebe. –

+0

@TomasJansson: Ich bin mir nicht sicher über die Ausführungsreihenfolge und kann es jetzt nicht testen, aber wenn 'WriteToStream' vor' SetDefaultContentHeaders' ausgeführt wird, können Sie das Objekt auf 'WriteToStream' einer Eigenschaft zuweisen Greifen Sie später auf das Objekt zu. –

7

Um einen benutzerdefinierten Namen auf die Daten (zumindest in Webbasierte bereitzustellen API 2), möchten Sie GetPerRequestFormatterInstance überschreiben. Von dort können Sie auf die HttpRequestMessage zugreifen.

private string FileName { get; set; } 

public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) 
{ 
    base.SetDefaultContentHeaders(type, headers, mediaType); 
    if (!string.IsNullOrEmpty(FileName)) 
     headers.Add("Content-Disposition", string.Format("attachment; filename={0}", FileName)); 
} 

public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType) 
{ 
    // We aren't setting the name, so just return the current instance. 
    if (!request.Properties.ContainsKey("filename")) return this; 

    var formatter = new CsvFormatter(); 
    var fileName = request.Properties["filename"] as string; 
    formatter.FileName = string.Format("{0}.csv", fileName); 
    return formatter; 
} 

Dann können Sie in Ihrer Controller-Aktion den Dateinamen so einstellen ...

Ich verwende {ext}, wenn ich zusätzliche Formatierer hinzufüge, die einen Dateinamen benötigen. Theoretisch sollte nur die Erweiterung geändert werden, um die anderen Formate zu unterstützen.

+1

+1 für die GetPerRequestFormatterInstcance und Anfrage Eigenschaft Trick. In meiner Implementierung muss ich jedoch keine Instanz des Formatierungsprogramms neu erstellen, wenn der Dateiname beeinflusst wird: Ich setze einfach die Eigenschaft und gebe "this" zurück: 'if (! request.Properties.ContainsKey (" OutputFilename "))) zurückgeben; this.FileName = request.Properties ["OutputFilename"] als Zeichenfolge; return this; ' – odalet

+0

Erstellt Web.API eine Instanz des Formatierers für jede Anforderung oder verwendet sie eine einzelne Instanz? Da die Lösung möglicherweise Probleme mit Nebenläufigkeit hat ... –

+0

Die Eigenschaft FileName befindet sich in der Anforderungsinstanz. Dies ist ein anderes Objekt als das zum Erstellen dieser Instanz verwendete Objekt. Solange Sie dem Code folgen und die FileName-Eigenschaft der Anforderungsinstanz festlegen, sollte alles in Ordnung sein. – Brian

Verwandte Themen