Filestream a blob from Azure storage - c#

I have images in Azure that I need to add in a pdf using pdfJet.
This is the code that I use if I read an image on disk, however I have a lot of images and it does not make sense to download them from Azure.
Image image = new Image(objects, new BufferedStream(new FileStream(LocalPath + "image.PNG", FileMode.Open, FileAccess.Read)), ImageType.PNG);
PS: This is done in asp.net webforms.
Thank you for your help.
I am now using the following function to read a PDF:
public MemoryStream DownloadToMemoryStream(DTO.BlobUpload b)
{
CloudStorageAccount storageAccount = Conn.SNString(b.OrgID);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference(b.Container);
CloudBlockBlob blob = container.GetBlockBlobReference(b.FileName);
var sasToken = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(10),//assuming the blob can be downloaded in 10 miinutes
}, new SharedAccessBlobHeaders()
{
ContentDisposition = "attachment; filename=file-name"
});
using (MemoryStream ms = new MemoryStream())
{
blob.DownloadToStream(ms);
return ms;
}
}
And in the aspx page I use:
MemoryStream pdfScript = B.DownloadToMemoryStream(b);
to read the stream:
SortedDictionary<Int32, PDFobj> objects = pdfFinalScript.Read(pdfScript);
However I get the error message:
Cannot access a closed Stream
I have looked at how to open the stream but haven't managed to do it.
Could you please help, thank you

According to your description, you would download blobs from Azure.
Here are several ways you could refer to.
1.Download with blob url.
Create a Shared Access Signature with Read permission and Content-Disposition header set and create blob URL based on that and use that URL. In this case, the blob contents will be directly streamed from storage to the client browser.
2.Get the blob and DownloadFileFromBlob.
3.Download file to exactly path in local.
Webform:
You could use Response.Redirect(blobUrl); to redirect blob url and download it.
In .aspx:
<asp:Button ID="Button1" runat="server" Text="Click Me" OnClick="Button1_Click" />
In aspx.cs:
protected void Button1_Click(object sender, EventArgs e)
{
CloudStorageAccount account = new CloudStorageAccount(new StorageCredentials("accountname", "accountkey"), true);
var blobClient = account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("container");
var blob = container.GetBlockBlobReference("text.PNG");
var sasToken = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(10),//assuming the blob can be downloaded in 10 miinutes
}, new SharedAccessBlobHeaders()
{
ContentDisposition = "attachment; filename=file-name"
});
using (MemoryStream ms = new MemoryStream())
{
blob.DownloadToStream(ms);
Image image = new Image(objects, ms, ImageType.PNG);
}
}

Related

Downloading file to browser from Azure Blob Storage using SAS

In my DownloadFile page's Page_Load method, the filename a user wishes to download is retrieved from the query string. The file is hosted in an Azure Blob Storage account. I am attempting to download the file using shared access signatures (SAS) via this approach:
var containerName = "containerName";
var con = "connectionString";
CloudStorageAccount account = CloudStorageAccount.Parse(con);
var blobClient = account.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
var blob = container.GetBlockBlobReference("file.pdf");
var sasToken = blob.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
Permissions = SharedAccessBlobPermissions.Read,
SharedAccessExpiryTime = DateTime.UtcNow.AddMinutes(10),
}, new SharedAccessBlobHeaders()
{
ContentDisposition = "attachment; filename=file.pdf"
});
var blobUrl = string.Format("{0}{1}", blob.Uri.AbsoluteUri, sasToken);
Response.Redirect(blobUrl);
However, this does not download the file. Instead, the browser just shows a garbled character stream of the file:
The blobUrl appears to be valid. But the Response.Redirect isn't working as expected. Am I doing something wrong?
Note: I am using WebForms (unfortunately), not MVC
I was able to figure out a workaround by using an iframe. If I add an iframe to the page:
<iframe id="iframeFile" runat="server" style="display:none;"></iframe>
Then set the source in the codefile:
iframeFile.Src = blobUrl;
It downloads the file.
This may not be ideal, and I'm still not sure why Response.Redirect isn't working as expected. So I'm certainly open to other suggestions as well. But this workaround does resolve the issue of not being able to download the file.

Uploading Base64 Image to Azure Blob

