Azure blob storage download to stream returning "" asp.net - c#

I am currently trying to download a file from Azure blob storage using the DownloadToStream method to download the contents of a blob as a text string.
However I am not getting anything back but an empty string.
Here is my code that I use to connect to the azure blob container and retrieve the blob file.
public static string DownLoadFroalaImageAsString(string blobStorageName, string companyID)
{
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference(companyID.ToLower());
//retrieving the actual filename of the blob
string removeString = "BLOB/";
string trimmedString = blobStorageName.Remove(blobStorageName.IndexOf(removeString), removeString.Length);
// Retrieve reference to a blob named "trimmedString"
CloudBlockBlob blockBlob2 = container.GetBlockBlobReference(trimmedString);
string text;
using (var memoryStream = new MemoryStream())
{
blockBlob2.DownloadToStream(memoryStream);
text = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
}
return text;
}
I was following along this documentation however I cannot seem to get it to work. Any help would be greatly appreciated.

However I am not getting anything back but an empty string.
I test your supplied code on my side, it works correctly. I assume that the test blob content is empty in your case. We could trouble shooting with following ways:
1.please have a try to check the Length of memoryStream. If length equal 0 we could know that the blob content is empty.
using (var memoryStream = new MemoryStream())
{
blockBlob2.DownloadToStream(memoryStream);
var length = memoryStream.Length;
text = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
}
2.We could upload a blob with content to container, we could do that with Azure portal or Microsoft Azure storage explorer easily. And please have a try test it with uploaded blob.

If you want to get the text from the blob, you can use DownloadTextAsync()
var text = await blockBlob2.DownloadTextAsync();
If you want to return file stream back to an API respoinse, you can use FileStreamResult which is IActionResult.
var stream = await blockBlob2.OpenReadAsync();
return File(stream, blockBlob2.Properties.ContentType, "name");

Related

Getting error when Dropbox url copy to azure blob storage

I am using the azure blob storage to copy the dropbox file. But when I try to copy that file via URL, got the 500 error and totalbytes are -1.
I am using StartCopy method of WindowsAzure.Storage.Blob package. But here I get the copyStatus.TotalBytes as -1 and copy not working.
Tried the all types of url as below:
https://dl.dropboxusercontent.com/s/1v9re1dozilpdgi/1_32min.mp4?dl=0
https://dl.dropboxusercontent.com/s/1v9re1dozilpdgi/1_32min.mp4?dl=1
https://www.dropbox.com/s/1v9re1dozilpdgi/1_32min.mp4?dl=0
So can you please help me to solve this issue? Anything needs to change in URL or any way to copy the dropbox media to azure blob storage.
Also, I am using the .net 4.8 frameworks with the C#.
Sample Code:
string url = "https://dl.dropboxu`enter code here`sercontent.com/s/1v9re1dozilpdgi/1_32min.mp4?dl=0";
Uri fileUri = new Uri(url);
string filename = "test-file.mp4";
var account = CloudStorageAccount.Parse(connectionstring);
var blobClient = account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("test-container");
var blob = container.GetBlockBlobReference(filename);
blob.DeleteIfExists();
blob.StartCopy(fileUri);
var refBlob = (CloudBlockBlob)container.GetBlobReferenceFromServer(filename);
var fileLength = refBlob.CopyState.TotalBytes ?? 0;
while (refBlob.CopyState.Status == CopyStatus.Pending)
{
refBlob = (CloudBlockBlob)container.GetBlobReferenceFromServer(filename);
var copyStatus = refBlob.CopyState;
}
Error message: 500 InternalServerError "Copy failed."
We need to use CloudBlockBlob instead of using GetBlockBlobReference .
Because the filename, not the URL, is passed to GetBlockBlobReference in its Constructor.
For more information please refer the below
SO THREAD as suggested by #Tobias Tengler
& This BLOG:- Azure – Upload and Download data using C#.NET

Read Parquet file from Azure blob with out downloading it locally c# .net

