I would like to get the URL for a BlobItem.
In the Azure Portal, I can see the URL in the properties section, but when I get the BlobItemProperties object from the BlobItem, I cannot find the URL property.
Here is what I have so far:
var blobContainerClient = new BlobContainerClient(connectionString, containerName);
await foreach (var blob in blobContainerClient.GetBlobsAsync())
{
blob.Properties.???
}
You can do that :
var blobContainerClient = new BlobContainerClient(connectionString, containerName);
await foreach (var blob in blobContainerClient.GetBlobsAsync())
{
BlobClient blobClient = blobContainerClient.GetBlobClient(blob.Name);
var uri = blobClient.Uri;
}
There is no AbsoluteUri or Uri property available with the latest SDK , what you need to actually do is to generate a url based on the Container Uri.
You can get the Container Uri as,
var containerUri = blobContainerClient.Uri.AbsoluteUri;
and then you can generate as
List<string> results = new List<string>();
await foreach (BlobItem blobItem in containerClient.GetBlobsAsync())
{
results.Add(
Flurl.Url.Combine(
containerClient.Uri.AbsoluteUri,
blobItem.Name
)
);
}
Also make sure to import,
using Flurl;
Related
this.container = new BlobContainerClient(new Uri(connectionString), new DefaultAzureCredential());
BlobServiceClient blobServiceClient = this.container.GetParentBlobServiceClient();
Azure.Storage.Blobs.Models.UserDelegationKey userDelegationKey = blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(1));
foreach (DataRow row in dt.Rows)
{
string path = folderName + "/" + row.ItemArray[7] + "/" + row.ItemArray[0] + ".png";
BlobClient blobClient = this.container.GetBlobClient(path);
bool isexists = blobClient.Exists();
if(isexists)
{
BlobSasBuilder sasBuilder = new BlobSasBuilder()
{
BlobContainerName = blobClient.BlobContainerName,
BlobName = blobClient.Name,
Resource = "b",
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddDays(1)
};
// Specify read and write permissions for the SAS.
sasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.Write);
// Add the SAS token to the blob URI.
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
{
// Specify the user delegation key.
Sas = sasBuilder.ToSasQueryParameters(userDelegationKey, blobServiceClient.AccountName)
};
}
}
I need to generate SAS uri for each blob but getting Authorization Mismatch error on GetUserDelegationKey Is there any access which is missing or anything else which I need to do.
I tried reproduce in my environment and got below results:
Authorisation mismatch error:
Check your SAS permission whether you are trying to do a write operation with a SAS which only permits read.
Check your RBAC permissions Whether trying to do a write operation while user does not have necessary RBAC permissions on the object.
Also check the Access control(IAM) which is in storage blob contributor role
Code:
using Azure.Identity;
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Models;
using Azure.Storage.Blobs.Specialized;
using Azure.Storage.Sas;
namespace SAStoken
{
class Program
{
private static void Main()
{
var storageAccountUriString = $"https://storage1326.blob.core.windows.net";
var credential = new DefaultAzureCredential();
var blobServiceClient = new BlobServiceClient(new Uri(storageAccountUriString), credential);
var userDelegationKey = blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(1));
var blobContainerClient = blobServiceClient.GetBlobContainerClient("container1"); //container name
var blobClient = blobContainerClient.GetBlobClient("folder1"); // my image blob name
var sasBuilder = new BlobSasBuilder()
{
BlobContainerName = blobClient.BlobContainerName,
BlobName = blobClient.Name,
Resource = "b", // b for blob, c for container
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddHours(4),
};
sasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.Write); // read write permissions
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
{
// Specify the user delegation key.
Sas = sasBuilder.ToSasQueryParameters(userDelegationKey, blobServiceClient.AccountName)
};
Console.WriteLine("Blob user delegation SAS URI: {0}", blobUriBuilder);
}
}
}
Console:
Output:
Reference:
Create a user delegation SAS - Azure Storage | Microsoft Learn
We are migrating the code to use azure storage v12 client libraries (Azure.Storage.Blobs 12.12.0) from V11. Getting the below mentioned exception when we try to create SAS Uri using GenerateSasUri() method.
Exception: "Value cannot be null. (Parameter 'sharedKeyCredential')"
this.blobContainerClient = new BlobContainerClient(
new Uri($https://{storageAccountName}.blob.core.windows.net/{containerName}),
new ManagedIdentityCredential(managedIdentityAppId));
var blobClient = blobContainerClient.GetBlobClient(blobName);
BlobSasBuilder sasBuilder = new()
{
BlobContainerName = containerName,
BlobName = blobName,
Resource = "b",
StartsOn = DateTime.UtcNow.AddMinutes(-15),
ExpiresOn = expirationTimeUtc
};
sasBuilder.SetPermissions(requestedPermission);
return blobClient.GenerateSasUri(sasBuilder);
Thomas pointed out the cause for this issue. The best to handle in your code is to check whether your blobclinet can able to create the sas using CanGenerateSasUri
this.blobContainerClient = new BlobContainerClient(
new Uri($https://{storageAccountName}.blob.core.windows.net/{containerName}),
new ManagedIdentityCredential(managedIdentityAppId));
var blobClient = blobContainerClient.GetBlobClient(blobName);
// Check whether this BlobClient object has been authorized with Shared Key.
if (blobClient.CanGenerateSasUri)
{
BlobSasBuilder sasBuilder = new()
{
BlobContainerName = containerName,
BlobName = blobName,
Resource = "b",
StartsOn = DateTime.UtcNow.AddMinutes(-15),
ExpiresOn = expirationTimeUtc
};
sasBuilder.SetPermissions(requestedPermission);
return blobClient.GenerateSasUri(sasBuilder);
}
else
{
Console.WriteLine(#"BlobClient must be authorized with Shared Key
credentials to create a service SAS.");
return null;
}
You CAN create SAS Uris for AD authenticated (incl managed service identities) users as well, with what is called user delegation key.
Read more from here:
Create a user delegation SAS for a container, directory, or blob with .NET
Example code (abbreviated from the link above):
var blobServiceClient = blobClient
.GetParentBlobContainerClient()
.GetParentBlobServiceClient();
var userDelegationKey = await blobServiceClient
.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow, DateTimeOffset.UtcNow.AddDays(7));
var sasBuilder = new BlobSasBuilder()
{
BlobContainerName = blobClient.BlobContainerName,
BlobName = blobClient.Name,
Resource = "b",
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddDays(7)
};
sasBuilder.SetPermissions(BlobSasPermissions.Read);
var blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
{
Sas = sasBuilder.ToSasQueryParameters(
userDelegationKey,
blobServiceClient.AccountName)
};
var uri = blobUriBuilder.ToUri();
Note that user delegation keys cannot be as long-lived as shared keys. I think the max duration for UDK was in the scale of days or a few weeks, while you could use months for SAS urls with shared keys.
I do not know if this is a bug or not, but I have made a Xamarin app, that will connect to Azure storage to upload a file.
It doesn't want to upload nd I get this error
Azure service, to upload the file
I made the same application, using a console app (for testing fester)
var path = Path.Combine(projectPath, "universal.txt");
var fullpath = Path.GetFullPath(path);
var FileName = Path.GetFileName(fullpath);
using (StreamWriter sw = new StreamWriter(fullpath)) {
sw.WriteLine("Hello I want to go to Universal tomorrow");
}
var AzureStorage = new BlobContainerClient(ConectionString, ContanerName);
var blob = AzureStorage.GetBlobClient(FileName);
await blob.UploadAsync(fullpath);
My file get uploaded to Azure
File in storage
Use these functions to upload a file from xamarin.
static CloudBlobContainer GetContainer(ContainerType containerType)
{
var account = CloudStorageAccount.Parse(Constants.StorageConnection);
var client = account.CreateCloudBlobClient();
return client.GetContainerReference(containerType.ToString().ToLower());
}
public static async Task<string> UploadFileAsync(ContainerType containerType, Stream stream)
{
var container = GetContainer(containerType);
await container.CreateIfNotExistsAsync();
var name = Guid.NewGuid().ToString();
var fileBlob = container.GetBlockBlobReference(name);
await fileBlob.UploadFromStreamAsync(stream);
return name;
}
OR
client = new BlobServiceClient(storageConnectionString);
containerClient = await client.CreateBlobContainerAsync(containerName);
blobClient = containerClient.GetBlobClient(fileName);
await containerClient.UploadBlobAsync(fileName, memoryStreamFile);
Our code is currently using the old Microsoft.WindowsAzure.Storage libraries for blob storage access in Azure. I am trying to use the new v12 Azure.Storage.Blobs libraries to replace the old ones, however I cannot figure out how to decrypt/encrypt the blobs. The MS docs (https://learn.microsoft.com/en-us/azure/storage/blobs/storage-encrypt-decrypt-blobs-key-vault?tabs=dotnet) helpfully say that the v12 code snippets aren't ready yet, so there are no code examples.
The old code is like this:
var tokenProvider = new AzureServiceTokenProvider();
var cloudResolver = new KeyVaultKeyResolver(
new KeyVaultClient.AuthenticationCallback(_tokenProvider.KeyVaultTokenCallback));
var encryptionThingy = await cloudResolver.ResolveKeyAsync(<Key Vault URL> + "/keys/" + <key name>, CancellationToken.None);
var policy = new BlobEncryptionPolicy(encryptionThingy, cloudResolver);
var options = new BlobRequestOptions() { EncryptionPolicy = policy };
await <ICloudBlob Instance>.DownloadToStreamAsync(<stream>, null, options, null);
So far with the new code I've gotten here:
var azureKeys = new KeyClient(new Uri(<key vault url>), new DefaultAzureCredential());
var encKey = azureKeys.GetKey(<key name>);
ClientSideEncryptionOptions encryptionOptions = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V1_0)
{
KeyEncryptionKey = (IKeyEncryptionKey)key
};
var bsClient = new BlobServiceClient(cStr, new SpecializedBlobClientOptions() { ClientSideEncryption = encryptionOptions });
var containerClient = new BlobContainerClient(cStr, containerName);
bClient = containerClient.GetBlobClient(<blob name>);
Of course this throws an exception because KeyVaultKey cannot be converted to IKeyEncryptionKey. So my questions are
Can the key be converted to an IKeyEncryptionKey easily, and how?
Can a key resolver be easily retrieved from the Azure SDKs, and how so?
I'm presuming there are ways to do this that don't involve creating our own implementations of the interfaces, but MS in their infinite wisdom didn't see fit to add those few lines to their documentation.
I write a simple demo for you. Just try the C# console app below about azure blob client-encryption with azure KeyVault:
using System;
using Azure.Identity;
using Azure.Security.KeyVault.Keys.Cryptography;
using Azure.Storage;
using Azure.Storage.Blobs;
using Azure.Storage.Blobs.Specialized;
namespace BlobEncyptionWithBlob
{
class Program
{
static void Main(string[] args)
{
string keyVaultName = "";
string keyName = "";
string kvUri = "https://" + keyVaultName + ".vault.azure.net/keys/" + keyName;
string storageConnStr = "";
string containerName = "";
string encyptBlob = "encypt.txt";
string localblobPath = #"C:\Users\Administrator\Desktop\123.txt";
string localblobPath2 = #"C:\Users\Administrator\Desktop\123-decode.txt";
//Below is to use recommended OAuth2 approach
//string clientID = "<OAuth Client ID>";
//string clientSecret = "<OAuth Secret>";
//string tenant = "<OAuth Tenant ID>";
//var cred = new ClientSecretCredential(tenant, clientID, clientSecret);
//This is what you use to directly replace older AppAuthentication
var cred = new DefaultAzureCredential();
CryptographyClient cryptoClient = new CryptographyClient(new Uri(kvUri), cred);
KeyResolver keyResolver = new KeyResolver(cred);
ClientSideEncryptionOptions encryptionOptions = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V1_0)
{
KeyEncryptionKey = cryptoClient,
KeyResolver = keyResolver,
KeyWrapAlgorithm = "RSA-OAEP"
};
BlobClientOptions options = new SpecializedBlobClientOptions() { ClientSideEncryption = encryptionOptions };
var blobClient = new BlobServiceClient(storageConnStr,options).GetBlobContainerClient(containerName).GetBlobClient(encyptBlob);
//upload local blob to container
blobClient.Upload(localblobPath);
//If you want to modify the meta data you have to copy the exisiting meta, think there is a bug in the library that will wipe out the encryptiondata metadata if you write your own meta
var myMeta = new Dictionary<string, string>();
myMeta.Add("comment", "dis file is da shiznit");
foreach (var existingMeta in blobClient.GetProperties().Value.Metadata)
{
if (!myMeta.ContainsKey(existingMeta.Key))
{
myMeta.Add(existingMeta.Key, existingMeta.Value);
}
}
blobClient.SetMetadata(myMeta);
//Download from container to see if it is decided
blobClient.DownloadTo(localblobPath2);
}
}
}
Result:
My local .txt file content:
Upload to blob and its content, it has been encrypted :
Download to local again and its content, it has been decoded:
So I am trying to list blobs contained in a virtual folder let's call it "VF"
I have tried many methods for example:
var storageAccount = CloudStorageAccount.Parse("...");
var blobClient = storageAccount.CreateCloudBlobClient();
var container = blobClient.GetContainerReference("Container_Name");
List<IListBlobItem> blobslist = container.ListBlobsSegmentedAsync("VF", true).ToList();
But I receive errors like:
Error: Argument 2: cannot convert from 'bool' to 'Microsoft.WindowsAzure.Storage.Blobl.BlobContinuationToken"}
I am trying to return file contents using an API, is this why I am receiving trouble and am using the incorrect methods?
Any help is greatly appreciated
You need to implement the usage of BlobContinuationToken correctly.
Try it like this
if (CloudStorageAccount.TryParse(connectionString, out CloudStorageAccount storageAccount))
{
var context = new OperationContext();
var options = new BlobRequestOptions();
var cloudBlobClient = storageAccount.CreateCloudBlobClient();
var cloudBlobContainer = cloudBlobClient.GetContainerReference(blobContainerName);
BlobContinuationToken blobContinuationToken = null;
do
{
var results = await cloudBlobContainer.ListBlobsSegmentedAsync(null, true, BlobListingDetails.All,
null, blobContinuationToken, options, context);
blobContinuationToken = results.ContinuationToken;
foreach (var item in results.Results)
{
//do what you want with each blob
}
} while (blobContinuationToken != null);
}