Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 981
The One Avatar asked May 12 '15 14:05

The One


People also ask

What is content disposition in HTTP?

In a regular HTTP response, the Content-Disposition response header is a header indicating if the content is expected to be displayed inline in the browser, that is, as a Web page or as part of a Web page, or as an attachment, that is downloaded and saved locally.

What is content disposition in Java?

The MIME Content-disposition header provides presentation information for the body-part. It is often added to attachments specifying whether the attachment body part should be displayed (inline) or presented as a file name to be copied (attachment).

What is content type and content disposition?

Content-Disposition takes one of two values, `inline' and `attachment'. 'Inline' indicates that the entity should be immediately displayed to the user, whereas `attachment' means that the user should take additional action to view the entity.

What is content disposition S3?

S3 provides multiple ways to set the Content-Disposition header of an object being downloaded, two of the main ways are: Set Content Disposition parameter on upload – works for new objects. Set response-content-disposition parameter in request – works for an existing object however requires a signed URL.


3 Answers

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.

like image 98
Mehrzad Chehraz Avatar answered Oct 06 '22 18:10

Mehrzad Chehraz


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
like image 41
The Senator Avatar answered Oct 06 '22 20:10

The Senator


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
}
like image 38
The One Avatar answered Oct 06 '22 19:10

The One