【问题标题】:System.InvalidCastException in Renaming Azure Container重命名 Azure 容器时出现 System.InvalidCastException
【发布时间】:2020-03-27 17:41:32
【问题描述】:

我正在尝试重命名 azure blob 存储中的容器。我能够成功重命名容器。但我注意到在某些情况下,在某些过程中。我遇到了一些错误。

这是错误信息。

System.InvalidCastException: '无法转换类型的对象 'Microsoft.WindowsAzure.Storage.Blob.CloudBlobDirectory' 键入 'Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob'。'

下面是我的代码。

string ContainerName = "old-container-name";
    string NewContainerName = "new-container-name";
    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(CloudConfigurationManager.GetSetting("StorageConnectionString"));
    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
    CloudBlobContainer container = blobClient.GetContainerReference(ContainerName);
    CloudBlobContainer destcontainer = blobClient.GetContainerReference(NewContainerName);
    destcontainer.CreateIfNotExists(BlobContainerPublicAccessType.Blob);
    IEnumerable<IListBlobItem> IE = container.ListBlobs(blobListingDetails: BlobListingDetails.Metadata);
    foreach (IListBlobItem item in IE)
    {
        CloudBlockBlob blob = (CloudBlockBlob)item;
        CloudBlockBlob destBlob = destcontainer.GetBlockBlobReference(blob.Name);
        destBlob.StartCopyAsync(new Uri(GetSharedAccessUri(blob.Name, container)));
    }

我在这一行收到错误:

CloudBlockBlob blob = (CloudBlockBlob)item;

你们有解决这个问题的办法吗?有关如何解决此问题的任何提示?

【问题讨论】:

    标签: c# asp.net azure azure-blob-storage


    【解决方案1】:

    您收到此错误的原因是您列出 Blob 的方式。

    IEnumerable<IListBlobItem> IE = container.ListBlobs(blobListingDetails: BlobListingDetails.Metadata);
    

    上面的代码行将列出 blob 和虚拟文件夹。虚拟文件夹由CloudBlobDirectory 表示。由于您尝试将 CloudBlockBlob 类型的对象转换为 CloudBlobDirectory,因此您会遇到此异常。

    要列出 blob 容器中的所有 blob,请使用以下 ListBlobs 方法的覆盖:https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.storage.blob.cloudblobcontainer.listblobs?view=azure-dotnet-legacy

    您需要为useFlatBlobListing 参数传递true。然后它将只返回 blob 而不是虚拟文件夹。

    【讨论】:

    • 知道了 Gaurav。这是导致问题的原因。我添加了 useFlatBlobListing 而没有删除旧的,现在它工作正常。谢谢大佬
    【解决方案2】:
    • 在投射前检查item 的类型。
    • 你必须await你的Task
    • 总是更喜欢异步 API。不要混合使用非 Async 和 Async API(这确实意味着使用自定义的 ListBlobsAsync 方法,因为没有单一的 ListBlobsAsync 方法):
    
    async Task CopyBlobsAsync()
    {
        const String ContainerName    = "old-container-name";
        const String NewContainerName = "new-container-name";
    
        CloudStorageAccount storageAccount = CloudStorageAccount.Parse( CloudConfigurationManager.GetSetting("StorageConnectionString") );
        CloudBlobClient     blobClient     = storageAccount.CreateCloudBlobClient();
        CloudBlobContainer  container      = blobClient.GetContainerReference( ContainerName );
        CloudBlobContainer  destcontainer  = blobClient.GetContainerReference( NewContainerName );
    
        await destcontainer.CreateIfNotExistsAsync( BlobContainerPublicAccessType.Blob );
    
        List<IListBlobItem> blobs = await ListBlobsAsync( container ).ConfigureAwait(false);
        List<Task>          tasks = new List<Task>();
    
        foreach( IListBlobItem item in blobs )
        {
            if( item is CloudBlockBlob blob )
            {
                CloudBlockBlob destBlob = destcontainer.GetBlockBlobReference( blob.Name );
                Uri destUri = new Uri( GetSharedAccessUri( blob.Name, container ) );
                Task task = destBlob.StartCopyAsync( destUri  );
                tasks.Add( task );
            }
        }
    
        await Task.WhenAll( tasks ).ConfigureAwait(false);
    }
    
    // From https://ahmet.im/blog/azure-listblobssegmentedasync-listcontainerssegmentedasync-how-to/
    async Task<List<IListBlobItem> ListBlobsAsync( CloudBlobContainer container )
    {
        BlobContinuationToken continuationToken = null;
        List<IListBlobItem> results = new List<IListBlobItem>();
        do
        {
            var response = await ListBlobsSegmentedAsync( continuationToken );
            continuationToken = response.ContinuationToken;
            results.AddRange( response.Results );
        }
        while( continuationToken != null );
        return results;
    }
    

    【讨论】:

    • 感谢您回答戴。我使用您的代码并更改我的代码。我注意到一些我不熟悉的行。首先是这个 ListBlobsSegmentedAsync,vs 编译器确实阅读了这个并建议创建一个方法。此外,如果(项目是 CloudBlockBlob blob)编译器说它在 c# 5 中不可用,它建议升级我的版本。最后一个是 .CreateIfNotExistsAsync(BlobContainerPublicAccessType.Blob) 它说无法从“Microsoft.WindowzAzure.Storage.Blob.BlobContainerPublicAccessType”转换为“System.Threading.CancellationToken”。
    • @KevinJacob 您使用的是什么版本的 Visual Studio?您的项目配置为使用哪个版本的 C# 语言?您使用的是什么 Azure 存储库包(全名)和版本?
    • 它的 c# 5 和我们正在使用的 azure 存储我不确定,但这是我们在 web.config 中的 azure storage sn-p。
    • @KevinJacob Ah - C# 5.0 来自 2012 年(我们现在使用 C# 8.0),Microsoft.WindowsAzure.Storage 也已过时(我们现在是第 10 版)。我的代码适用于带有 C# 7.3 的 10 版。您使用非常过时的工具是有原因的吗?
    • 抱歉回复晚了。是的戴。我正在处理旧的源代码。
    猜你喜欢
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 2019-07-08
    • 1970-01-01
    • 2020-03-27
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多