2015-05-12 7 views
9

Come si ottengono i parametri Content-Disposition restituiti dal controller WebAPI tramite WebClient?Get Parametri disposizione-contenuto

controller WebAPI

[Route("api/mycontroller/GetFile/{fileId}")] 
    public HttpResponseMessage GetFile(int fileId) 
    { 
     try 
     { 
       var file = GetSomeFile(fileId) 

       HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK); 
       response.Content = new StreamContent(new MemoryStream(file)); 
       response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); 
       response.Content.Headers.ContentDisposition.FileName = file.FileOriginalName; 

       /********* Parameter *************/ 
       response.Content.Headers.ContentDisposition.Parameters.Add(new NameValueHeaderValue("MyParameter", "MyValue")); 

       return response; 

     } 
     catch(Exception ex) 
     { 
      return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex); 
     } 

    } 

client

void DownloadFile() 
    { 
     WebClient wc = new WebClient(); 
     wc.DownloadDataCompleted += wc_DownloadDataCompleted; 
     wc.DownloadDataAsync(new Uri("api/mycontroller/GetFile/18")); 
    } 

    void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) 
    { 
     WebClient wc=sender as WebClient; 

     // Try to extract the filename from the Content-Disposition header 
     if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"])) 
     { 
      string fileName = wc.ResponseHeaders["Content-Disposition"].Substring(wc.ResponseHeaders["Content-Disposition"].IndexOf("filename=") + 10).Replace("\"", ""); //FileName ok 

     /****** How do I get "MyParameter"? **********/ 

     } 
     var data = e.Result; //File OK 
    } 

sto tornando un file dal regolatore WebAPI, sto allegando il nome del file nelle intestazioni contenuto della risposta, ma anche mi piacerebbe per restituire un valore adizionale.

Nel client sono in grado di ottenere il nome file, ma come ottengo il parametro adizionale?

risposta

15

Se si lavora con .NET 4.5 o versione successiva, considerare l'utilizzo della classe System.Net.Mime.ContentDisposition:

string cpString = wc.ResponseHeaders["Content-Disposition"]; 
ContentDisposition contentDisposition = new ContentDisposition(cpString); 
string filename = contentDisposition.FileName; 
StringDictionary parameters = contentDisposition.Parameters; 
// You have got parameters now 

Edit:

in caso contrario, è necessario analizzare intestazione Content-Disposition in base ad esso è specification.

Ecco una semplice classe che esegue il parsing, vicino alla specifica:

class ContentDisposition { 
    private static readonly Regex regex = new Regex("^([^;]+);(?:\\s*([^=]+)=(\"[^\"]*\");?)*$", RegexOptions.Compiled); 

    private string fileName; 
    private StringDictionary parameters; 
    private string type; 

    public ContentDisposition(string s) { 
     if (string.IsNullOrEmpty(s)) { 
      throw new ArgumentNullException("s"); 
     } 
     Match match = regex.Match(s); 
     if (!match.Success) { 
      throw new FormatException("input is not a valid content-disposition string."); 
     } 
     var typeGroup = match.Groups[1]; 
     var nameGroup = match.Groups[2]; 
     var valueGroup = match.Groups[3]; 

     int groupCount = match.Groups.Count; 
     int paramCount = nameGroup.Captures.Count; 

     this.type = typeGroup.Value; 
     this.parameters = new StringDictionary(); 

     for (int i = 0; i < paramCount; i++) { 
      string name = nameGroup.Captures[i].Value; 
      string value = valueGroup.Captures[i].Value; 

      if (name.Equals("filename", StringComparison.InvariantCultureIgnoreCase)) { 
       this.fileName = value; 
      } 
      else { 
       this.parameters.Add(name, value); 
      } 
     } 
    } 
    public string FileName { 
     get { 
      return this.fileName; 
     } 
    } 
    public StringDictionary Parameters { 
     get { 
      return this.parameters; 
     } 
    } 
    public string Type { 
     get { 
      return this.type; 
     } 
    } 
} 

Quindi è possibile utilizzare in questo modo:

static void Main() {   
    string text = "attachment; filename=\"fname.ext\"; param1=\"A\"; param2=\"A\";"; 

    var cp = new ContentDisposition(text);  
    Console.WriteLine("FileName:" + cp.FileName);   
    foreach (DictionaryEntry param in cp.Parameters) { 
     Console.WriteLine("{0} = {1}", param.Key, param.Value); 
    }   
} 
// Output: 
// FileName:"fname.ext" 
// param1 = "A" 
// param2 = "A" 

L'unica cosa che dovrebbe essere considerato quando usando questa classe non gestisce i parametri (o il nome del file) senza una doppia citazione.

+0

Grande, lo contrassegnerò come la risposta corretta, hai scritto la lezione da zero? in caso contrario, si prega di indicare la fonte. – Tuco

+0

Sì, ma come ho già detto, potrebbero essere necessari ulteriori miglioramenti, ma spero che risolva il problema. –

1

Il valore è lì ho solo bisogno di estrarlo:

L'intestazione Content-Disposition viene restituita come questo:

Content-Disposition = attachment; filename="C:\team.jpg"; MyParameter=MyValue 

Così ho usato un po 'di manipolazione di stringhe per ottenere i valori:

void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e) 
{ 
    WebClient wc=sender as WebClient; 

    // Try to extract the filename from the Content-Disposition header 
    if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"])) 
    { 
     string[] values = wc.ResponseHeaders["Content-Disposition"].Split(';'); 
     string fileName = values.Single(v => v.Contains("filename")) 
           .Replace("filename=","") 
           .Replace("\"",""); 

     /********** HERE IS THE PARAMETER ********/ 
     string myParameter = values.Single(v => v.Contains("MyParameter")) 
            .Replace("MyParameter=", "") 
            .Replace("\"", ""); 

    } 
    var data = e.Result; //File ok 
} 
+0

Sembra buono, vorrei solo aggiungere un Trim(). Non riesco a utilizzare System.New.Mime.ContentDisposition a causa di errori di analisi in quella classe. –

4

È possibile analizzare fuori la disposizione dei contenuti utilizzando il seguente codice del framework:

var content = "attachment; filename=myfile.csv"; 
var disposition = ContentDispositionHeaderValue.Parse(content); 

Quindi rimuovere i pezzi dall'istanza di disposizione.

disposition.FileName 
disposition.DispositionType 
Problemi correlati