C# with azure storage getting exception when using DeleteIfExists() - c#

I get an exception when using the method DeleteIfExists from the CloudBlockBlob class.
This is my code:
CloudBlobClient blobClient = this._storageAccount.CreateCloudBlobClient();
directory = directory.ToLower();
string containerDirectory = this.GetContainer(directory);
string relativePathWithoutContainer = this.GetRelativePathWithoutContainer(directory);
CloudBlobContainer container = blobClient.GetContainerReference(containerDirectory);
container.CreateIfNotExist();
container.SetPermissions(new BlobContainerPermissions() { PublicAccess = BlobContainerPublicAccessType.Blob });
foreach (HttpPostedFileBase file in files)
{
CloudBlockBlob blob = container.GetBlockBlobReference(string.Format("{0}/{1}", relativePathWithoutContainer, file.FileName.ToLower()));
blob.DeleteIfExists();
blob.UploadFromStream(file.InputStream,new BlobRequestOptions());
}
return true;
I get the exception at the line:
blob.DeleteIfExists();
The details of the exception are:
Server failed to authenticate the request. Make sure the value of
Authorization header is formed correctly including the signature.

Got an example from here try to add these and see if it works
// Delete the blob if it already exists, also deleting any snapshots.
BlobRequestOptions options = new BlobRequestOptions();
options.DeleteSnapshotsOption = DeleteSnapshotsOption.IncludeSnapshots;
blob.DeleteIfExists(options);

Related

UploadFromByteArrayAsync not saving extension with file name in Azure Blob storage in asp.net core