We have a parquet formatfile (500 mb) which is located in Azure blob.How to read the file directly from blob and save in memory of c# ,say eg:Datatable.
I am able to read parquet file which is physically located in folder using the below code.
public void ReadParqueFile()
{
using (Stream fileStream = System.IO.File.OpenRead("D:/../userdata1.parquet"))
{
using (var parquetReader = new ParquetReader(fileStream))
{
DataField[] dataFields = parquetReader.Schema.GetDataFields();
for (int i = 0; i < parquetReader.RowGroupCount; i++)
{
using (ParquetRowGroupReader groupReader = parquetReader.OpenRowGroupReader(i))
{
DataColumn[] columns = dataFields.Select(groupReader.ReadColumn).ToArray();
DataColumn firstColumn = columns[0];
Array data = firstColumn.Data;
//int[] ids = (int[])data;
}
}
}
}
}
}
(I am able to read csv file directly from blob using sourcestream).Please kindly suggest a fastest method to read the parquet file directly from blob
Per my experience, the solution to directly read the parquet file from blob is first to generate the blob url with sas token and then to get the stream of HttpClient from the url with sas and finally to read the http response stream via ParquetReader.
First, please refer to the sample code below of the section Create a service SAS for a blob of the offical document Create a service SAS for a container or blob with .NET using Azure Blob Storage SDK for .NET Core.
private static string GetBlobSasUri(CloudBlobContainer container, string blobName, string policyName = null)
{
string sasBlobToken;
// Get a reference to a blob within the container.
// Note that the blob may not exist yet, but a SAS can still be created for it.
CloudBlockBlob blob = container.GetBlockBlobReference(blobName);
if (policyName == null)
{
// Create a new access policy and define its constraints.
// Note that the SharedAccessBlobPolicy class is used both to define the parameters of an ad hoc SAS, and
// to construct a shared access policy that is saved to the container's shared access policies.
SharedAccessBlobPolicy adHocSAS = new SharedAccessBlobPolicy()
{
// When the start time for the SAS is omitted, the start time is assumed to be the time when the storage service receives the request.
// Omitting the start time for a SAS that is effective immediately helps to avoid clock skew.
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(24),
Permissions = SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Create
};
// Generate the shared access signature on the blob, setting the constraints directly on the signature.
sasBlobToken = blob.GetSharedAccessSignature(adHocSAS);
Console.WriteLine("SAS for blob (ad hoc): {0}", sasBlobToken);
Console.WriteLine();
}
else
{
// Generate the shared access signature on the blob. In this case, all of the constraints for the
// shared access signature are specified on the container's stored access policy.
sasBlobToken = blob.GetSharedAccessSignature(null, policyName);
Console.WriteLine("SAS for blob (stored access policy): {0}", sasBlobToken);
Console.WriteLine();
}
// Return the URI string for the container, including the SAS token.
return blob.Uri + sasBlobToken;
}
Then to get the http response stream of HttpClient from the url with sas token .
var blobUrlWithSAS = GetBlobSasUri(container, blobName);
var client = new HttpClient();
var stream = await client.GetStreamAsync(blobUrlWithSAS);
Finally to read it via ParquetReader, the code comes from Reading Data of GitHub repo aloneguid/parquet-dotnet.
var options = new ParquetOptions { TreatByteArrayAsString = true };
var reader = new ParquetReader(stream, options);

CloudBlockBlob.UploadFromByteArrayAsync returns, but no image has been created

I have a method to upload my image to Azure blob storage. I have my account already created, and a name and key placed in my app. The behavior I'm seeing is that await UploadFromByteArrayAsync(...) returns and my method returns a URL. However, when I navigate to my azure blob storage in Microsoft Azure Storage Explorer, I can see that no blob has been created. Obviously, navigating to the URL returned by the method returns 404 also. The method has successfully created my container, so there is a definite connection with appropriate perms to my storage account, I have checked the content of the byte array and it contains actual data. Does anyone know why my image is never uploaded?
public async Task<string> UploadImage(byte[] imageByteArr)
{
// Retrieve storage account from the connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=redacted;AccountKey=redacted;EndpointSuffix=core.windows.net");
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve a reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("user-images");
// Create the container if it doesn't already exist.
await container.CreateIfNotExistsAsync().ConfigureAwait(false);
var docId = Guid.NewGuid().ToString();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(docId);
await blockBlob.UploadFromByteArrayAsync(imageByteArr, 0, imageByteArr.Length);
blockBlob.Properties.ContentType = "image/jpg";
await blockBlob.SetPropertiesAsync();
return blockBlob.Uri.ToString();
}
I had missed a step in the creation of the blobs tutorial I was following.
We need to call the following when creating the container in the codebehind so that we have public access to the image uploaded.
container.SetPermissions(
new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });

