Head 404 dependency issue when trying to write to Blob Storage - azure

I have storage and inside Blob with public access.
but when I am trying to write a document live telemetry shows below Dependency error.
1:21:57 PM | Dependency | 404 | 65
HEAD imagesa| LogLevel=Information | Blob=255274.jpg
Time: 1:21:57 PM
Duration: 65 ms
Outgoing Command: HEAD imagesa
Result code: 404
fileName =imageURL.Substring(imageURL.LastIndexOf(#"/") + 1);
var req = System.Net.WebRequest.Create(imageURL);
using (Stream filestream = req.GetResponse().GetResponseStream())
{
// Get the reference to the block blob from the container
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(fileName);
//create a snapshot
bool existsTask = await blockBlob.ExistsAsync();
if (existsTask == true)
{
// the base blob's metadata is copied to the snapshot.
await blockBlob.CreateSnapshotAsync();
blockBlob.Metadata.Clear();
}
}

I cannot reproduce your issue with the same code in a console app(And if you run your code with some special setting/environment, please point it out).
Please make sure somethings:
1.check if you have set the blob access to public in azure portal, and check your code if use the same blob / container.
2.please use the latest version of WindowsAzure.Storage package, 9.3.3.
And one thing you also need to know: after the code blockBlob.Metadata.Clear(), you need use blockBlob.SetMetadata(). Or it will not clear the metadata.
The code I used:
CloudStorageAccount storageAccount = new CloudStorageAccount(new StorageCredentials("account", "key"), true);
CloudBlobClient cloudBlobClient = storageAccount.CreateCloudBlobClient();
var cloudBlobContainer = cloudBlobClient.GetContainerReference("test-2");
var imageURL = "https://xx.blob.core.windows.net/test-2/sample.JPG";
var fileName = imageURL.Substring(imageURL.LastIndexOf(#"/") + 1);
var req = System.Net.WebRequest.Create(imageURL);
using (Stream filestream = req.GetResponse().GetResponseStream())
{
CloudBlockBlob blockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
bool existsTask = await blockBlob.ExistsAsync();
if (existsTask == true)
{
await blockBlob.CreateSnapshotAsync();
blockBlob.Metadata.Clear();
blockBlob.SetMetadata(); // add this line of code to ensure the changes to metadata is committed.
}
}
Please let me know if you have more issues.

Related

How to download from Azure blob storage using connection string and stored URL [duplicate]

I'm trying to upload images to Azure Blob Storage. I'm using .Net Core and Azure.Storage.Blobs v12.8.0.
The following code is what I have so far.
try
{
var documentByteArray = // a valid byte array of a png file
var blobUri = new Uri("https://mystorageaccount.blob.core.windows.net/images/myfile.png");
BlobClient blobClient = new BlobClient(blobUri);
using (MemoryStream stream = new MemoryStream(documentByteArray))
{
await blobClient.UploadAsync(stream, true, default);
await blobClient.SetHttpHeadersAsync(new BlobHttpHeaders
{
ContentType = "image/png"
});
}
}
catch (Exception ex)
{
//
}
...but somewhat predictably it fails with the exception Server failed to authenticate the request. Please refer to the information in the www-authenticate header.. I say predictable because I've not added any authentication...
And this is the problem/question. How do I add authentication so it will upload?
I know there are Access Keys that I can use - but how? I can't find any examples in MS documentation.
Any insight is appreciated.
If you have access to the Azure Portal, you can get the connection string of the storage account (under "Access Keys" section).
Once you have the connection string, you can use the following code:
var connectionString = "your-storage-account-connection-string";
var containerName = "images";
var blobName = "myfile.png";
var blobClient = new BlobClient(connectionString, containerName, blobName);
//do the upload here...
Other option is to use storage account name and access key (again you can get it from Azure Portal). You would do something like:
var accountName = "account-name";
var accountKey = "account-key";
var blobUri = new Uri("https://mystorageaccount.blob.core.windows.net/images/myfile.png");
var credentials = new StorageSharedKeyCredential(accountName, accountKey);
var blobClient = new BlobClient(blobUri, credentials);
//do the upload here...
You can find more information about BlobClient constructors here: https://learn.microsoft.com/en-us/dotnet/api/azure.storage.blobs.blobclient?view=azure-dotnet.
You should upload your blob through a CloudStorageAccount instance, like this:
var storageAccount = new CloudStorageAccount(
new StorageCredentials("<your account name>", "<your key>"),
"core.windows.net",
true);
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference(containerName);
var blob = container.GetBlockBlobReference(fileName);
await blob.UploadFromStreamAsync(stream);

Why can't I download an Azure Blob using an asp.net core application published to Azure server

I am trying to download a Blob from an Azure storage account container. When I run the application locally, I get the correct "Download" folder C:\Users\xxxx\Downloads. When I publish the application to Azure and try to download the file, I get an error. I have tried various "Knownfolders", and some return empty strings, others return the folders on the Azure server. I am able to upload files fine, list the files in a container, but am struggling with downloading a file.
string conn =
configuration.GetValue<string>"AppSettings:AzureContainerConn");
CloudStorageAccount storageAcct = CloudStorageAccount.Parse(conn);
CloudBlobClient blobClient = storageAcct.CreateCloudBlobClient();
CloudBlobContainer container =
blobClient.GetContainerReference(containerName);
Uri uriObj = new Uri(uri);
string filename = Path.GetFileName(uriObj.LocalPath);
// get block blob reference
CloudBlockBlob blockBlob = container.GetBlockBlobReference(filename);
Stream blobStream = await blockBlob.OpenReadAsync();
string _filepath = _knownfolder.Path + "\\projectfiles\\";
Directory.CreateDirectory(_filepath);
_filepath = _filepath + filename;
Stream _file = new MemoryStream();
try
{
_file = File.Open(_filepath, FileMode.Create, FileAccess.Write);
await blobStream.CopyToAsync(_file);
}
finally
{
_file.Dispose();
}
The expected end result is the file ends up in the folder within the users "Downloads" folder.
Since you're talking about publishing to Azure, the code is probably from a web application, right? And the code for the web application runs on the server. Which means the code is trying to download the blob to the server running the web application.
To present a downloadlink to the user to enable them to download the file, use the FileStreamResult which
Represents an ActionResult that when executed will write a file from a stream to the response.
A (pseudo code) example:
[HttpGet]
public FileStreamResult GetFile()
{
var stream = new MemoryStream();
CloudBlockBlob blockBlob = container.GetBlockBlobReference(filename);
blockBlob.DownloadToStream(stream);
blockBlob.Seek(0, SeekOrigin.Begin);
return new FileStreamResult(stream, new MediaTypeHeaderValue("text/plain"))
{
FileDownloadName = "someFile.txt"
};
}

GetBlockBlobReference not giving the folder path details

I am trying to download a block blob from Azure storage explorer. I am able to download all the block blobs that exist in the root directory of my container. I am unable to download blobs that are nested in subfolders inside the container.
CloudBlockBlob blob = container.GetBlockBlobReference(fileName);
SharedAccessBlobPolicy sasConstraints = new SharedAccessBlobPolicy();
sasConstraints.SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddHours(1);
sasConstraints.Permissions = SharedAccessBlobPermissions.Read;
string sasBlobToken = blob.GetSharedAccessSignature(sasConstraints);
return blob.Uri.AbsoluteUri + sasBlobToken;
I couldn't get the absolute path of blockBlob using GetBlockBlobReference(fileName). The below code solved my issue. I got the listing and then used LINQ to get the blockBlob with the absolute path details.
This post helped as well
do
{
var listingResult = await blobDirectory.ListBlobsSegmentedAsync(useFlatBlobListing, blobListingDetails, maxBlobsPerRequest, continuationToken, null, null);
//The below lined fetched the blockBlob with the correct directory details.
var blockBlob = listingResult.Results.Where(x => x.Uri.AbsolutePath.Contains(fileName)).Count()>0 ? (CloudBlockBlob)listingResult.Results.Where(x=>x.Uri.AbsolutePath.Contains(fileName)).FirstOrDefault():null;
if (blockBlob != null)
{
sasConstraints.SharedAccessExpiryTime = expiryTimeSAS;
sasConstraints.Permissions = SharedAccessBlobPermissions.Read;
string sasBlobToken = blockBlob.GetSharedAccessSignature(sasConstraints);
return blockBlob.Uri.AbsoluteUri + sasBlobToken;
}
continuationToken = listingResult.ContinuationToken;
} while (continuationToken != null);
Correct me if there is any other efficient way of pulling the blob information from a list of directories in a container.
Below Solution helps to access single File Absolute path residing under Directory( or Folder Path).
public static String GetBlobUri(string dirPath, string fileName)
{
//Get a reference to a blob within the container.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("Blob Key");
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
CloudBlobContainer container = blobClient.GetContainerReference("Blob Container");
CloudBlockBlob blockBlob = container.GetBlockBlobReference(dirPath+fileName);
return blockBlob.Uri.AbsoluteUri;
}
Hope this helps someone trying to access Blob File path based on multi level Directory(Level1/Level2/Level3) path.
Just use the ListBlobs mentioned in the answer from Gaurav Mantri to retrieve all files (blobs) within your desired subfolder. Then iterate over it and download it:
var storageAccount = CloudStorageAccount.Parse("yourConnectionString");
var client = storageAccount.CreateCloudBlobClient();
var container = client.GetContainerReference("yourContainer");
var blobs = container.ListBlobs(prefix: "subdirectory1/subdirectory2", useFlatBlobListing: true);
foreach (var blob in blobs)
{
blob.DownloadToFileAsync("yourFilePath");
}

Unable to download the files which were uploaded to the blob storage

I have created container on azure storage and with code below made it work to upload my files(blobs) in container. Now it says upload was successful however I can't figure out how to reach those files to download it. There is no documentation on the internet about it.
Any help would be appreciated to solve it.
// create Azure Storage
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("DefaultEndpointsProtocol=https;AccountName=bireddy;AccountKey=8OMbjBeJR+SIYaSt0YtBUzivLKPX5ZbsGJeEY9vsX0BPbX3uy9KxOckK7LuLeH3ZbOh+NoEaiEIV/NWvZbFOrA==");
// create a blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// create a container
CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");
// make it public
container.SetPermissions(
new BlobContainerPermissions {
PublicAccess = BlobContainerPublicAccessType.Container
});
// create a block blob
CloudBlockBlob blockBlob = container.GetBlockBlobReference(FileUpload1.FileName);
// upload to Azure Storage
// this has to be changed sometime later
blockBlob.Properties.ContentType = FileUpload1.PostedFile.ContentType;
blockBlob.UploadFromStream(FileUpload1.FileContent);
Grateful to your discussion.
There are a number of options to download your blobs:
Using PowerShell: See the Azure Storage Powershell guide here:
http://azure.microsoft.com/en-us/documentation/articles/storage-powershell-guide-full/
Using Command Line: See the documentation for the AzCopy tool here:
http://aka.ms/azcopy
Using your C# code: There is a guide here, that includes a section on how to download blobs:
http://azure.microsoft.com/en-us/documentation/articles/storage-dotnet-how-to-use-blobs/
Using GUI-based explorers: There are a number of third-party explorers, some of them are listed here:
http://blogs.msdn.com/b/windowsazurestorage/archive/2014/03/11/windows-azure-storage-explorers-2014.aspx
// Parse the connection string and return a reference to the storage account.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
//Create the Blob service client
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve a reference to a container.
CloudBlobContainer container = blobClient.GetContainerReference("mycontainer");
// Retrieve reference to a blob named
CloudBlockBlob blockBlob2 = container.GetBlockBlobReference(document);
//using (var np = File.Open(#"C:\mydocuments\"+ document, FileMode.Create))
// blockBlob2.DownloadToStream(np, null, options, null);
byte[] fileBytes;
using (var fileStream = new MemoryStream())
{
blockBlob2.DownloadToStream(fileStream, null, options, null);
fileBytes = fileStream.ToArray();
}
return fileBytes;

Can't rename blob file in Azure Storage

I am trying to rename blob in azure storage via .net API and it is I am unable to rename a blob file after a day : (
Here is how I am doing it, by creating new blob and copy from old one.
var newBlob = blobContainer.GetBlobReferenceFromServer(filename);
newBlob.StartCopyFromBlob(blob.Uri);
blob.Delete();
There is no new blob on server so I am getting http 404 Not Found exception.
Here is working example that i have found but it is for old .net Storage api.
CloudBlob blob = container.GetBlobReference(sourceBlobName);
CloudBlob newBlob = container.GetBlobReference(destBlobName);
newBlob.UploadByteArray(new byte[] { });
newBlob.CopyFromBlob(blob);
blob.Delete();
Currently I am using 2.0 API. Where I am I making a mistake?
I see that you're using GetBlobReferenceFromServer method to create an instance of new blob object. For this function to work, the blob must be present which will not be the case as you're trying to rename the blob.
What you could do is call GetBlobReferenceFromServer on the old blob, get it's type and then either create an instance of BlockBlob or PageBlob and perform copy operation on that. So your code would be something like:
CloudBlobContainer blobContainer = storageAccount.CreateCloudBlobClient().GetContainerReference("container");
var blob = blobContainer.GetBlobReferenceFromServer("oldblobname");
ICloudBlob newBlob = null;
if (blob is CloudBlockBlob)
{
newBlob = blobContainer.GetBlockBlobReference("newblobname");
}
else
{
newBlob = blobContainer.GetPageBlobReference("newblobname");
}
//Initiate blob copy
newBlob.StartCopyFromBlob(blob.Uri);
//Now wait in the loop for the copy operation to finish
while (true)
{
newBlob.FetchAttributes();
if (newBlob.CopyState.Status != CopyStatus.Pending)
{
break;
}
//Sleep for a second may be
System.Threading.Thread.Sleep(1000);
}
blob.Delete();
The code in OP was almost fine except that an async copy method was called. The simplest code in new API should be:
var oldBlob = cloudBlobClient.GetBlobReferenceFromServer(oldBlobUri);
var newBlob = container.GetBlobReference("newblobname");
newBlog.CopyFromBlob(oldBlob);
oldBlob.Delete();

Resources