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?
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?
Share Improve this question asked Feb 7 at 9:24 binga58binga58 17113 bronze badges 6- Whether you need to copy only single file or whole folder fron one storage account to another? – Venkatesan Commented Feb 7 at 10:01
- @Venkatesan for now just a file like what I have tried in the code. Destination path can have folder too but I think that works when I just put like folder1/subfolder/destfilename – binga58 Commented Feb 7 at 10:32
- So what you need actually? – Venkatesan Commented Feb 7 at 10:34
- I need to copy a file inside a container to some container but in different storage account. It works perfectly within same storage account I can copy between different containers or same container. But it doesn't allow me to copy to a different storage account. Hope my question is clear – binga58 Commented Feb 7 at 10:46
- Check the below answer. – Venkatesan Commented Feb 7 at 11:48
2 Answers
Reset to default 1The 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
unable to StartCopyFromUriAsync a blob between 2 storage accounts
You can use the below code that will copy a file from one Azure storage account container to another Storage account container in the local emulator setup using azurite.
Code:
using System;
using System.IO;
using System.Threading.Tasks;
using Azure.Storage.Blobs;
class Program
{
static async Task Main()
{
string sourceAccountName = "devstoreaccount1";
string sourceAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
string sourceBlobEndpoint = $"http://127.0.0.1:10000/{sourceAccountName}";
string destinationAccountName = "account1";
string destinationAccountKey = "Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==";
string destinationBlobEndpoint = $"http://127.0.0.1:10000/{destinationAccountName}";
string sourceConnectionString = $"DefaultEndpointsProtocol=http;AccountName={sourceAccountName};AccountKey={sourceAccountKey};BlobEndpoint={sourceBlobEndpoint}";
string destinationConnectionString = $"DefaultEndpointsProtocol=http;AccountName={destinationAccountName};AccountKey={destinationAccountKey};BlobEndpoint={destinationBlobEndpoint}";
string sourceContainerName = "mycontainer";
string sourceBlobName = "seed.txt";
string destinationContainerName = "testcontainer";
string destinationBlobName = "sample.txt";
try
{
BlobServiceClient sourceBlobServiceClient = new BlobServiceClient(sourceConnectionString);
BlobServiceClient destinationBlobServiceClient = new BlobServiceClient(destinationConnectionString);
var sourceBlobClient = sourceBlobServiceClient.GetBlobContainerClient(sourceContainerName).GetBlobClient(sourceBlobName);
var destinationBlobClient = destinationBlobServiceClient.GetBlobContainerClient(destinationContainerName).GetBlobClient(destinationBlobName);
using (MemoryStream ms = new MemoryStream())
{
await sourceBlobClient.DownloadToAsync(ms);
ms.Position = 0; // Reset stream position
await destinationBlobClient.UploadAsync(ms, overwrite: true);
}
Console.WriteLine($"Blob '{sourceBlobName}' copied from '{sourceContainerName}' to '{destinationContainerName}'.");
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
}
Output:
Blob 'seed.txt' copied from 'mycontainer' to 'testcontainer'.
Reference: azure - using multiple storage accounts locally using azurite at the same time - Stack Overflow by me.