14
votes

I'm trying to create a utility to download file from the internet and upload it again to Azure blob storage. Blob containers already created well; But for some reason i'm getting "Bad Request 400" exception when i tried to upload the file to storage ... Container name is created, small letters, so special characters. But I still do not know why i'm getting the exception!

Please help.

Note:

  • I'm not using any emulator ... Directly testing on the cloud.
  • All of my containers with "Public Container" access option.

Here is the exception:

An exception of type 'Microsoft.WindowsAzure.Storage.StorageException' 
occurred in Microsoft.WindowsAzure.Storage.dll but was not handled in user code
Additional information: The remote server returned an error: (400) Bad Request.

And here is the code:

foreach (var obj in objectsList)
{
     var containerName = obj.id.Replace("\"", "").Replace("_", "").Trim();
     CloudBlobContainer blobContainer = blobClient.GetContainerReference(containerName);

     if (blobContainer.Exists())
     {
         var fileNamesArr = obj.fileNames.Split(new char[] { '#' }, StringSplitOptions.RemoveEmptyEntries);

         foreach (var sora in fileNamesArr)
         {
             int soraInt = int.Parse(sora.Replace("\"", ""));
             String fileName = String.Format("{0}.mp3", soraInt.ToString("000"));

             var url = String.Format("http://{0}/{1}/{2}", obj.hostName.Replace("\"", ""), obj.id.Replace("\"", ""), fileName.Replace("\"", "")).ToLower();

             var tempFileName = "temp.mp3";

             var downloadedFilePath = Path.Combine(Path.GetTempPath(), tempFileName).ToLower();

             var webUtil = new WebUtils(url);
             await webUtil.DownloadAsync(url, downloadedFilePath).ContinueWith(task =>
             {
                 var blobRef = blobContainer.GetBlockBlobReference(fileName.ToLower());
                 blobRef.Properties.ContentType = GetMimeType(downloadedFilePath);

                 using (var fs = new FileStream(downloadedFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
                 {
                     blobRef.UploadFromStream(fs); // <--- Exception
                 }
             });
         }
      }
      else
      {
          throw new Exception(obj.id.Replace("\"", "") + " Container not exist!");
      }
}

Edit: The Storage Exception

Microsoft.WindowsAzure.Storage.StorageException: The remote server returned an error: (400) Bad Request. ---> System.Net.WebException: The remote server returned an error: (400) Bad Request. at System.Net.HttpWebRequest.GetRequestStream(TransportContext& context) at System.Net.HttpWebRequest.GetRequestStream() at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand1 cmd, IRetryPolicy policy, OperationContext operationContext) --- End of inner exception stack trace --- at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand1 cmd, IRetryPolicy policy, OperationContext operationContext) at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromStreamHelper(Stream source, Nullable`1 length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext) at Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob.UploadFromStream(Stream source, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext) at TelawatAzureUtility.StorageService.<>c__DisplayClass4.b__12(Task task) in \psf\Home\Documents\Visual Studio 14\Projects\Telawat Azure Utility\TelawatAzureUtility\StorageService.cs:line 128 Request Information RequestID: RequestDate:Sat, 28 Jun 2014 20:12:14 GMT StatusMessage:Bad Request

Edit 2: Request Information:

enter image description here

enter image description here

Edit 3: The problem comes from WebUtils .. I replaced it with below code and it works! I will add weUtils code, maybe you can help to know what is the problem with it.

HttpClient client = new HttpClient();
var stream = await client.GetStreamAsync(url);

WebUtils Code:

public class WebUtils
{
    private Lazy<IWebProxy> proxy;

    public WebUtils(String url)
    {
        proxy = new Lazy<IWebProxy>(() => string.IsNullOrEmpty(url) ? null : new WebProxy {
            Address = new Uri(url), UseDefaultCredentials = true });
    }

    public IWebProxy Proxy
    {
        get { return proxy.Value; }
    }

    public Task DownloadAsync(string requestUri, string filename)
    {
        if (requestUri == null)
            throw new ArgumentNullException("requestUri is missing!");

        return DownloadAsync(new Uri(requestUri), filename);
    }

    public async Task DownloadAsync(Uri requestUri, string filename)
    {
        if (filename == null)
            throw new ArgumentNullException("filename is missing!");

        if (Proxy != null)
        {
            WebRequest.DefaultWebProxy = Proxy;
        }

        using (var httpClient = new HttpClient())
        {
            using (var request = new HttpRequestMessage(HttpMethod.Get, requestUri))
            {
                using (Stream contentStream = await (await httpClient.SendAsync(request)).Content.ReadAsStreamAsync())
                {
                    using (var stream = new FileStream(filename, FileMode.Create, FileAccess.Write))
                    {
                        contentStream.CopyTo(stream);
                        stream.Flush();
                        stream.Close();
                    }
                    contentStream.Close();
                }
            }
        }
    }
}

Also when I tried this code ... the 'Wait' will never finish or completed!

webUtil.DownloadAsync(url, downloadedFilePath).Wait()
6
Which version of storage client library are you using? Can you trace request/response through Fiddler? That should give you some more details about 400 error.Gaurav Mantri
From Nuget: <package id="WindowsAzure.Storage" version="4.1.0" targetFramework="net45" /> ... I will check with fiddler now.bunjeeb
Other thing you could do is catch the storage exception and look into its properties especially RequestInformation. You'll also find same information as Fiddler there.Gaurav Mantri
You have just dumped the stack trace :) ... Please try to debug your code in Visual Studio and go through the RequestInformation property of your storage exception as mentioned in my previous comment.Gaurav Mantri
StorageException.RequestInformation.ServiceRequestID being null indicates that this response is not coming from Azure Storage service. I agree with Gaurav that a Fiddler trace would help greatly and Fiddler would indeed capture it unless you have filters enabled. Could you please double check Fiddler can capture traffic from other processes on your machine?Serdar Ozler

6 Answers

37
votes

Have you tried creating a container manually on azure portal? It has some limitations on what name you can give containers.

For example: Container name cannot contain upper case letters.

If you request a container with an invalid name, it will result in (400) Bad Request, which you are getting. So check your "containerName" string.

19
votes

I had the same problem. I resolved it by changing the TLS version in the configuration of the storage; the new TLS version (1.2) is not compatible with the older version of the storage client. I changed it to the 1.0 and it works.

The configuration of the storage is in the portal of Azure.

Storage -> Configuration -> TLS Version:

storage configuration in portal

3
votes

I also got this error with the Azure Storage Message Queues.

The Azure Storage Message Queue names must also be all lowercase. ie: "newqueueitem" name in lowercase.

// Retrieve a reference to a queue.
CloudQueue queue = queueClient.GetQueueReference("newqueueitem");

// Create the queue if it doesn't already exist.
queue.CreateIfNotExists();
2
votes

If you create a container with an invalid name, it will result in (400) Bad Request. There are some convention for creating container name as below:

  1. Container names must start with a letter or number, and can contain only letters, numbers, and the dash (-) character.
  2. Every dash (-) character must be immediately preceded and followed by a letter or number; consecutive dashes are not permitted in container names.
  3. All letters in a container name must be lowercase.
  4. Container names must be from 3 through 63 characters long.

Source: https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata

1
votes

I had a very different case of bad request message. Posting here for anyone else who may hit the same. In my case, I was just moving around resource across other resource groups . In that shuffling, a bug in azure allowed me to point my storage to location ("South East Asia") which was not available in my region. So all requests against the storage account returned the bad request message. It took me a while to figure this out because I then created another storage account to test, which when creating, azure did not allow me to pick "South East Asia" as a location of choice, so I picked another location ("East Asia") and then everything worked fine.

0
votes

I faced the same issue while creating the queue in Azure with one UpperCase Letter from my C# code. The error was with the Queue Name. All the characters should be lowercase. After changing all the characters to lowercase it worked! :)

//Retrieve a reference to a queue
CloudQueue queue = queueClient.GetQueueReference("myqueue");
//Create a queue if it alredy doen't exists
queue.CreateIfNotExists();