I have another problem with Azure Blob Storage, this time with downloading. I get a list of files without a problem, unfortunately when I want to download it I get a 404 error that the file was not found.
using System.IO;
using System.Linq;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
namespace BlobStorage
{
class Program
{
static void Main(string[] args)
{
CloudStorageAccount backupStorageAccount = CloudStorageAccount.Parse(
"{connectionString}");
var backupBlobClient = backupStorageAccount.CreateCloudBlobClient();
var backupContainer = backupBlobClient.GetContainerReference("{container-name");
var list = backupContainer.ListBlobs(useFlatBlobListing: true);
foreach (var blob in list)
{
var blobFileName = blob.Uri.Segments.Last();
CloudBlockBlob blockBlob = backupContainer.GetBlockBlobReference(blobFileName);
string destinationPath = string.Format(#"D:\" + blobFileName +".txt");
blockBlob.DownloadToFile(destinationPath, FileMode.OpenOrCreate);
}
}
}
}
Error message:
Microsoft.WindowsAzure.Storage.StorageException: "The remote server
returned an error: (404) Not found."
Internal exception WebException: The remote server returned an error:
(404) Not found.
And points to the line:
blockBlob.DownloadToFile (destinationPath, FileMode.OpenOrCreate);
A file like this most exists in blob storage. When I enter the blob editions, copy the url to a file, I can download it through the browser without any problem. Unfortunately, I can not download it from the application level due to a 404 error.
Only why does such a file exist?
The issue is how you're getting the blob name in the following line of code:
var blobFileName = blob.Uri.Segments.Last();
Considering, the path is tempdata/ExampleIotHub/02/2019/05/14/39, the blob's name is ExampleIotHub/02/2019/05/14/39 (assuming your container name is tempdata) however the blobFileName you're getting is just 39 (please see examples here). Since there is no blob by the name 39, you're getting this 404 error.
I suggest you try by doing something like the following:
foreach (var blob in list)
{
var localFileName = blob.Uri.Segments.Last();
CloudBlockBlob blockBlob = blob as CloudBlockBlob;
if (blockBlob != null)
{
string destinationPath = string.Format(#"D:\" + localFileName +".txt");
blockBlob.DownloadToFile(destinationPath, FileMode.OpenOrCreate);
}
}
Please note that I have not tried running this code so there may be some errors.
Related
The package which I am using is Azure.Storage.Blobs (v12.9.1) and I am trying to delete a blob.
Here is the code I have written (I do not get any errors):
//path - storage url without token
public async Task<bool> DeleteFilefromStorage(string path)
{
try
{
BlobServiceClient blobServiceClient = new BlobServiceClient(Helper.StorageCS);
string containerName = Helper.ContainerName;
Uri uri = new Uri(path);
string filename = Path.GetFileName(uri.LocalPath);
BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(containerName);
var blob = blobContainerClient.GetBlobClient(filename);
return await blob.DeleteIfExistsAsync();
}
catch
{
throw;
}
}
The reason your code is failing is because your blob URL is something like https://mystorage.blob.core.windows.net/mycontainer/files/ba143f66-ba18-478a-85d6-0d661e6894dd.xlsx where the file (ba143f66-ba18-478a-85d6-0d661e6894dd.xlsx) is inside a virtual folder called files.
However when you do string filename = Path.GetFileName(uri.LocalPath);, it will only return ba143f66-ba18-478a-85d6-0d661e6894dd.xlsx and not files/ba143f66-ba18-478a-85d6-0d661e6894dd.xlsx.
Because of this when you try to delete the file, you will get a 404 error. Since DeleteIfExistsAsync method will eat 404 (Not Found) error, you will not get any errors but at the same time the blob will not be deleted as well (because it does not exist).
Here is my code:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using System;
using Microsoft.WindowsAzure;
using System.Net.Http;
namespace Test
{
class Program
{
static void Main(string[] args)
{
//get the storage account from the connection string
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=[account name];AccountKey=[account key];EndpointSuffix=core.windows.net");
//instantiate the client
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
//set the container
CloudBlobContainer container = blobClient.GetContainerReference("images");
//get the blob reference
CloudBlockBlob blockBlob = container.GetBlockBlobReference("myblob.jpg");
//get image from stream and upload
using (var client = new HttpClient())
{
using (var stream = client.GetStreamAsync(some_url).GetAwaiter().GetResult())
{
if (stream != null)
{
blockBlob.UploadFromStreamAsync(stream);
}
}
client.Dispose();
}
}
}
}
The storage account instantiation works fine.
The container referencing works fine (it actually exists).
The block blob referencing works, as well, with no errors.
The stream has the image I am getting from the URL referenced.
Finally, the upload returns no errors.
Except, there is no image when I navigate to the Blob URI.
I get the following error:
The specified blob does not exist. RequestId:7df0aadc-0001-007c-6b90-f95158000000 Time:2017-07-10T15:21:25.2984015Z
I have also uploaded an image via the Azure Portal and that exists and can be navigated to through a browser.
Am I missing something?
Update below line in your code as you're calling async method.
blockBlob.UploadFromStreamAsync(stream).GetAwaiter().GetResult();
This should resolve your problem.
I have an application that upload, download and delete files on Azure blob storage. It works fine but when I perform load testing sometimes I got following exception during file download.
Microsoft.WindowsAzure.Storage.StorageException: The remote server returned an error: (404) Not Found. ---> System.Net.WebException: The remote server returned an error: (404) Not Found.
I am initializing these things once in constructor and then reuse it for all methods:
cloudStorageAccount = CloudStorageAccount.Parse(_storage.ConnectionString);
blobClient = cloudStorageAccount.CreateCloudBlobClient();
container = blobClient.GetContainerReference(_storage.Container);
var permission = container.GetPermissions();
permission.PublicAccess = BlobContainerPublicAccessType.Container;
container.SetPermissions(permission);
Here is my code for blob download:
MemoryStream memoryStream = new MemoryStream();
var retryPolicy = TransientFactory.GetStorageRetryPolicy();
retryPolicy.ExecuteAction(() =>
{
CloudBlockBlob blockBlob = container.GetBlockBlobReference(sourceUri);
if (blockBlob.Exists())
{
blockBlob.DownloadToStream(memoryStream);
memoryStream.Position = 0;
}
});
return memoryStream;
Make sure that the name of the file - which is a part of the URL - has EXACT same casing -
Do not use .ToLower() etc to change the casing.
Atleast this was the issue in my case.
Also check if the file is not uploaded to a sub Folder. In such case you'll need to add the name of this sub Folder in your Blob reference :
CloudBlockBlob blob = container.GetBlockBlobReference("subFolder/"+reference);
If you are using Azure Storage Client Library 4.0 or above, please pass in the blob name instead of a Uri to GetBlockBlobReference. Or if you would like to use a Uri, you should use the CloudBlockBlob constructor instead.
I've been trying to create a Windows Azure Blob containing an image file. I followed these tutorials: http://www.nickharris.net/2012/11/how-to-upload-an-image-to-windows-azure-storage-using-mobile-services/ and http://www.windowsazure.com/en-us/develop/mobile/tutorials/upload-images-to-storage-dotnet/. Finally the following code represents a merging of them. On the last line, however, an exception is raised:
An exception of type 'System.TypeLoadException' occurred in
mscorlib.ni.dll but was not handled in user code
Additional information: A binding for the specified type name was not
found. (Exception from HRESULT: 0x80132005)
Even the container is created the table, but It doesn't work properly.
private async void SendPicture()
{
StorageFile media = await StorageFile.GetFileFromPathAsync("fanny.jpg");
if (media != null)
{
//add todo item to trigger insert operation which returns item.SAS
var todoItem = new Imagem()
{
ContainerName = "mypics",
ResourceName = "Fanny",
ImageUri = "uri"
};
await imagemTable.InsertAsync(todoItem);
//Upload image direct to blob storage using SAS and the Storage Client library for Windows CTP
//Get a stream of the image just taken
using (var fileStream = await media.OpenStreamForReadAsync())
{
//Our credential for the upload is our SAS token
StorageCredentials cred = new StorageCredentials(todoItem.SasQueryString);
var imageUri = new Uri(todoItem.SasQueryString);
// Instantiate a Blob store container based on the info in the returned item.
CloudBlobContainer container = new CloudBlobContainer(
new Uri(string.Format("https://{0}/{1}",
imageUri.Host, todoItem.ContainerName)), cred);
// Upload the new image as a BLOB from the stream.
CloudBlockBlob blobFromSASCredential =
container.GetBlockBlobReference(todoItem.ResourceName);
await blobFromSASCredential.UploadFromStreamAsync(fileStream.AsInputStream());
}
}
}
Please use Assembly Binding Log Viewer to see which load is failing. As also mentioned in the article, the common language runtime's failure to locate an assembly typically shows up as a TypeLoadException in your application.
I am trying to rename blob in azure storage via .net API and it is I am unable to rename a blob file after a day : (
Here is how I am doing it, by creating new blob and copy from old one.
var newBlob = blobContainer.GetBlobReferenceFromServer(filename);
newBlob.StartCopyFromBlob(blob.Uri);
blob.Delete();
There is no new blob on server so I am getting http 404 Not Found exception.
Here is working example that i have found but it is for old .net Storage api.
CloudBlob blob = container.GetBlobReference(sourceBlobName);
CloudBlob newBlob = container.GetBlobReference(destBlobName);
newBlob.UploadByteArray(new byte[] { });
newBlob.CopyFromBlob(blob);
blob.Delete();
Currently I am using 2.0 API. Where I am I making a mistake?
I see that you're using GetBlobReferenceFromServer method to create an instance of new blob object. For this function to work, the blob must be present which will not be the case as you're trying to rename the blob.
What you could do is call GetBlobReferenceFromServer on the old blob, get it's type and then either create an instance of BlockBlob or PageBlob and perform copy operation on that. So your code would be something like:
CloudBlobContainer blobContainer = storageAccount.CreateCloudBlobClient().GetContainerReference("container");
var blob = blobContainer.GetBlobReferenceFromServer("oldblobname");
ICloudBlob newBlob = null;
if (blob is CloudBlockBlob)
{
newBlob = blobContainer.GetBlockBlobReference("newblobname");
}
else
{
newBlob = blobContainer.GetPageBlobReference("newblobname");
}
//Initiate blob copy
newBlob.StartCopyFromBlob(blob.Uri);
//Now wait in the loop for the copy operation to finish
while (true)
{
newBlob.FetchAttributes();
if (newBlob.CopyState.Status != CopyStatus.Pending)
{
break;
}
//Sleep for a second may be
System.Threading.Thread.Sleep(1000);
}
blob.Delete();
The code in OP was almost fine except that an async copy method was called. The simplest code in new API should be:
var oldBlob = cloudBlobClient.GetBlobReferenceFromServer(oldBlobUri);
var newBlob = container.GetBlobReference("newblobname");
newBlog.CopyFromBlob(oldBlob);
oldBlob.Delete();