followup question for this
I have 2 storage accounts setup locally. I tried to StartCopyFromUriAsync
blob from 1 storage account to another. before this I tried to StartCopyFromUriAsync
same account+same container and same account+different container and both of them worked in my approach. But when I try between 2 storage accounts It gives Azure.RequestFailedException: 'Server failed to authenticate the request. Make sure the value of the Authorization header is formed correctly including the signature
in the line StartCopyFromUriAsync
I tried like this
var sourceAccountName = "devstoreaccount1";
var sourceAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
var sourceBlobEndpoint = $"http://127.0.0.1:10000/{sourceAccountName}";
var destinationAccountName = "devstoreaccount2";
var destinationAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
var destinationBlobEndpoint = $"http://127.0.0.1:10000/{destinationAccountName}";
var sourceConnectionString = $"DefaultEndpointsProtocol=http;AccountName={sourceAccountName};AccountKey={sourceAccountKey};BlobEndpoint={sourceBlobEndpoint}";
var destinationConnectionString = $"DefaultEndpointsProtocol=http;AccountName={destinationAccountName};AccountKey={destinationAccountKey};BlobEndpoint={destinationBlobEndpoint}";
var sourceContainerName = "srccontainer";
var destinationContainerName = "destcontainer";
var sourceBlobName = "myblob";
var destinationBlobName = "destblob";
var sourceBlobServiceClient = new BlobServiceClient(sourceConnectionString);
var destinationBlobServiceClient = new BlobServiceClient(destinationConnectionString);
var sourceContainerClient = sourceBlobServiceClient.GetBlobContainerClient(sourceContainerName);
var sourceBlobClient = sourceContainerClient.GetBlobClient(sourceBlobName);
var destinationContainerClient = destinationBlobServiceClient.GetBlobContainerClient(destinationContainerName);
var destinationBlobClient = destinationContainerClient.GetBlobClient(destinationBlobName);
await destinationContainerClient.CreateIfNotExistsAsync();
var sourceBlobUri = sourceBlobClient.Uri;
Console.WriteLine($"Starting copy from {sourceBlobUri} to {destinationBlobClient.Uri}");
var copyOperation = await destinationBlobClient.StartCopyFromUriAsync(sourceBlobUri);
await copyOperation.WaitForCompletionAsync();
Console.WriteLine("Copy completed");
whats going on here. any idea why?
The error already hints at the problem.
You will need to authenticate against the source blob. Unless the source blob is public available you will need to use a SAS token for example to add authentication information. Add a method like
public static async Task<Uri> CreateServiceSASBlob(
BlobClient blobClient,
string storedPolicyName = null)
{
// Check if BlobContainerClient object has been authorized with Shared Key
if (blobClient.CanGenerateSasUri)
{
// Create a SAS token that's valid for one day
BlobSasBuilder sasBuilder = new BlobSasBuilder()
{
BlobContainerName = blobClient.GetParentBlobContainerClient().Name,
BlobName = blobClient.Name,
Resource = "b"
};
if (storedPolicyName == null)
{
sasBuilder.ExpiresOn = DateTimeOffset.UtcNow.AddDays(1);
sasBuilder.SetPermissions(BlobContainerSasPermissions.Read);
}
else
{
sasBuilder.Identifier = storedPolicyName;
}
Uri sasURI = blobClient.GenerateSasUri(sasBuilder);
return sasURI;
}
else
{
// Client object is not authorized via Shared Key
return null;
}
}
And modify your code to
var sourceAccountName = "devstoreaccount1";
var sourceAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
var sourceBlobEndpoint = $"http://127.0.0.1:10000/{sourceAccountName}";
var destinationAccountName = "devstoreaccount2";
var destinationAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
var destinationBlobEndpoint = $"http://127.0.0.1:10000/{destinationAccountName}";
var sourceConnectionString = $"DefaultEndpointsProtocol=http;AccountName={sourceAccountName};AccountKey={sourceAccountKey};BlobEndpoint={sourceBlobEndpoint}";
var destinationConnectionString = $"DefaultEndpointsProtocol=http;AccountName={destinationAccountName};AccountKey={destinationAccountKey};BlobEndpoint={destinationBlobEndpoint}";
var sourceContainerName = "srccontainer";
var destinationContainerName = "destcontainer";
var sourceBlobName = "myblob";
var destinationBlobName = "destblob";
var sourceBlobServiceClient = new BlobServiceClient(sourceConnectionString);
var destinationBlobServiceClient = new BlobServiceClient(destinationConnectionString);
var sourceContainerClient = sourceBlobServiceClient.GetBlobContainerClient(sourceContainerName);
var sourceBlobClient = sourceContainerClient.GetBlobClient(sourceBlobName);
Uri blobSASURI = await CreateServiceSASBlob(sourceBlobClient);
var destinationContainerClient = destinationBlobServiceClient.GetBlobContainerClient(destinationContainerName);
var destinationBlobClient = destinationContainerClient.GetBlobClient(destinationBlobName);
await destinationContainerClient.CreateIfNotExistsAsync();
Console.WriteLine($"Starting copy from {blobSASURI} to {destinationBlobClient.Uri}");
var copyOperation = await destinationBlobClient.StartCopyFromUriAsync(blobSASURI);
await copyOperation.WaitForCompletionAsync();
Console.WriteLine("Copy completed");
More background, including on how to generate a SAS token for a container instead of a blob can be found here