2012-09-07 5 views
11

Ho implementato correttamente un formattatore di tipi di supporti Csv nel mio progetto API Web ASP.Net. Sono in grado di ottenere risultati in formato CSV. Tuttavia il nome file risultante è "parti" senza un'estensione.Asp.net Web API - Come impostare il nome file per un formattatore di tipi di supporti CSV personalizzato

Idealmente, voglio essere in grado di impostare questo nome di file nel controller, ma essere in grado di aggiungere l'estensione globalmente sarebbe un minimo.

Qui di seguito sono gli esempi che ho trovato

OnGetResponseHeaders Override - non vedo che come opzione nella versione attuale. http://forums.asp.net/t/1782973.aspx/1?Setting+response+and+content+headers+esp+ContentDisposition+inside+a+MediaTypeFormatter

Secondo tale articolo questo dovrebbe funzionare

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

Tuttavia Visual Studio dice: "Non esiste un metodo adatto per override" e non verrà compilato quando aggiungo che, per mia abitudine Csv Formatter.

Restituisci HttpMessageResponse dal controller - How to set downloading file name in ASP.NET Web API Tuttavia sembra che stia semplicemente spingendo i file del server esistenti, il che toglierebbe la serializzazione Csv dal mix. Di seguito è un tentativo di fare questo lavoro approccio:

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

Il problema qui è che il nuovo StreamContent() si aspetta un flusso - c'è un modo per ottenere il flusso di corrente che su misura Csv Formatter creato?

In conclusione, come posso impostare il nome file per un set di risultati che viene prima serializzato in formato Csv?

Soluzione

Grazie Claudio - che mi ha fatto andare nella giusta direzione. Un paio di modifiche da quello che hai postato:

  1. ero derivanti da BufferedMediaTypeFormatter per mia abitudine Csv Formatter e di utilizzare SetDefaultContentHeaders ho dovuto invece derivano dalla MediaTypeFormatter.

  2. SetDefaultContentHeaders accetta il parametro mediaType con un tipo di MediaTypeHeaderValue e non una stringa.

Ecco il codice finale:

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

Perché è necessario ereditare 'MediaTypeFormatter' anziché il' BufferedMediaTypeFormatter', penso che entrambi dovrebbero funzionare. –

+0

@Tomas, Sembra che tu abbia ragione - SetDefaultContentHeaders è disponibile anche con BufferedMediaTypeFormatter. –

risposta

14

override del metodo SetDefaultContentHeaders sul 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

Contrassegnato come la soluzione, ma vedere il mio post originale per un paio di modifiche che ho apportato. –

+1

Conosci un modo per accedere all'oggetto che vuoi restituire? Cioè, ho un oggetto e voglio basare il nome del file su quell'oggetto. In 'SetDefaultContentHeaders' non ho accesso all'oggetto che sto restituendo. –

+0

@TomasJansson: Non sono sicuro dell'ordine di esecuzione e non posso testarlo ora, ma se 'WriteToStream' viene eseguito prima di' SetDefaultContentHeaders' potresti essere in grado di assegnare l'oggetto su 'WriteToStream' a una proprietà in modo che tu possa accedere all'oggetto più tardi. –

7

Al fine di fornire un nome personalizzato sulla base dei dati (almeno in Web API 2), si vorrà sovrascrivere GetPerRequestFormatterInstance. Da lì puoi accedere a HttpRequestMessage.

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

Quindi, nell'azione del controller, è possibile impostare il nome file come ...

if (!Request.Properties.ContainsKey("filename")) 
    Request.Properties.Add("filename", "MyFile.{ext}"); 

Io uso {ext} nel caso in cui aggiungo altri formattatori che richiedono un nome file. In teoria, solo l'estensione dovrebbe essere modificata per supportare gli altri formati.

+1

+1 per GetPerRequestFormatterInstcance e richiesta trucco delle proprietà. tuttavia, nella mia implementazione, non è necessario ricreare un'istanza del formattatore quando si influisce sul nome del file: ho semplicemente impostato la proprietà, quindi restituisco "this": 'if (! request.Properties.ContainsKey (" OutputFilename "))) restituisce questo; this.FileName = request.Properties ["OutputFilename"] come stringa; restituisce questo; ' – odalet

+0

Web.API crea un'istanza del formatore per ogni richiesta o riutilizza una singola istanza? Perché la tua soluzione potrebbe affrontare alcuni problemi di concorrenza ... –

+0

La proprietà FileName si trova nell'istanza richiesta. Questo è un oggetto diverso da quello usato per creare quell'istanza. Finché si segue il codice e si imposta la proprietà FileName dell'istanza di richiesta, si dovrebbe andare bene. – Brian

Problemi correlati