I am saving a document byte array to azure blob but I discovered that the extension is not saved. After the file is saved the full name of the file is returned with the extension. I expect that when I click on the link the file should open in the browser but instead I got..
<Error>
<Code>ResourceNotFound</Code>
<Message>The specified resource does not exist. RequestId:6012e9b1-901e-011b-57e9-447dc0000000 Time:2022-03-31T10:21:29.3337046Z</Message>
</Error>
public async Task<string> UploadFileToBlobAsync(string strFileName, byte[] fileData, string fileMimeType)
{
var accessKey = _configuration.GetValue<string>("ConnectionStrings:AzureBlob");
CloudStorageAccount csa = CloudStorageAccount.Parse(accessKey);
CloudBlobClient cloudBlobClient = csa.CreateCloudBlobClient();
string containerName = "api-v2-files"; //Name of your Blob Container
CloudBlobContainer cbContainer = cloudBlobClient.GetContainerReference(containerName);
if (await cbContainer.CreateIfNotExistsAsync())
{
await cbContainer.SetPermissionsAsync(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
}
if (strFileName != null && fileData != null)
{
CloudBlockBlob cbb = cbContainer.GetBlockBlobReference(strFileName);
cbb.Properties.ContentType = fileMimeType;
await cbb.UploadFromByteArrayAsync(fileData, 0, fileData.Length);
return cbb.Uri.AbsoluteUri;
}
return "";
}
The issue is with the following line of code:
if (await cbContainer.CreateIfNotExistsAsync())
{
await cbContainer.SetPermissionsAsync(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
}
Basically your code is not going into if block if the container is already exists in your storage account. Because of this, your container's access level is not changed.
Assuming you are using version 11 of the SDK, please use the following override of CreateIfNotExists: CreateIfNotExistsAsync(BlobRequestOptions, OperationContext, CancellationToken).

Renaming a container/folder in azure blob storage

I am trying to rename a container name for users when a condition is met. I made some research and found out that there is no rename function for containers in azure blob storage. But there is a way to accomplish this by copying the files and deleting it after copy. Below is the code I made.
string ContainerName = "old-container-name-user1";
string NewContainerName = "new-container-name-user2"
CloudStorageAccount sourceAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudBlobClient sourceblobClient = sourceAccount.CreateCloudBlobClient();
CloudBlobContainer sourceBlobContainer = sourceblobClient.GetContainerReference(ContainerName);
CloudBlobContainer destBlobContainer = sourceblobClient.GetContainerReference(NewContainerName);
CloudBlockBlob blobOriginal = sourceBlobContainer.GetBlockBlobReference(ContainerName);
CloudBlockBlob blobNew = destBlobContainer.GetBlockBlobReference(NewContainerName);
blobNew.StartCopy(blobOriginal);
blobOriginal.Delete();
When I execute this code I got an error message. Below is the error.
Exception User-Unhandled
Microsoft.WindowsAzure.Storage.StorageException:'The remote server
returned an error: (404) Not Found.'
Inner Exception WebException: The remote server returned an error:
(404) Not Found.
When I also try "blobNew.StartCopyAsync(blobOriginal)" the code just goes through but when I check the containers in azure there is no container created. What do you think the problem is? Any tips on how to improve my code? Delete function does not work also.
UPDATE
I update my code and was able to copy the files from other to container to the new one. Below is the code.
string ContainerName = "old-container-name-user1"
string NewContainerName = "new-container-name-user2"
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(ContainerName);
CloudBlobContainer destcontainer = blobClient.GetContainerReference(NewContainerName);
destcontainer.CreateIfNotExists(BlobContainerPublicAccessType.Blob);
IEnumerable<IListBlobItem> IE = container.ListBlobs(useFlatBlobListing: true);
foreach (IListBlobItem item in IE)
{
CloudBlockBlob blob = (CloudBlockBlob)item;
CloudBlockBlob destBlob = destcontainer.GetBlockBlobReference(blob.Name);
destBlob.StartCopyAsync(new Uri(GetSharedAccessUri(blob.Name, container)));
}
AccessURI Method
private static string GetSharedAccessUri(string blobName, CloudBlobContainer container)
{
DateTime toDateTime = DateTime.Now.AddMinutes(60);
SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessStartTime = null,
SharedAccessExpiryTime = new DateTimeOffset(toDateTime)
};
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
string sas = blob.GetSharedAccessSignature(policy);
return blob.Uri.AbsoluteUri + sas;
}
Now its working but another problem shows up. It says
System.InvalidCastException: 'Unable to cast object of type
'Microsoft.WindowsAzure.Storage.Blob.CloudBlobDirectory' to type
'Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob'.'
But this will be posted in another question. Thanks to our friend Gauriv for pointing out my problem. Check his answer below.
Update 2
By adding useFlatBlobListing: true in IEnumerable<IListBlobItem> IE = container.ListBlobs(blobListingDetails: BlobListingDetails.Metadata); I was able to fix my problem. This line of code was put in my display.
Final Code
IEnumerable<IListBlobItem> IE = container.ListBlobs(blobListingDetails: BlobListingDetails.Metadata, useFlatBlobListing: true);
If you look at your code for creating source and destination blob:
CloudBlockBlob blobOriginal = sourceBlobContainer.GetBlockBlobReference(ContainerName);
CloudBlockBlob blobNew = destBlobContainer.GetBlockBlobReference(NewContainerName);
You'll notice that you're passing the names of the blob container and not the name of the blob. Because you don't have a blob in the container by the name of the container, you're getting 404 error.
To copy a blob container, what you have to do is list all blobs from the source container and then copy them individually in the destination container. Once all the blobs have been copied, you can delete the source container.
If you want, you can use Microsoft's Storage Explorer to achieve "rename container" functionality. It also works by copying blobs from old container to the renamed container and then deletes the old container.
static void RenameContainer()
{
var connectionString = "DefaultEndpointsProtocol=https;AccountName=account-name;AccountKey=account-key";
var storageAccount = CloudStorageAccount.Parse(connectionString);
var client = storageAccount.CreateCloudBlobClient();
var sourceContainer = client.GetContainerReference("source-container");
var targetContainer = client.GetContainerReference("target-container");
targetContainer.CreateIfNotExists();//Create target container
BlobContinuationToken continuationToken = null;
do
{
Console.WriteLine("Listing blobs. Please wait...");
var blobsResult = sourceContainer.ListBlobsSegmented(prefix: "", useFlatBlobListing: true, blobListingDetails: BlobListingDetails.All, maxResults: 1000, currentToken: continuationToken, options: new BlobRequestOptions(), operationContext: new OperationContext());
continuationToken = blobsResult.ContinuationToken;
var items = blobsResult.Results;
foreach (var item in items)
{
var blob = (CloudBlob)item;
var targetBlob = targetContainer.GetBlobReference(blob.Name);
Console.WriteLine(string.Format("Copying \"{0}\" from \"{1}\" blob container to \"{2}\" blob container.", blob.Name, sourceContainer.Name, targetContainer.Name));
targetBlob.StartCopy(blob.Uri);
}
} while (continuationToken != null);
Console.WriteLine("Deleting source blob container. Please wait.");
//sourceContainer.DeleteIfExists();
Console.WriteLine("Rename container operation complete. Press any key to terminate the application.");
}
You can rename containers with Microsoft's "Microsoft Azure Storage Explorer" (after version 0.8.3).
Actual Answer:
Regarding your error message, If the client application receives an HTTP 404 (Not found) message from the server, this means that the object the client was attempting to use does not exist in the storage service. There are several possible reasons for this, such as:
· The client or another process previously deleted the object (Make sure name is correct)
· A Shared Access Signature (SAS) authorization issue
· Client-side code does not have permission to access the object
· Network failure
In order to identify the issue in detail, you can add a try/catch and see the actual error

Copy Azure Append Blob getting a 404

Trying to move a append blob to another container after processing it.
I am first just trying to copy it, then I will delete it (unless there is a actual move function?)
Using C#
I keep getting a 404
: The remote server returned an error: (404) Not Found. ---> System.Net.WebException : The remote server returned an error: (404) Not Found.
at System.Net.HttpWebRequest.GetResponse()
I have tried creating a SasToken at both the container and blob level.
private static void copyBlob(messageClass msgPassed, CloudStorageAccount storageAccount)
{
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer sourceContainer = blobClient.GetContainerReference(receiveScanContainer);
//create a SAS on source blob container with "read" permission. We will append this SAS later
var sasToken = sourceContainer.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow.AddDays(1),
});
CloudBlobContainer targetContainer = blobClient.GetContainerReference(archiveContainer);
CloudAppendBlob sourceBlob = sourceContainer.GetAppendBlobReference(msgPassed.currentName);
var sasToken2 = sourceBlob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow.AddDays(1),
});
CloudAppendBlob targetBlob = targetContainer.GetAppendBlobReference(msgPassed.currentName);
string name = sourceBlob.Uri.Segments.Last();
CloudAppendBlob destBlob = targetContainer.GetAppendBlobReference(name+sasToken2);
targetBlob.StartCopy(destBlob);
}
OK...dug into it more.
The below works.
I also was passing the name of the target container slightly wrong (one letter off) from what the container name actually was.
private static void copyBlob(messageClass msgPassed, CloudStorageAccount storageAccount)
{
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer sourceContainer = blobClient.GetContainerReference(receiveScanContainer);
CloudBlobContainer targetContainer = blobClient.GetContainerReference(archiveContainer);
CloudAppendBlob sourceBlob = sourceContainer.GetAppendBlobReference(msgPassed.currentName);
CloudAppendBlob targetBlob = targetContainer.GetAppendBlobReference(msgPassed.currentName);
targetBlob.StartCopy(sourceBlob);
}

