Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey:System.ObjectDisposedException:无法访问已关闭的流
Posted
技术标签:
【中文标题】Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey:System.ObjectDisposedException:无法访问已关闭的流【英文标题】:Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey : System.ObjectDisposedException: Cannot access a closed Stream 【发布时间】:2021-12-21 21:29:00 【问题描述】:我们在使用 GetUserDelegationKey 生成 SAS 令牌时遇到异常,这是我们在并发请求中遇到的异常。
System.ObjectDisposedException: Cannot access a closed Stream.
at System.IO.MemoryStream.Write(ReadOnlySpan`1 buffer)
at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
at System.IO.StreamWriter.Dispose(Boolean disposing)
at System.Xml.XmlTextWriter.Close()
at Azure.Core.XmlWriterContent.Dispose()
at Azure.Core.Pipeline.HttpClientTransport.PipelineRequest.Dispose()
at Azure.Core.HttpMessage.Dispose()
at Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey(KeyInfo keyInfo, Nullable`1 timeout, CancellationToken cancellationToken)
at Azure.Storage.Blobs.BlobServiceClient.GetUserDelegationKeyInternal(Nullable`1 startsOn, DateTimeOffset expiresOn, Boolean async, CancellationToken cancellationToken)
at Azure.Storage.Blobs.BlobServiceClient.GetUserDelegationKey(Nullable`1 startsOn, DateTimeOffset expiresOn, CancellationToken cancellationToken)
at service.mediastorage.DefsultCredntialStorageService.GetUrlWithAccessToken(String url, Double expiredInHours)
at service.services.VideoService.Convert(Video video) in /home/vsts/work/Source/service.services/VideoService.cs:line 456
at System.Linq.Enumerable.SelectListIterator`2.ToList()
at service.services.VideoService.GetVideosByPaginationaAsync(VideoFilterQueryParams filterParameters, LoggedInUserInfo loggedInUserInfo) in /home/vsts/work/Source/service.services/VideoService.cs:line 175
at service.api.Controllers.VideoController.GetVideosByPaginationAsync(VideoFilterQueryParams videoFilterQueryParameters) in /home/vsts/work/Source/service.api/Controllers/VideoController.cs:line 216
以下代码用于生成 sastoken
public string GetUrlWithAccessToken(string url, double expiredInHours = 0)
if (string.IsNullOrEmpty(url)) return null;
var uri = new Uri(url);
var blobClient = new BlobClient(uri, GetDefaultCredentials());
var blobServiceClient = GetBlobServiceClient(_amsSettings.StorageEndPointUrl);
UserDelegationKey userDelegationKey = blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow,
DateTimeOffset.UtcNow.AddHours(1));
string sasTokenUrl = GetBlobUrlWithAccessToken(userDelegationKey, blobClient, url, expiredInHours);
return sasTokenUrl;
private string GetBlobUrlWithAccessToken(UserDelegationKey userDelegationKey, BlobClient blobClient,string url,double expiredInHours)
// Create a SAS token
BlobSasBuilder sasBuilder = new BlobSasBuilder()
BlobContainerName = blobClient.GetParentBlobContainerClient().Name,
BlobName = blobClient.Name,
Resource = "b"
;
sasBuilder.ExpiresOn = DateTimeOffset.UtcNow.AddHours(expiredInHours);
sasBuilder.SetPermissions(BlobSasPermissions.Read);
// Add the SAS token to the container URI.
BlobUriBuilder blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
// Specify the user delegation key.
Sas = sasBuilder.ToSasQueryParameters(userDelegationKey,
blobClient.AccountName)
;
var sasToken = blobUriBuilder.Sas.ToString();
return url + "?" + sasToken;
谁能帮我解决这个问题。
编辑:
我们正在使用托管标识,当我们进行负载测试时,一些请求失败,但其中一些成功。
谢谢
【问题讨论】:
【参考方案1】:您能否尝试使用此代码生成 SAS 令牌
private static string GetSharedAccessSignature(
string accountName,
string accountkey,
string blobContainer,
string blobName,
DateTimeOffset sharedAccessStartTime,
DateTimeOffset sharedAccessExpiryTime)
var canonicalNameFormat = $"/blob/accountName/blobContainer/blobName";
var st = sharedAccessStartTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
var se = sharedAccessExpiryTime.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssZ");
var sasVersion = "2016-05-31";
string stringToSign = string.Format("0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12", new object[]
"r",
st,
se,
canonicalNameFormat,
string.Empty,
string.Empty,
string.Empty,
sasVersion,
string.Empty,
string.Empty,
string.Empty,
string.Empty,
string.Empty
);
var sas = GetHash(stringToSign, accountkey);
var credentials =
$"?sv=sasVersion&sr=b&sig=UrlEncoder.Default.Encode(sas)&st=UrlEncoder.Default.Encode(st)&se=UrlEncoder.Default.Encode(se)&sp=r";
string blobUri = $"https://accountName.blob.core.windows.net/blobContainer/blobName";
return blobUri + credentials;
private static string GetHash(string stringToSign, string key)
byte[] keyValue = Convert.FromBase64String(key);
using (HMACSHA256 hmac = new HMACSHA256(keyValue))
return Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
更多详情请参考SO Thread:
【讨论】:
OP 想要创建一个User Delegation SAS Token
。您在回答中提到的代码创建了一个Service SAS Token
。
是的,想要创建用户委托 SAS 令牌,因为我们使用的是 ManagedIdentity 和最新的 sdk 版本 Azure.Storage.Blobs=12.9.1
请参考此文档:codewithadam.com/Azure/…
它和我的代码@ShrutiJoshi-MT 一样以上是关于Azure.Storage.Blobs.ServiceRestClient.GetUserDelegationKey:System.ObjectDisposedException:无法访问已关闭的流的主要内容,如果未能解决你的问题,请参考以下文章