I have the following ASPX markup:
<asp:Image ImageUrl="placeholder.png" runat="server" ID="plhdr" />
The webpage lets a user upload an image, which is processed through a JavaScript library and then set as the source of the above control. The JavaScript sets the source as a Base64 String like this:
data:image/jpeg;base64,/9j/4AAQ...
I have a function on the same page that is meant to upload the displayed image to Azure Storage and then add a reference to it in Azure SQL. The code I have in the code behind is:
StorageCredentials creden = new StorageCredentials(accountname, accesskey);
CloudStorageAccount acc = new CloudStorageAccount(creden, useHttps: true);
CloudBlobClient client = acc.CreateCloudBlobClient();
CloudBlobContainer cont = client.GetContainerReference("testcont");
cont.CreateIfNotExists();
cont.SetPermissions(new BlobContainerPermissions
{
PublicAccess = BlobContainerPublicAccessType.Blob
});
CloudBlockBlob cblob = cont.GetBlockBlobReference("cblob");
var imagesrc = plhdr.ImageUrl;
cblob.UploadFromFile(#imagesrc);
var imageUrl = cblob.Uri;
Server Error in '/' Application. Could not find a part of the path
'D:\Windows\system32\placeholder.png'. Exception Details:
System.IO.DirectoryNotFoundException: Could not find a part of the
path 'D:\Windows\system32\dist\img\fling\space.gif'.
At this line: cblob.UploadFromFile(#imagesrc);.
Hoping someone can point me in the right direction.
According to your description, we can upload the image file to azure storage by using UploadFromStream(stream), Please have a try to do it with following sample code. It works for me.
CloudBlockBlob cblob = cont.GetBlockBlobReference("testblob");
var bytes = Convert.FromBase64String(#"iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==");// without data:image/jpeg;base64 prefix, just base64 string
using (var stream = new MemoryStream(bytes))
{
cblob.UploadFromStream(stream);
}

Upload file into Blob Azure

I'm trying to upload files into blob Azure from an MVC app, I'm following this tutorial, and I'm stuck in this snippet:
using (var fileStream = System.IO.File.OpenRead(#"path\myfile"))
{
blockBlob.UploadFromStream(fileStream);
}
How to make #"path\myfile" dynamic?? How to retrieve the real path of my file to put it in there? I accept any other suggestion too to upload to blob :)
UPDATE
As suggested I added the code inside my View:
#model RiPSShared.Models.RiPSModels.AgencyNote
<h2>PostFile</h2>
<form action="#Url.Action("PostFile", "AgencyNotes", new { NoteId=Model.aut_id})" method = "post" enctype="multipart/form-data">
<label for="file1"> File name:</label>
<input type="file" name="file" id="file1" />
<input type="submit" value="Submit" />
</form>
And the full action controller:
public ActionResult PostFile(HttpPostedFileBase file, int NoteId)
{
CloudBlockBlob blockBlob = container.GetBlockBlobReference(path);
using (Stream fileStream = file.InputStream)
{
blockBlob.UploadFromStream(fileStream);
}
return RedirectToAction("Index");
}
HttpPostedFileBase will have the information you need. Specifically the InputStream property will give you the stream
[HttpPost]
public ActionResult PostFile(HttpPostedFileBase file, int NoteId)
{
// Your existing code for azure blob access
CloudBlockBlob blockBlob = container.GetBlockBlobReference("myblob");
// make sure to a null check on file parameter before accessing the InputStream
using (var s = file.InputStream)
{
blockBlob.UploadFromStream(s);
}
// to do :Return something
}
Also you set your connection string in configuration file and get from that and store file into blob storage first get its container name
//StorageConnectionString string specified in configuration file
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(
CloudConfigurationManager.GetSetting("StorageConnectionString"));
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve a reference to a container.
//specified container name
CloudBlobContainer container = blobClient.GetContainerReference("myBlobcontainer");
// Create the container if it doesn't already exist.
container.CreateIfNotExists();
container.SetPermissions(
new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob });
CloudBlockBlob blockBlob = container.GetBlockBlobReference("myBlob");
// Create or overwrite the "myblob" blob with contents from a local file.
using (var fileStream = file.InputStream)
{
blockBlob.UploadFromStream(fileStream);
}

Displaying images from azure blob container

I have an asp mvc application where I am trying to display images that have been stored in Azure blob storage.
When I return the string the browser just shows as a broken image. When I right click and "inspect" and click the generated URI I recieve the following message
BlobNotFound
The specified blob does not exist. RequestId:f7c32876-0001-013e-539d-dede28000000 Time:2016-07-15T13:30:49.7560775Z
I have downloaded Azure Storage Explorer and can see the file. I have tried to change the access levels on the container to read access for blobs only from no public access (but I thought I did that in code with the line PublicAccess = BlobContainerPublicAccessType.Blob).
How do I display images that are contained in storage?
public string Index()
{
CloudBlockBlob blob = GetBlobInContainer("blobContainerTjsContainer", "PS-ICON-120x120_140.jpg");
return "<img src="+ blob.Uri.AbsoluteUri +" alt='PS Image'>";
}
CloudBlockBlob GetBlobInContainer(string container, string fileName)
{
//use web.config appSetting to get connection setting .NET Framework's ConfigurationManager class can also be used for this
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
//create the blob client
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
//retrieve a refernce to a container
CloudBlobContainer blobContainer = blobClient.GetContainerReference(CloudConfigurationManager.GetSetting(container));
//set permission to show to public
blobContainer.SetPermissions(new BlobContainerPermissions { PublicAccess = BlobContainerPublicAccessType.Blob});
blobContainer.CreateIfNotExists();
// Retrieve reference to a blob named "photo1.jpg".
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(fileName);
return blockBlob;
}
EDIT
After further reading I have changed
// Retrieve reference to a blob named "photo1.jpg".
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(fileName);
return blockBlob;
to
// Retrieve reference to a blob named "photo1.jpg".
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(fileName);
blockBlob.Properties.ContentType = "image/jpg";
blockBlob.SetProperties();
return blockBlob;
this changes returns an exception
Exception Details: System.Net.WebException: The remote server returned an error: (404) Not Found.
Do I need to do something different at the time of uploading?
Edit
#Gaurav Mantri
I can see that it is stored as application/octet-stream but when I tried to change this to image/jpg using
blockBlob.Properties.ContentType = "image/jpg";
blockBlob.SetProperties();
I got a 404 exception at set properties. When I pull the image, while debugging I can see the image name is the same as it was when I uploaded it
at the time of uploading I used the below code
void UploadFile(string filePath)
{
//use web.config appSetting to get connection setting .NET Framework's ConfigurationManager class can also be used for this
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
//create the blob client
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
//retrieve a refernce to a container
CloudBlobContainer blobContainer = blobClient.GetContainerReference(CloudConfigurationManager.GetSetting("blobContainerTjsContainer"));
//create a container if it doesnt exist
blobContainer.CreateIfNotExists();
//gets the reference to the blob that will be written or OVER written
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference("my-image-blob");
using (var fileStream = System.IO.File.OpenRead(filePath))
{
blockBlob.UploadFromStream(fileStream);
}
}
Thanks to the comments from Gaurav I was able to work out my problem.
I was downloading the file as below
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(fileName);
blockBlob.Properties.ContentType = "image/jpg";
blockBlob.SetProperties();
return blockBlob;
But when storing the file I was not setting the content type so it was being saved as application/octet-stream and the above code was trying to convert the type when calling the file. By setting the type prior to uploading I was able to simply call the file and have it displayed as an image e.g.
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference("my-image-blob");
blockBlob.Properties.ContentType = "image/jpg";
using (var fileStream = System.IO.File.OpenRead(filePath))
{
blockBlob.UploadFromStream(fileStream);
}

Image upload to Azure

I created a web app in Azure. This was a simple web app created using microsoft asp .net. I downloaded my azure profile and published to the azure web app using visual studio. There is an image folder in the web app. When I published all the images uploaded like a charm. Then I used a WPF smartclient app using a web client object and set its Credentials to network credentials along with the user id and the password of my azure account. But when the line reaches the webclient.upload kind of method, I am getting a 401 unauthorized exception. It looks to me that when I try to upload my credentails are not taken as correct. If it were IIS, I know what to do. But in AZURE I am not sure how I can give an anonymous user and access to upload the image. Any comments or points to be considered here?
If your images are not a static part of your application but instead they can be created from your application (example user uploading his picture) I would recommend using Azure Storage instead of file system (you wont loose images uploaded by your users after you do next deploy).
Azure Storage can be easily managed both from code as well as using GUI management tools like CloudBerry Explorer.
adding name space
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
2.Adding class
public class blobservice
{
public CloudBlobContainer GetCloudBlobContainer()
{
string connString = "DefaultEndpointsProtocol=https;AccountName="";AccountKey=E"";";
string destContainer = "mysample";
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connString);
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer blobContainer = blobClient.GetContainerReference(destContainer);
if (blobContainer.CreateIfNotExists())
{
blobContainer.SetPermissions(new BlobContainerPermissions
{
PublicAccess = BlobContainerPublicAccessType.Blob
});
}
return blobContainer;
}
}
3..aspx.cs
blobservice _blobServices = new blobservice();
protected void Page_Load(object sender, EventArgs e)
{
blobservice _blobServices = new blobservice();
Upload();
}
public void Upload()
{
CloudBlobContainer blobContainer = _blobServices.GetCloudBlobContainer();
CloudBlockBlob blob = blobContainer.GetBlockBlobReference("Sampleblob.jpg");
WebClient wc = new WebClient();
byte[] bytes = wc.DownloadData(Server.MapPath("~/Images/active.png"));
using (Stream ms = new MemoryStream(bytes))
{
blob.UploadFromStream(ms);
}
}
protected void btnDelete_Click(object sender, EventArgs e)
{
string Name = "https://bikeimages.blob.core.windows.net/mysample/Sampleblob.jpg";
Uri uri = new Uri(Name);
string filename = System.IO.Path.GetFileName(uri.LocalPath);
blobservice _blobServices = new blobservice();
CloudBlobContainer blobContainer = _blobServices.GetCloudBlobContainer();
CloudBlockBlob blob = blobContainer.GetBlockBlobReference(filename);
blob.Delete();
}

Categories