最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - unable to StartCopyFromUriAsync a blob between 2 storage accounts - Stack Overflow

programmeradmin2浏览0评论

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
 |  Show 1 more comment

2 Answers 2

Reset to default 1

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

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.

发布评论

评论列表(0)

  1. 暂无评论