Dropbox REST API Part 4: Download a File

February 26, 2012

IntroductionDropBox Logo

So far we’ve covered the following topics in the Dropbox series:

Once you are authenticated you can make API requests such as requesting your account information, creating, deleting folders…etc. One particular type of request is downloading a file from your Dropbox account. Once you’ve worked your way through the previous 3 parts this becomes trivially easy.

If you want to follow along go to the download page and download the code for the third part (article #65). Unzip it and open it up in Visual Studio.

Table Of Contents

A New Method

Let’s add a new method to the DropboxApi type called DownloadFile(…).

public FileSystemInfo DownloadFile(string root, string path)
{
    // ...
}

It takes two parameters, namely:

  • root: The root relative to which the path is specified. Valid values are sandbox and dropbox.
  • path: The path to the file you want to download.

It returns an instance of the FileSystemInfo type, which we created earlier in part #3. The FileSystemInfo type contains the file’s metadata.

Example usage of the new method:

var api = new DropboxApi(ConsumerKey, ConsumerSecret, accessToken);
var file = api.DownloadFile("dropbox", "Public/DropboxPart3.zip");
file.Save(@"C:\DropboxPart3.zip");

Top of page

Expanding FileSystemInfo

Before we can proceed we need to modify the existing FileSystemInfo type.

public class FileSystemInfo
{
    //...

    public byte[] Data { get; internal set; }

    public void Save(string path)
    {
        using (var fileStream = new FileStream(
            path, FileMode.Create, FileAccess.ReadWrite))
        {
            fileStream.Write(Data, 0, Data.Length);
        }            
    }
}

The new property Data returns a byte array which contains the contents of the file we downloaded. The Save(…) method allows you to easily save the file. No world shocking news here.

Top of page

Downloading the File

Let’s implement the DownloadFile(…) method. When downloading a file we need to contact the API content server. So let’s add a URL to the DropboxRestApi type.

public class DropboxRestApi
{
    public const string ApiVersion = "1";

    public const string ApiContentServer = 
        "https://api-content.dropbox.com/" + ApiVersion + "/";

    //...
}

Now we can start with implementing the DownloadFile(…) method. First we need to compose a URL for the file which we want to retrieve.

For example:

https://api-content.dropbox.com/1/files?root=dropbox&path=Public/DropboxPart3.zip

var uri = new Uri(new Uri(DropboxRestApi.ApiContentServer),
    String.Format("files?root={0}&path={1}",
    root, UpperCaseUrlEncode(path)));

Remark: We created the UpperCaseUrlEncode(…) method last time to circumvent a rather annoying problem when URL encoding the path.

Next we need to sign the request.

var oauth = new OAuth();
var requestUri = oauth.SignRequest(uri, _consumerKey, _consumerSecret, 
    _accessToken);

Then you can finally execute a GET request to download the file.

var request = (HttpWebRequest) WebRequest.Create(requestUri);
request.Method = WebRequestMethods.Http.Get;
var response = request.GetResponse();

The HTTP response contains the file’s metadata in JSON format within an x-dropbox-metadata header. Let’s extract this metadata from the headers and deserialize it into a FileSystemInfo instance.

var metadata = response.Headers["x-dropbox-metadata"];
var file = ParseJson<FileSystemInfo>(metadata);

Now we can read the response and store the file as a byte array in the FileSystemInfo instance.

using (Stream responseStream = response.GetResponseStream())
using (MemoryStream memoryStream = new MemoryStream())
{
    byte[] buffer = new byte[1024];
    int bytesRead;
    do
    {
        bytesRead = responseStream.Read(buffer, 0, buffer.Length);                    
        memoryStream.Write(buffer, 0, bytesRead);
    } while (bytesRead > 0);

    file.Data = memoryStream.ToArray();
}            

And the only thing that remains is to return our FileSystemInfo instance.

return file;

Voila, that’s the whole implementation of the DownloadFile(…) method.

Thanks to the fact that we did most of the work during the previous parts, this turned out to be a rather short article. Check out the Dropbox REST API documentation if you want to explore it further and implement new features on your own.

https://www.dropbox.com/developers/reference/api

In part 5 I’ll discuss how you can upload new files to your Dropbox account. You can download the source code accompanying this article from the download page. If you have any questions or suggestions please drop me an e-mail or submit a comment.

Top of page

Advertisements

24 Responses to “Dropbox REST API Part 4: Download a File”

  1. cap Says:

    I can’t get this to work, all methods, except for AccountInfo of the Dropbox.Api, crash at this:

    private string GetResponse(Uri uri)
    {
    var oauth = new OAuth();
    var requestUri = oauth.SignRequest(uri, _consumerKey, _consumerSecret, _accessToken);
    var request = (HttpWebRequest) WebRequest.Create(requestUri);
    request.Method = WebRequestMethods.Http.Get;

    var response = request.GetResponse(); // Always crash here

    var reader = new StreamReader(response.GetResponseStream());
    return reader.ReadToEnd();
    }

    What am i doing wrong? My app only have permissions for its folder, I have all tried this:

    var file = api.DownloadFile(“dropbox”, “Apps/MM/Teste.txt”);

    var file = api.DownloadFile(“dropbox”, “/apps/mm/teste.txt”);

    etc…

    thx

    • Christophe Says:

      Which error do you receive? Please paste the request URL (requestUri) in your browser and navigate to it (before you execute the request.GetResponse() line!). Please post the error code and message the Dropbox API gives you.

      • cap Says:

        Error 403, the requestUri returned a file with the text: {“error”: “The provided token does not allow this operation”}

        So, if the i am getting a Bad OAuth request, why can i see the account info, and i can’t donwload a file?

        I will review my login process to see if i can fix this…

        thx

    • Christophe Says:

      Best to checkout the Dropbox forums too. There you’ll find more information regarding this message:

      http://forums.dropbox.com/topic.php?id=29119

      Seems to be related to the access type (full or app folder).

      • cap Says:

        I will try to use the sandbox folder as a root insted…

      • cap Says:

        Great news, for apps with the “app folder” access type we invoke the method as this:

        var file = api.DownloadFile(“sandbox”, “myFile.ext”);

        Looking forward for the next part and the following updates to the api.

  2. Mason Says:

    Ok, I got everything working great. I am able to download the thumbnails from the users app folder and display on a webpage. All works great, except….

    I add a photo from my iphone named
    Photo Feb 29, 6 12 17 PM.jpg

    It uploads fine. I see it in the app folder along with the other 7 images. Now I go to display them on the web page and I get this error when attempting to retrieve the thumbnail for ONLY this file. If I remove this file, it works flawlessly.

    The remote server returned an error: (403) Forbidden.

    If I change the name of the file from Photo Feb 29, 6 12 17 PM.jpg to newfile.jpg it works. So I have isolated the error to the file name. I think it may have something to do with the spaces. Is this a bug in the API? Should the file name matter when downloading a file or thumbnail. The above file name is common for someone taking a photo from their phone. It simply date/time stamps it as the default name. Note, I have tried to url encode the filename, but get the same error.

    Any ideas on how to solve this? It’s kind of killing my entire app. 😦

    Thank You!!

    • Christophe Says:

      Turns out that .NET’s HttpUtility.UrlEncode(…) does not follow the RFC3986:

      http://www.faqs.org/rfcs/rfc3986.html

      One thing that it does differently is to encode spaces as ‘+’ signs instead of using ‘%20’.

      In PHP they have two functions for this urlencode and rawurlencode. I cannot find a substitue for the rawurlencode method in the .NET framework.

      You can easily fix it yourself by replacing the last line of the UpperCaseUrlEncode(…) method by the following:

      return new string(temp).Replace(“+”, “%20”);

      This makes sure the ‘+’ signs (spaces) are correctly encoded. Make sure you test / tweak this quick fix. It works on my machine.

  3. Mason Says:

    Christophe, you’re awesome! That fixed it. Thank you for your quick response and for this great series on .net and the Dropbox API!

  4. Mason Says:

    Perhaps I spoke to soon, the problem is back again. This time I uploaded the same file twice. I noticed dropbox does the same thing if I delete a file and then add it back. Perhaps its a revision number. Something any user could easily do. Dropbox appends (1) to the end. So here is the name

    Photo Feb 29, 6 12 17 PM (1).jpg

    This causes the same issue as before. When I try to download the thumb for this file with the parens, Bam! Why would the (1) cause it to break?

    The remote server returned an error: (403) Forbidden.

    Thank you

    • Christophe Says:

      More problems with HttpUtility.UrlEncode(…). The brackets “(” & “)” are not being encoded.

      ( should become %28
      ) should become %29

      Just replace the last line of the UpperCaseUrlEncode(…) method with this:

      var values = new Dictionary()
      {
      { “+”, “%20” },
      { “(“, “%28” },
      { “)”, “%29” }
      };

      var data = new StringBuilder(new string(temp));
      foreach (string character in values.Keys)
      {
      data.Replace(character, values[character]);
      }
      return data.ToString();

      Now it correctly encodes the spaces and brackets. If any more characters should cause problems you just need to add them to the values dictionary.

      Also take a look at percent encoding:

      http://en.wikipedia.org/wiki/Percent-encoding

  5. Mason Says:

    Thank you!

  6. pkellner Says:

    Thanks for the clear explanations. When I use your download file api call in a multithreaded environment (multiple images coming on from a browser to a image handler), I get 403’s. I’m sure that’s the issue and am wondering if you’ve seen it before or know of a way around it. Could it have something to do with the nounce and sequential processing? I posted on the Dropbox forum also so I’ll see what they said. My workaround is to just lock() the code that does the download. I’m assuming I’ll have the same problem on upload which will make me unhappy also 😦

  7. sajid Says:

    I can’t get this method working
    api.DownloadFile(string root, string path)
    I am working in asp .net MVC 3. All methods are working very fine except that.
    I have made all changes in this method which you have mentioned in above comments but still receiving 403. Kindly help me
    UpperCaseUrlEncode(string s)

    var file = api.DownloadFile(“dropbox”, “Apps/MM/Teste.txt”);

    var file = api.DownloadFile(“dropbox”, “/apps/mm/teste.txt”);
    var file = api.DownloadFile(“sandbox”, “Apps/MM/Teste.txt”);

    var file = api.DownloadFile(“sandbox”, “/apps/mm/teste.txt”);

  8. Anders Frey Says:

    These dropbox pieces and sample code are really great! I’ve had a few problems with the download file though and just want to share my experience to help any future readers who might encounter the same thing:

    When using the downloadfile method I got following URI: https://api-content.dropbox.com/1/files?root=sandbox&path=zipnote.rar?oauth_consumer_key=rdclvufh3syiugp&oauth_token=ds83kijgf8etkwz&oauth_nonce=5502686&oauth_timestamp=1356264383&oauth_signature_method=HMAC-SHA1&oauth_version=1.0&oauth_signature=TS1u%2bgU59zcE52PNCspNcR0TCb4%3d

    That URI returned a 403 error: oath_consumer_key not found.

    After a lot of debugging I found out that the question mark after zipnote.rar was the culprint. When replacing that with and ampersand (&) the URI worked ok and the file was downloaded.

    To replace the ? with an & I modified the OAuth.SignRequest method to replaced the hardcoded ?.

    Once again, thanks for a great blog. It’s been an immense help in getting started with dropbox API.

  9. Anders Frey Says:

    Sorry I forgot to mention that I’m only using the modified SignRequest method for downloading files. For other requests I still use the original method.

  10. loulou Says:

    hi,

    I have a problem when i want to download an mp3 file from dropbox to my filesystem. I have this code (in c#):

    var file = api.DownloadFile(“dropbox”, “music/AZ-theformat.mp3″);
    file.Save(@”C:\Users\Pc\Music”);

    this is my error : System.UnauthorizedAccessException: Access to the path ‘C:\Users\Pc\Music’ is denied.
    In fileSystemInfo, i have this :
    public void Save(string path)
    {
    using (var fileStream = new FileStream(
    path, FileMode.Create, FileAccess.ReadWrite))

    {
    fileStream.Write(Data, 0, Data.Length);

    }
    }

    How can i solve this problem? (problem of permissions ?)

    Thanks.

  11. Mayank Says:

    // Uncomment the following line or manually provide a valid token so that you
    // don’t have to go through the authorization process each time.
    // var accessToken = GetAccessToken();
    var accessToken = new OAuthToken(“token”, “Secret”);

    using the GetAccessToken() function am able to download the file from dropbox. But everytime going to the browser and clicking allow is overhead. Were can i get valid token for the given line.
    var accessToken = new OAuthToken(“token”, “Secret”);

    I request you to please help me with this.


  12. when downloading a file 800 mb i am gettign this error,”Exception of type ‘System.OutOfMemoryException’ was thrown.”

  13. divayp Says:

    when i am downloading a file 800 mb from my dropbox account to my PC i get error, ” Exception of type ‘System.OutOfMemoryException’ was thrown.”

  14. divayp Says:

    when i am downloading a large file ie nearly 800 mb. Igot tehfollowing error,”Received an unexpected EOF or 0 bytes from the transport stream.”

  15. Prasannakumar Says:

    You did a great job. How to get the revisions and restore done?


Comments are closed.

%d bloggers like this: