Upload a file to Azure Blob Storage using WebApi

Written by ppolyzos

Software engineer based in Athens, Greece

51 Comments

  1. Akodo_Shado

    let’s assume that the client sends:
    – the file
    – md5 hash as a parameter.
    What is the best method to check, that saved blob md5 hash is equal with client md5 hash?

    1. ppolyzos

      Any blob file stored in Azure Storage can have Properties and Metadata.
      In blob’s file Properties you can use the ContentMD5, which is the base64-encoded binary MD5 value.

      If you want to have a custom value for validation, you can use blob’s Metadata but you need to have in mind that the total size of the metadata, including both the name and value together, may not exceed 8 KB in size.

      For additional info you can have a look at the following articles:
      https://msdn.microsoft.com/en-us/library/dd179404.aspx
      https://www.simple-talk.com/cloud/platform-as-a-service/azure-blob-storage-part-6-blob-properties,-metadata,-etc/

  2. Mitesh Prajapati

    Can you please provide a solution where I could post the formdata & files on the same request.

    1. save files to blob
    2. read formdata & save it under DB

    Thanks,
    Mitesh

    1. ppolyzos

      You can have a look at gab-demo-athens, a demo project created for Global Azure Bootcamp Athens 2016, where user can upload image files and through Azure Cognitive Services, detect faces on them.

      In FileUploadController I can upload multiple files and then store them to database.

      If you need something more specific, don’t hesitate to ask me.

  3. Ammar Mheir

    What’s good practice for security using Storage Blobs? I have a mobile app that with access RESTful web services provided by the Web API, can i just used my Azure storage access keys within my Web API or is it better to use a SAS key even though the mobile clients aren’t talking directly to the Blob (going through the Web API) (or does it even not work like that? Sorry still learning)

    1. ppolyzos

      Shared access signature (SAS) provides a powerful way to grant limited access to objects in your storage account to other clients, without having to expose your account key.
      If you have private blobs that you want to be accessible only, for example, by certain users, I would suggest you to provide a REST API call, in your web api controller, that will generate the Shared Access Signature to access this blob for limited time, or to apply a certain security policy.
      Storage account credentials (account name and key) should not be available to your mobile app to access storage account directly, but only through your Web API app. Consider the fact that, in case your access keys are compromised, you need to update all your mobile clients to continue accessing your storage account, while in the other case you simply update the credentials to your app and none of your clients is affected.

      I would suggest to have a look at this article
      Create and use shared access signatures on how to access your blobs using SAS and Stored Access Policy.

  4. Matthew

    Great article! Thanks for sharing. In my use case, I had a few extract string values being posted in the form body. If you’re passing in multiple, GetStream() is called for each one. In the case of non-file values, I had to return Stream from the base class. Otherwise, you’ll get an exception that “stream cannot be read” since “blob.OpenWrite()” does not expose the ability to read the stream and prevents you from getting at those FormData[] values.

  5. Danielle

    Hi, can you give me the full path of the Postman request URL and also show me how the authorization is structured in Postman? Thank you.

    1. ppolyzos

      Your server needs to know how to access your storage account container and this info can be provided in UploadController:

      The full path of the Postman URL is shown in the image above.

      As far as securing your API calls, it depends on the approach you have followed. For example, if you have selected to authorize access to your calls using Tokens, then in Postman you need to add a header: Authorization with a value Bearer {AuthToken}

      PS: If I misunderstood your questions don’t hesitate to contact me.

  6. Wim

    Hi

    Thank you for the example works great:)

    The web api works fine through Postman , but for some reason I am struggling to post through Xamarin android.

    Do you have any experience in this?

    Thank you

      1. Wim

        Hi

        Thanks I resolved my problem in the end. Thanks for the linked it helped as well.

        The problem after getting everything to work was the MIME types, but i only removed that and it worked perfectly.

        Thanks a bunch:)

    1. Scott Rudy

      Thank you for the post. I was working on a demo and wanted to move from a local demo to an Azure demo, so wanted to use Azure Strorage. This post was spot on, aside from the mimetypes. The _supportedMimeTypes should start with “image/” not “images/”.

    1. ppolyzos

      The url of a file stored in a Azure Storage container, is in the following format:
      https://{storage_account_name}.blob.core.windows.net/{container}/{filename}

      In this demo:

      • – storage_account_name is ppoldemo
      • – container is images
      • – uploaded image is 0e8f2a66-c860-4362-9bcc-c8b9d8316f93

      So the url will be: https://ppoldemo.blob.core.windows.net/images/0e8f2a66-c860-4362-9bcc-c8b9d8316f93

      In addition, you can view file’s url through Azure Portal. Clicking on a file pops up a sidebar where among other details, gives you file’s URL.
      An other way to view file details, stored in an Azure Storage account is using Microsoft Azure Storage Explorer.

  7. badboby

    Hello, when I try to upload using a rest client I am getting error code 415 Unsupported Media Type. When I use the debugger it’s not even getting past this line: if (!Request.Content.IsMimeMultipartContent(“form-data”)).

    These are my request headers if this helps at all:

    Content-Type: multipart/form-data
    Content-Length: 0

    Is my rest client configured wrong? Or would there be another factor why I’m getting this error

    1. ppolyzos

      Hey there! Are you sure that the file is in a format your server supports? What type is the file you are trying to upload? What REST client do you use? Can you try it using Postman as shown in the image above?

      1. badboby

        I was using advanced rest client but I have just tried it with postman like you suggested. I am still getting error 415 with content-length 0. I have followed your guide for the web api, but how would I allow my server to support the file being uploaded? Should I change something in my web.config?

          1. badboby

            Ah, I was specifically using your example for the azure blob storage as that is what I’m using to store my files, but I will look into what you linked as well. Thank you!

  8. Haris

    Hi,
    When I upload image to Azure, how can I show that picture later on my web app? Can I just load the image url in the page? On my app idea is that the users upload their images. So I need to track which user uploaded which image. I thought to do that with saving the image url in my database with the user’s info. Is that good idea?

    1. ppolyzos

      When you upload an image or any other file in an Azure Storage Blob container this is publicly available, in case blob’s container policy is set to public. That means that, if you have uploaded your file using i.e. “image/jpg”, then using {storage_account_url}/{container}/{file} anyone can access the file.
      If you want to track the uploaded images, you can use a private blob container and generate a SAS (Shared Access signature) whenever an image is requested. You can read more here.
      Saving the image filename (i.e. guid) or filepath in a database is a good idea, as you can easily retrieve it from blob container storage using Azure Storage SDK.

  9. Sam

    I got the upload working fine! Thanks a lot!

    I’m trying to do a resize before uploading and really struggling with it. Any advice for how to go about this?

  10. Taeyo

    Good Article!
    but, i got some error when using your repo.

    Unexpected end of MIME multipart stream. MIME multipart message is not complete.

    i think it’s a kind of bugs in asp.net web api module.
    Do you know how i can fix.

  11. Taeyo

    OK. I got it.
    It seems like a postman problem. I think postman does’t append Line break at the end of mime
    everything is OK with fiddler.

  12. Jayendran

    Excellent Article! Learned a lot.Now I’ve got a clear view about the uploading blobs.
    I’m trying to download a blob with an uploaded URL (which is Retrieved from DB) i.e, https://{storage_account_name}.blob.core.windows.net/{container}/{filename} using Web API calls.
    But I’m not having any idea how it can be implemented in Web API also how can I able test those in POSTMAN?

    Can you please provide some example for downloading which can easily merge with your code?

  13. Cello

    Hi there,

    First of all, great article, It’s more clearer than anything else I find in the internet on this topic.

    Second, I’m trying to follow the steps, and currently up to using postman to test my api, however, no matter what I try, I’m getting a “Api key is invalid” error, I’m not sure where it’s coming from, would you be able to help me?

    Thanks,

    1. ppolyzos

      If I recall correctly Azure Storage API does not respond with “API key is invalid” mesage, even if your call is unauthorized. Are you sure Account name and key are correct? Do you get any error, in UploadFile method, when debugging your request? Can you please share your code to have a look at it, can you upload it in a GitHub repo or a gist snippet?

  14. vinee

    Good Article!
    but, i got some error when using your repo.

    Unexpected end of MIME multipart stream. MIME multipart message is not complete.

    i think it’s a kind of bugs in asp.net web api module.
    Do you know how i can fix. facing the issue with postman and fiddler both

    Reply

  15. Bumbel

    Hi

    Thanks for the code example. Is there a way to find out the size of the file before uploading to azure storage?
    I want to allow up to 20 MB file. I initially thought using the IFormFile but that won’t scale.

    Thanks.

  16. Bumbel

    Thanks for quick reply. Really appreciate your help.
    When I do .length on the file stream i get 0 as length.
    Here is the code i am using.

    var boundary = GetBoundary(Request.ContentType);
    var reader = new MultipartReader(boundary, Request.Body, 80 * 1024);

    var valuesByKey = new Dictionary();
    MultipartSection section;

    while ((section = await reader.ReadNextSectionAsync()) != null)
    {
    var contentDispo = section.GetContentDispositionHeader();

    // reads the file part of the multipart request
    if (contentDispo.IsFileDisposition())
    {
    var fileSection = section.AsFileSection();

    var test = fileSection.FileStream.Length; this returns 0 i am expecting it to return file size.

  17. Bumbel

    Yep position is 0 as well.
    Tried everything can’t get the length of the file via file section. I am now using the content length of the entire request as my file size. The only downside is that this request also include other form fields which contribute to the size of the reqeust. not ideal but does the work. If you do find a way to determine file size please do reply.

    here is what i am using.
    var contentLength = Request.ContentLength;

Leave a Comment

Your email address will not be published. Required fields are marked *