Download and display a private Azure Blob using ASP MVC

I'm using ASP MVC 5 Razor with Microsoft Azure Blob storage. I can successfully upload documents and images to the Blob Storage using MVC but I am struggling to find some MVC examples how to download and display the files.
It would be quite straightforward to do this if the blobs were stored as public files, but I need them to be private.
Can anyone give me any examples or guidance how to achieve this?
I've got some code below that seems to retrieve the Blob, but I'm not sure what to do with it in MVC to actually display it in a browser.
var fullFileName = "file1.pdf";
var containerName = "default";
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["AttachmentStorageConnection"].ConnectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
// Retrieve reference to a blob ie "picture.jpg".
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fullFileName);
I'm making an assumption based on your comment
It would be quite straightforward to do this if the blobs were stored
as public files, but I need them to be private
that because the blobs are private you are attempting to return a byte array to the client via the mvc controller.
However, an alternate method would be to use a SharedAccessSignature to provide a client temporary access to the blob which you can then access as a public url. The period for which the url is valid can be specified in your controller. This also has the advantage of taking load away from your controller as the client will download the file directly from storage.
// view model
public class MyViewModel
{
string FileUrl {get; set;}
}
// controller
public ActionResult MyControllerAction
{
var readPolicy = new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow + TimeSpan.FromMinutes(5)
};
// Your code ------
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings ["AttachmentStorageConnection"].ConnectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference(containerName);
// Retrieve reference to a blob ie "picture.jpg".
CloudBlockBlob blockBlob = container.GetBlockBlobReference(fullFileName);
//------
var newUri = new Uri(blockBlob.Uri.AbsoluteUri + blockBlob.GetSharedAccessSignature(readPolicy));
var viewModel = new MyViewModel()
{
FileUrl = newUri.ToString()
};
return View("MyViewName", viewModel);
}
Then in your view you can use the view model value
//image
<img src="#Model.FileUrl" />
//in a new tab
`Open in new window`
I hope this answers your questions:
In order to download a file or open it in a new window/tab you need to specify the proper Content-Disposition in the header. There's an example here. Basically if you want to download a blob you execute the following. Keep in mind that if the mime type is set to application/octet-stream, the file will not be opened in a new tab. It will be downloaded. You need to set the correct ContentType when you save the blob in Azure.
//Downloads file
public ActionResult Index(string name)
{
Response.AddHeader("Content-Disposition", "attachment; filename=" + name);
var blob = _azureBlobContainer.DownloadData(); //Code that returns CloudBlockBlob
var memStream = new MemoryStream();
blob.DownloadToStream(memStream);
return File(memStream.ToArray(), blob.Properties.ContentType);
}
//Opens file if correct ContentType is passed
public ActionResult Index(string name)
{
Response.AddHeader("Content-Disposition", "inline; filename=" + name); //Set it as inline instead of attached.
var blob = _azureBlobContainer.DownloadData(); //Code that returns CloudBlockBlob
var memStream = new MemoryStream();
blob.DownloadToStream(memStream);
return File(memStream.ToArray(), blob.Properties.ContentType);
}
To open file in a new tab, make sure you specify the target in the view:
In regards to the blob being public/private, you should handle that in your interaction with Azure Storage. If you want to give users permission to access your blobs from outside your application, you should use a Shared Access Signature. Details here.
Hope this helps.
As an extension Alex S's excellent answer, if you're just adding say a 'Download' button or hyperlink then an alternative approach is to make the MyControllerAction method return a Redirect:
return Redirect(newUri.ToString());
And then in your view make the download link open the response from that controller action in a new window:
Download
That will trigger the download of the file to the user and without triggering navigation to a new page.

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 ?

Categories

Resources