Upload a file to Azure Blob Storage - c#

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.

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).

How to correctly server a file from Azure Storage using a dotnet core controller?

I have a controller in my dotnet core web application to fetch a resource from a Azure storage account in Azure and offer it to the user for download. The user can't directly access the Azure storage account, so my webapp works as a proxy and authenticates the user before service the file.
My doubt is if my implementation if efficient with large files? My concern is that DownloadToStreamAsync() actually fetches the entire file in the memory of the webapp before serving it.
public async Task<IActionResult> Serve(string path)
{
MemoryStream streamIn = null;
CloudFile file = null;
Stream fileStream = null;
var filename = Path.GetFileName(path);
// application-level permission checks checks
// fetching file from Azure Storage
try {
var storageConnectionString = _azureOptions.AzureStorageAccountConnectionString;
var storageAccount = CloudStorageAccount.Parse(storageConnectionString);
var fileClient = storageAccount.CreateCloudFileClient();
var share = fileClient.GetShareReference(_azureOptions.AzureStorageAccountContentShareName);
var root = share.GetRootDirectoryReference();
file = root.GetFileReference(path);
if (!await file.ExistsAsync())
{
return NotFound();
}
streamIn = new MemoryStream();
await file.DownloadToStreamAsync(streamIn);
fileStream = await file.OpenReadAsync();
} catch (StorageException e) {
_logger.LogError($"Error while retrieving content resource: {path}", e);
return NotFound();
}
return File(fileStream, _getContentType(filename));
}
You are right to have this concern because your code is downloading the entire blob to memory before uploading it to the client. This is very inefficient.
Furthermore, you are not even using the MemoryStream where you download the file. Just delete this code:
streamIn = new MemoryStream();
await file.DownloadToStreamAsync(streamIn);
The rest of the code should stream the file from Azure and stream it to the client in parallel.

How to download the file from online azure blob storage

When I tried to download the image file from the online azure blob, it throws exception as "The given path's format is not supported". My code block is below:
StorageCredentials creds = new StorageCredentials(accountName, accountKey);
CloudStorageAccount account = new CloudStorageAccount(creds, useHttps: true);
CloudBlobClient client = account.CreateCloudBlobClient();
container = client.GetContainerReference(blobName);
CloudBlockBlob blockBlob = container.GetBlockBlobReference(MyPath);
await blockBlob.DownloadToFileAsync(Path, FileMode.OpenOrCreate);
using (var fileStream = System.IO.File.Create(Path))
{
await blockBlob.DownloadToStreamAsync(fileStream);
}
If I provide the local path as "c:\users\Joy\Downloads" in path,as like below:
var localPath = #"C:\Users\Joy \Downloads\user.jpg" ;
await blockBlob.DownloadToFileAsync(localPath, FileMode.OpenOrCreate);
using (var fileStream = System.IO.File.Create(localPath))
{
await blockBlob.DownloadToStreamAsync(fileStream);
}
It can be copied into corresponding location. But I couldn't download the file in my custom location.
According to your description, I enabled public read access to my blobs to check this issue. I created a console application and you could refer to the following code snippet for downloading the file and maintain the virtual directory in your local file system as follows:
CloudBlockBlob blockBlob = new CloudBlockBlob(new Uri("https://brucchstorage.blob.core.windows.net/images/2017/11/28/lake.jpeg"));
var localPath = Path.Combine(/*your custom root folder for storing file(s)*/AppDomain.CurrentDomain.BaseDirectory,$"downloads\\{blockBlob.Name}"); //blockBlob.Name =2017/11/28/lake.jpeg
var rootDir = new FileInfo(localPath).Directory;
if (!rootDir.Exists) //make sure the parent directory exists
rootDir.Create();
await blockBlob.DownloadToFileAsync(localPath,FileMode.Create);
//OR
using (var fs = new FileStream(localPath, FileMode.Create))
{
await blockBlob.DownloadToStreamAsync(fs);
}
Result:
Moreover, you could construct the CloudBlockBlob instance with the Uri contains the SAS token as follows:
https://brucchstorage.blob.core.windows.net/images/2017/11/28/lake.jpeg?st=2017-11-28T06%3A28%3A00Z&se=2017-11-29T06%3A28%3A00Z&sp=r&sv=2015-12-11&sr=b&sig=15NAaRB43C%2BniIZZe8gAvFl7LY%2BS6K7DNyjLflpvgBg%3D
More details, you could follow here.

How to create Web Service for uploading image to Azure Storage Blob?

I'm trying to upload an image that I get from my Android device as a ByteArray
to my Azure Storage Blob. By using a webservice in asp.net.
But I can't figure out how to do this...
Here is my code so far:
[WebMethod]
public string UploadFile(byte[] f, string fileName)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve a reference to a container.
CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");
// Create the container if it doesn't already exist.
container.CreateIfNotExists();
container.SetPermissions(
new BlobContainerPermissions
{
PublicAccess = BlobContainerPublicAccessType.Blob
});
// Retrieve reference to a blob named "filename...".
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
// Create or overwrite the "filename..." blob with contents from a local file.
using (var fileStream = System.IO.File.OpenRead("C:\\filepath"))
{
blockBlob.UploadFromStream(fileStream);
}
return "OK";
}
This code gets the image from a local file path on my computer, and thats not what I want.
I want to use the byte[] array 'f' wich I recive from my Android device instead of 'C:\filepath'
How can I do that ?

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

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);

Categories

Resources