Upload a file to Azure Blob Storage

I want to upload a file to Azure blob storage asynchronously. I have tried the way suggested in the official sdk:
This is how I get the container:
public static class BlobHelper
{
public static CloudBlobContainer GetBlobContainer()
{
// Pull these from config
var blobStorageConnectionString = ConfigurationManager.AppSettings["BlobStorageConnectionString"];
var blobStorageContainerName = ConfigurationManager.AppSettings["BlobStorageContainerName"];
// Create blob client and return reference to the container
var blobStorageAccount = CloudStorageAccount.Parse(blobStorageConnectionString);
var blobClient = blobStorageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(blobStorageContainerName);
container.CreateIfNotExists();
container.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
return container;
}
}
And this is how i try to upload the file:
var documentName = Guid.NewGuid().ToString();
CloudBlobContainer container = BlobHelper.GetBlobContainer();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(documentName);
public class FilesService
{
public async Task<string> UploadFiles(HttpContent httpContent)
{
var documentName = Guid.NewGuid().ToString();
CloudBlobContainer container = BlobHelper.GetBlobContainer();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(documentName);
using (var fileStream = System.IO.File.OpenRead(#"path\myfile"))
{
await blockBlob.UploadFromStreamAsync(fileStream);
}
return blockBlob.Uri.ToString();
}
}
The problem is that I do not know how to get the path to my file (it is uploaded by the user).
When I try this:
var rootpath = HttpContext.Current.Server.MapPath("~/App_Data");
var streamProvider = new MultipartFileStreamProvider(rootpath);
await httpContent.ReadAsMultipartAsync(streamProvider);
foreach (var file in streamProvider.FileData)
{
var localName = file.LocalFileName;
using (var fileStream = System.IO.File.OpenRead(file.LocalFileName))
{
await blockBlob.UploadFromStreamAsync(fileStream);
}
}
And when I try a post request. The request just crashes and does not return anything (even an exception);
Solution:
The issue was resolved in the following way. I used a service method in order to be able to upload a collection of files.
In the BlobHelper class I save the needed information about the container and then instantiate it, it is a static class. Using a collection makes it possible to upload a multiple files as a part of the same stream.
I think you are trying to get the path to the file that is being uploaded to the Blob Storage using standard ASP.NET methods and local context. Files uploaded to the blob will not be accessible that way.
Seems like you upload your blob properly. Now, if your file uploaded successfully, your method should return blockBlob.Uri.ToString(), which is the link to your file - you may store it somewhere in the database or anywhere else.

download from blob when given its uri fails in c#

I'm trying to download a file from Azure blob and save it locally, but it seems to fail.
Here's the relevant code:
var blobClientCode = client.CreateCloudBlobClient();
string codeUri = "https://???.blob.core.windows.net/...../mycode.exe";
using (var codeContent = File.OpenWrite("C:\\code.exe")) {
blobClientCode.GetBlockBlobReference(codeUri).DownloadToStream(codeContent);
}
I get an error in which the container doens't exist. What am I doing wrong?
Try getting a reference to the container first then defining the CloudBlockBlob from this using just the relative path.
This is the code that works for me:
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("myContainerName");
CloudBlockBlob blockBlob = container.GetBlockBlobReference("/subfolder/filename.exe");
using (fileStream == System.IO.File.OpenWrite("C:\code.exe")) {
blockBlob.DownloadToStream(fileStream);
}

Categories

Resources