I have to download some txt files which are in a Azure container allowing anonymous access. I am working with Visual Studio 2017 and the program is a Windows Form application.
This is my code (where myUri is the string containing the Uri and myContainer the one for the Container):
BlobServiceClient blobServiceClient = new BlobServiceClient(new Uri(myUri));
BlobContainerClient container = blobServiceClient.GetBlobContainerClient(myContainer);
Azure.Pageable<BlobItem> blobs = container.GetBlobs(BlobTraits.All,BlobStates.All);
foreach (BlobItem blob in blobs)
{
BlobClient bc = container.GetBlobClient(blob.Name);
bc.DownloadTo(new FileStream(path + blob.Name, FileMode.Create));
}
I can see the files in my local path with the correct names, the problem is that if I try to open the .txt(s) with a common editor such as Notepad++ I see encoded chars instead of normal ASCII.
Where is the problem? Can anyone help me?
(too long for comment)
While I am not able to see any issue in your code that would cause encoding issue, you may try the below to download your blob. Here I am using BlobDownloadInfo class to get an idea of the content type of what is being downloaded and it's Content.CopyTo method to write to the stream.
Azure.Pageable<BlobItem> blobs = container.GetBlobs(BlobTraits.All, BlobStates.All);
foreach (BlobItem blob in blobs)
{
BlobClient blobClient = container.GetBlobClient(blob.Name);
BlobDownloadInfo download = blobClient.Download();
Console.WriteLine("Content Type " + download.ContentType);
using (FileStream downloadFileStream = File.OpenWrite(Path.Combine(#"YourPath", blob.Name)))
{
download.Content.CopyTo(downloadFileStream);
downloadFileStream.Close();
}
}
Related
I have a question, is it possible to change the target framework for a C# project using Razor Pages from .Net 4.8 to 6.0?
In my project I want to copy files from the local disk to Azure Cloud BlobStorage and currently I can only do it with framework 6.0 or higher. I can't do the switch to the framework from 4.8 to 6.0 because it is not offered to me in this project. What can I do?
I hope that I am not the only one with this problem. Does anyone have any ideas to solve my problem?
Many greetings and thanks in advance
Code sample, this will work only with .Net 6.0 or higher
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
//Set <storage-account-name> to actual storage account name
var blobServiceClient = new BlobServiceClient("DefaultEndpointsProtocol=https;" +
"AccountName=.....;AccountKey=.....;EndpointSuffix=core.windows.net");
//Create a name for the container
string containerName = "myFiles";
//Create the container and return a container client object
BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);
//Create a local file in the directory for uploading and downloading
string localPath = "c:\\DATA";
Directory.CreateDirectory(localPath);
string fileName = "myFile" + ".txt";
string localFilePath = Path.Combine(localPath, fileName);
//Write text to the file
await File.WriteAllTextAsync(localFilePath, "Hello, World!");
//Get a reference to a blob
BlobClient blobClient = containerClient.GetBlobClient(fileName);
Console.WriteLine("Uploading to Blob storage as blob:\n\t {0}\n", blobClient.Uri);
//Upload data from the local file
await blobClient.UploadAsync(localFilePath, true);
Console.WriteLine("Listing blobs...");
//List all blobs in the container
await foreach (BlobItem blobItem in containerClient.GetBlobsAsync())
{
Console.WriteLine("\t" + blobItem.Name);
}
//Download the blob to a local file and append the string "DOWNLOADED" for compare
string downloadFilePath = localFilePath.Replace(".txt", "DOWNLOADED.txt");
Console.WriteLine("\nDownloading blob to\n\t{0}\n", downloadFilePath);
//Download the blob's contents and save it to a file
await blobClient.DownloadToAsync(downloadFilePath);
Console.WriteLine("Done");
I have a zip file(.Exe - Self-extracting zip file) that can be extracted using 7zip. As I want to automate the extraction process, I used the below C# code. It is working for the normal 7z files. But facing this issue 'Cannot access the closed Stream', when I trying to extract the specific self-extracting (.Exe) zip file. Fyi. Manually I ensured the 7zip command line version is unzipping the file.
using (SevenZipExtractor extract = new SevenZipExtractor(zipFileMemoryStream))
{
foreach (ArchiveFileInfo archiveFileInfo in extract.ArchiveFileData)
{
if (!archiveFileInfo.IsDirectory)
{
using (var memory = new MemoryStream())
{
string shortFileName = Path.GetFileName(archiveFileInfo.FileName);
extract.ExtractFile(archiveFileInfo.Index, memory);
byte[] content = memory.ToArray();
file = new MemoryStream(content);
}
}
}
}
The zip file is in Azure blob storage. I dont know how to get the extracted files in the blob storage.
Here is one of the workarounds that has worked for me. Instead of 7Zip I have used ZipArchive.
ZipArchive archive = new ZipArchive(myBlob);
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(destinationStorage);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(destinationContainer);
foreach(ZipArchiveEntry entry in archive.Entries) {
log.LogInformation($"Now processing {entry.FullName}");
string valideName = Regex.Replace(entry.Name, # "[^a-zA-Z0-9\-]", "-").ToLower();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(valideName);
using(var fileStream = entry.Open()) {
await blockBlob.UploadFromStreamAsync(fileStream);
}
}
REFERENCE:
How to Unzip Automatically your Files with Azure Function v2
I am trying to load a JSON string (serialized with Newtonsoft.Json) without creating a temporary file.
I am serializing object in runtime using JsonConvert.SerializeObject(obj,settings) which returns a string.
Following Microsoft documentation I could do as it's illustrated below:
// Create a local file in the ./data/ directory for uploading and downloading
string localPath = "./data/";
string fileName = "quickstart" + Guid.NewGuid().ToString() + ".txt";
string localFilePath = Path.Combine(localPath, fileName);
// Write text to the file
await File.WriteAllTextAsync(localFilePath, "Hello, World!");
// Get a reference to a blob
BlobClient blobClient = containerClient.GetBlobClient(fileName);
Console.WriteLine("Uploading to Blob storage as blob:\n\t {0}\n", blobClient.Uri);
// Open the file and upload its data
using FileStream uploadFileStream = File.OpenRead(localFilePath);
await blobClient.UploadAsync(uploadFileStream, true);
uploadFileStream.Close();
Although it works, I would have to create temporary file for each uploaded JSON file.
I tried this:
BlobServiceClient blobServiceClient = new BlobServiceClient("SECRET");
BlobContainerClient container = BlobServiceClient.GetBlobContainerClient("CONTAINER_NAME");
container.CreateIfNotExistsAsync().Wait();
container.SetAccessPolicy(Azure.Storage.Blobs.Models.PublicAccessType.Blob);
CloudBlockBlob cloudBlockBlob = new CloudBlockBlob(container.Uri);
var jsonToUplaod = JsonConvert.SerializeObject(persons, settings);
cloudBlockBlob.UploadTextAsync(jsonToUpload).Wait();
But, well...it doesn't have right to work as I am not specifing any actual file in the given container (I don't know where to do it).
Is there any way to upload a blob directly to a given container?
Thank You in advance.
The BlobClient class wants a Stream, so you can create a MemoryStream from your JSON string.
Try something like this:
BlobClient blob = container.GetBlobClient("YourBlobName");
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonToUpload)))
{
await blob.UploadAsync(ms);
}
I want to download files from Azure using C# then stream those into MemoryStream after that return/display to the user in Front-end with a link (Azure URI - which goes to the Azure blob) and the user will be able to see those PDF files in the browser or download them. There are multiple blobs/files in Azure so, I want to loop through each file and download to stream for example: using a foreach.
I'm not sure how can I reference those blobs CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName); as here I could give a name of the specific file but I've multiple files so not sure what to go here "fileName".
Code:
var files = container.ListBlobs();
foreach (var file in files)
{
using (var memoryStream = new MemoryStream())
{
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fileName);
blockBlob.DownloadToStream(memoryStream);
}
}
I'm not sure if I'm looping correcting right now in the code and downloading every blob?
Also, I tried replacing fileName with file.Uri.Segments.Last() -
I guess which gets the name of blobs.
The problem I'm having is that this foreach is just getting me one PDF file whenever I try to use the links in front-end. So, I need to know how can I properly loop through each file and download them?
So, I need to know how can I properly loop through each file and download them?
We can't download the mutiple files from the memory directly. If zip file is acceptable, you could use a compressed file such as a zip file to transfer multiple files instead. The following is my demo code, it works correctly on my side.
using (var ms = new MemoryStream())
{
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var file in files)
{
if (file.GetType() != typeof(CloudBlockBlob)) continue;
var blob = (CloudBlockBlob) file;
var entry = zipArchive.CreateEntry(blob.Name, CompressionLevel.Fastest);
using (var entryStream = entry.Open())
{
CloudBlockBlob blockBlob = container.GetBlockBlobReference(blob.Name);
blockBlob.DownloadToStream(entryStream);
}
}
}
}
Herein lies my problem, the working path to the file I am trying to load into a string variable, when copied from Azure Explorer works fine.
Working: https://container.blob.core.windows.net/files/emailtemplates/EmailMaster.html
When I try to do it via code:
[TestMethod]
public void TestMethod3()
{
string templateHtml;
var blob = AzureStorageMethods.GetAzureBlob(AzureFileFolder + "EmailMaster.html");
using (var memoryStream = new MemoryStream())
{
blob.DownloadToStream(memoryStream);
templateHtml = Encoding.UTF8.GetString(memoryStream.ToArray());
}
Assert.AreNotEqual(0, templateHtml.Length);
}
Here is the code for GetAzureBlob:
public static CloudBlockBlob GetAzureBlob(string filename)
{
var creds = ConfigurationManager.AppSettings["azurestorageconn"];
var storageAccount = CloudStorageAccount.Parse(creds);
var client = storageAccount.CreateCloudBlobClient();
//create a blob container and make it publicly accessibile
var sampleContainer = client.GetContainerReference(ConfigurationManager.AppSettings["azurecontainer"]);
sampleContainer.CreateIfNotExists();
sampleContainer.SetPermissions(new BlobContainerPermissions()
{
PublicAccess = BlobContainerPublicAccessType.Blob
});
var blob = sampleContainer.GetBlockBlobReference(#"files\" + filename);
return blob;
}
It fails to Download the stream because the endpoint path is wrong.
It comes back as
Not Working: https://container.blob.core.windows.net/container/files/emailtemplates/EmailMaster.html
Note that my method to return a blob, has the container as part of the url, whereas the path from azure explorer does not.
I can't see any way to solve this. I've tried accessing the files container directly but I'm either doing it wrong or it isn't doable.
The directory tree (even though there technically isn't one in Azure) is mystorageaccountname/files/emailtemplates/filename. Any solutions appreciated.
Please change this line of code:
var blob = sampleContainer.GetBlockBlobReference(#"files\" + filename);
to
var blob = sampleContainer.GetBlockBlobReference(filename);
Based on your note:
The directory tree (even though there technically isn't one in Azure)
is mystorageaccountname/files/emailtemplates/filename.
It is my understanding that the name of your container is files. When you use container.GetBlockBlobReference construct, you don't need to specify the container name again in the name parameter. It will be taken care of by the library.