简体   繁体   中英

Get Content-Disposition parameters

How do I get Content-Disposition parameters I returned from WebAPI controller using WebClient?

WebApi Controller

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

I'm returning a file from WebApi controller, I'm attaching the file name in the response content headers, but also I'd like to return an aditional value.

In the client I'm able to get the filename, but how do I get the aditional parameter?

If you are working with .NET 4.5 or later, consider using the System.Net.Mime.ContentDisposition class:

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:

otherwise, you need to parse Content-Disposition header according to it's specification .

Here is a simple class that performs the parsing, close to the specification:

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

    private readonly string fileName;
    private readonly StringDictionary parameters;
    private readonly 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;
        }
    }
} 

Then you can use it in this way:

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"  

The only thing that should be considered when using this class is it does not handle parameters (or filename) without a double quotation.

Edit 2:

It can now handle file names without quotations.

You can parse out the content disposition using the following framework code:

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

Then just take the pieces off of the disposition instance.

disposition.FileName 
disposition.DispositionType

The value is there I just needed to extract it:

The Content-Disposition header is returned like this:

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

So I just used some string manipulation to get the values:

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
}

As @Mehrzad Chehraz said you can use the new ContentDisposition class.

using System.Net.Mime;

// file1 is a HttpResponseMessage
FileName = new ContentDisposition(file1.Content.Headers.ContentDisposition.ToString()).FileName

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM