Consider the following code:
// _blobContainerClient is an instance of BlobContainerClient
await _blobContainerClient.UploadBlobAsync(uniqueName, stream);
string uri = < how to get the URI? >
How do I get the URI of the uploaded blob?
I am using Azure.Storage.Blobs 12.8.0.
You just need to create a client and return the Uri this,
var blob = new BlobClient(connectionString, containerName, fileName);
await blob.UploadAsync(fileStream, o);
return ReturnUri(blob.Uri);
If you want to do more things with the blob object, I would recommend creating a new BlobClient. If you just need the URI this should work as well:
var blobUri = $"{_blobContainerClient.Uri.AbsoluteUri}/{uniqueName}";
Related
I upload attachments to an Azure Blob storage. I also create a SAS-Token when uploading; I retrieve the unique URL, send it to the browser where it is opened immediatly.
When I do this I often (but not always) retrieve a 404 that this resource does not exist. When refreshing the page just a few seconds later it is retrieved correctly.
So it seems that I am "too fast" after uploading the attachment. Is there a way to wait until Azure is ready to serve the attachment? I would have expected awaiting the call would be sufficient to achieve this.
public async void UploadFile(string filename, byte[] filecontent)
{
var containerClient = _blobServiceclient.GetBlobContainerClient("attachments");
var blobClient = containerClient.GetBlobClient(filename);
using (var stream = new MemoryStream(filecontent))
{
await blobClient.UploadAsync(stream, new BlobHttpHeaders { ContentType = GetContentTypeByFilename(filename) });
}
}
public async Task<string> GetLinkForFile(string filename)
{
var containerClient = _blobServiceclient.GetBlobContainerClient("attachments");
var sasBuilder = new BlobSasBuilder()
{
BlobContainerName = containerName,
BlobName = filename,
Resource = "b",
StartsOn = DateTime.UtcNow.AddMinutes(-1),
ExpiresOn = DateTime.UtcNow.AddMinutes(5),
};
// Specify read permissions
sasBuilder.SetPermissions(BlobSasPermissions.Read);
var credentials = new StorageSharedKeyCredential(_blobServiceclient.AccountName, _accountKey);
var sasToken = sasBuilder.ToSasQueryParameters(credentials);
// Construct the full URI, including the SAS token.
UriBuilder fullUri = new UriBuilder()
{
Scheme = "https",
Host = string.Format("{0}.blob.core.windows.net", _blobServiceclient.AccountName),
Path = string.Format("{0}/{1}", containerName, filename),
Query = sasToken.ToString()
};
return fullUri.ToString();
}
public async Task<Document> GetInvoice(byte[] invoiceContent, string invoiceFilename)
{
string filePath = await GetLinkForFile(invoiceFilename);
UploadFile(invoiceFilename, file);
return new Document()
{
Url = filePath
};
}
The method GetInvoice is called by REST and the response (containing the URL) returned to the browser where it is opened.
If you notice, you're not waiting for the upload operation to finish here:
_azureStorageRepository.UploadFile(invoiceFilename, file);
Please change this to:
await _azureStorageRepository.UploadFile(invoiceFilename, file);
And you should not see the 404 error. Azure Blob Storage is strongly consistent.
Also, change the UploadFile method from public async void UploadFile to public async Task UploadFile as mentioned by #Fildor in the comments.
Problem
I am trying to generate Pdf and create MemoryStream object and trying to upload that stream to azure Blob Storage. I am already tried the below code so far but the blob is not uploaded to azure and also what is the name of that blob which I upload using stream method of azure sdk
Code
var memoryStream = new MemoryStream(byteArray, 0, byteArray.Length);
var cred = new StorageCredentials("foo", "key");
var account = new CloudStorageAccount(cred, true);
var client = account.CreateCloudBlobClient();
var container = client.GetContainerReference("container");
CloudBlockBlob sourceBlob = container.GetBlockBlobReference("foo/bar");
var attachment = sourceBlob.UploadFromStreamAsync(memoryStream);
As #Kirk has said, use await sourceBlob.UploadFromStreamAsync(memoryStream); instead of var attachment = sourceBlob.UploadFromStreamAsync(memoryStream); Or your code will exit before upload is finished.
Note that your method should change to public async Task methodname(), you will see related tip shown by VS.
Some references for you
Async and Await
How and when to use async and-await
And see container.GetBlockBlobReference("blobname"); the string you use to get blob reference is the name of blob uploaded.
I am writing a service that uploads / downloads files to and from Azure blob storage. I have the upload part working fine. I've been reading how to download the files and there seems to be several ways of doing it.
I've managed to download the file as a stream which works fine but I read somewhere that it's possible to simply pass the absolute URI of the file and get the browser to download the file.
I'm not sure how to do this. Do I send the URI to the request output stream? Any advice or examples of doing this appreciated. I'm using C# but we have other clients usng this service (such as Angular).
You need to create endpoint (GET) to obtain public URL as described in Azure Docs and either:
Return it to client who then can invoke GET on returned URI
Return HTTP REDIRECT response with redirection to Blob's public Url
Third option, if you just need client to have this file is to pass streams, so create endpoint returning stream, read Blob to memory stream, and return memorystream to client. Then you don't need to mess with authentication and anonymous access.
Downloading the source file:
public static Stream DownloadFile(string blobName)
{
CloudBlobContainer container = GetContainer();
CloudBlob blob = container.GetBlobReference(blobName);
MemoryStream memoryStream = new MemoryStream();
blob.DownloadToStream(memoryStream);
memoryStream.Position = 0;
return memoryStream;
}
Setting up and returning container:
private static CloudBlobContainer GetContainer()
{
string accountName = "***";
string accountKey = "***";
string endpoint = $"https://{accountName}.blob.core.windows.net/";
string containerName = "***";
StorageCredentials storageCredentials = new StorageCredentials(accountName, accountKey);
CloudStorageAccount cloudStorageAccount = new CloudStorageAccount(
storageCredentials, new Uri(endpoint), null, null, null);
CloudBlobClient cloudBlobClient = cloudStorageAccount.CreateCloudBlobClient();
CloudBlobContainer container = cloudBlobClient.GetContainerReference(containerName);
container.CreateIfNotExists();
return container;
}
I have an Azure blob container for storing images. I also have a suite of ASP.NET Web API methods for adding / deleting / listing the blobs in this container. This all works if I upload the images as files. But I now want to upload the images as a stream and am getting an error.
public async Task<HttpResponseMessage> AddImageStream(Stream filestream, string filename)
{
try
{
if (string.IsNullOrEmpty(filename))
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest));
}
BlobStorageService service = new BlobStorageService();
await service.UploadFileStream(filestream, filename, "image/png");
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
catch (Exception ex)
{
base.LogException(ex);
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.BadRequest));
}
The code for adding a new image to the blob container as a stream looks like this.
public async Task UploadFileStream(Stream filestream, string filename, string contentType)
{
CloudBlockBlob blockBlobImage = this._container.GetBlockBlobReference(filename);
blockBlobImage.Properties.ContentType = contentType;
blockBlobImage.Metadata.Add("DateCreated", DateTime.UtcNow.ToLongDateString());
blockBlobImage.Metadata.Add("TimeCreated", DateTime.UtcNow.ToLongTimeString());
await blockBlobImage.UploadFromStreamAsync(filestream);
}
And finally here's my unit test that is failing.
[TestMethod]
public async Task DeployedImageStreamTests()
{
string blobname = Guid.NewGuid().ToString();
//Arrange
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes($"This is a blob called {blobname}."))
{
Position = 0
};
string url = $"http://mywebapi/api/imagesstream?filestream={stream}&filename={blobname}";
Console.WriteLine($"DeployedImagesTests URL {url}");
HttpContent content = new StringContent(blobname, Encoding.UTF8, "application/json");
var response = await ImagesControllerPostDeploymentTests.PostData(url, content);
//Assert
Assert.IsNotNull(response);
Assert.IsTrue(response.IsSuccessStatusCode); //fails here!!
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
The error I am getting is Value cannot be null.
Parameter name: source
Is this the correct way to upload an image stream to Azure blob storage using Web API? I have it working with image files without a problem, and only getting this problem now that I'm trying to upload using streams.
Is this the correct way to upload an image stream to Azure blob storage using Web API? I have it working with image files without a problem, and only getting this problem now that I'm trying to upload using streams.
According to your description and error message, I found you send your stream data in your url to the web api.
According to this article:
Web API uses the following rules to bind parameters:
If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the .NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string. (More about type converters later.)
For complex types, Web API tries to read the value from the message body, using a media-type formatter.
In my opinion, the stream is a complex types, so I suggest you could post it as body to the web api.
Besides, I suggest you could crate a file class and use Newtonsoft.Json to convert it as json as message's content.
More details, you could refer to below codes.
File class:
public class file
{
//Since JsonConvert.SerializeObject couldn't serialize the stream object I used byte[] instead
public byte[] str { get; set; }
public string filename { get; set; }
public string contentType { get; set; }
}
Web Api:
[Route("api/serious/updtTM")]
[HttpPost]
public void updtTM([FromBody]file imagefile)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("aaaaa");
var client = storageAccount.CreateCloudBlobClient();
var container = client.GetContainerReference("images");
CloudBlockBlob blockBlobImage = container.GetBlockBlobReference(imagefile.filename);
blockBlobImage.Properties.ContentType = imagefile.contentType;
blockBlobImage.Metadata.Add("DateCreated", DateTime.UtcNow.ToLongDateString());
blockBlobImage.Metadata.Add("TimeCreated", DateTime.UtcNow.ToLongTimeString());
MemoryStream stream = new MemoryStream(imagefile.str)
{
Position=0
};
blockBlobImage.UploadFromStreamAsync(stream);
}
Test Console:
using (var client = new HttpClient())
{
string URI = string.Format("http://localhost:14456/api/serious/updtTM");
file f1 = new file();
byte[] aa = File.ReadAllBytes(#"D:\Capture2.PNG");
f1.str = aa;
f1.filename = "Capture2";
f1.contentType = "PNG";
var serializedProduct = JsonConvert.SerializeObject(f1);
var content = new StringContent(serializedProduct, Encoding.UTF8, "application/json");
var result = client.PostAsync(URI, content).Result;
}
I have only file Uri to open in the MediaElement.
How to use _MediaElement.SetSource with Uri? My way is based on this example:
var file = await openPicker.PickSingleFileAsync();
var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
mediaControl.SetSource(stream, file.ContentType);
But, I have only Uri from the file. Any ideas?
If you have the Uri, you should use the Source property on the MediaElement:
mediaControl.Source = myUri;
SetSource is more appropriate if you have a stream object.