Skip to content

Commit a1e7348

Browse files
committed
fix VFS metadata cancellation and provider absence semantics
1 parent ae834c9 commit a1e7348

13 files changed

Lines changed: 158 additions & 48 deletions

File tree

‎Directory.Build.props‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@
2929
<RepositoryUrl>https://github.com/managedcode/Storage</RepositoryUrl>
3030
<PackageProjectUrl>https://github.com/managedcode/Storage</PackageProjectUrl>
3131
<Product>Managed Code - Storage</Product>
32-
<Version>10.1.6</Version>
33-
<PackageVersion>10.1.6</PackageVersion>
32+
<Version>10.1.7</Version>
33+
<PackageVersion>10.1.7</PackageVersion>
3434

3535
</PropertyGroup>
3636

‎ManagedCode.Storage.VirtualFileSystem/Extensions/ServiceCollectionExtensions.cs‎

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -146,64 +146,35 @@ public override async Task SetVfsMetadataAsync(
146146
string blobName,
147147
CancellationToken cancellationToken = default)
148148
{
149-
_logger.LogDebug("Getting VFS metadata for: {BlobName}", blobName);
150-
151-
try
152-
{
153-
var blobMetadata = await _storage.GetBlobMetadataAsync(blobName, cancellationToken);
154-
if (blobMetadata.IsFailed || blobMetadata.Value.Metadata == null)
155-
{
156-
return null;
157-
}
158-
159-
return ParseVfsMetadata(blobMetadata.Value.Metadata);
160-
}
161-
catch (Exception ex)
162-
{
163-
_logger.LogError(ex, "Error getting VFS metadata for: {BlobName}", blobName);
164-
return null;
165-
}
149+
var metadata = await GetBlobInfoAsync(blobName, cancellationToken);
150+
return metadata?.Metadata is { } values ? ParseVfsMetadata(values) : null;
166151
}
167152

168153
public override async Task<IReadOnlyDictionary<string, string>> GetCustomMetadataAsync(
169154
string blobName,
170155
CancellationToken cancellationToken = default)
171156
{
172-
_logger.LogDebug("Getting custom metadata for: {BlobName}", blobName);
173-
174-
try
175-
{
176-
var blobMetadata = await _storage.GetBlobMetadataAsync(blobName, cancellationToken);
177-
if (blobMetadata.IsFailed || blobMetadata.Value.Metadata == null)
178-
{
179-
return new Dictionary<string, string>();
180-
}
181-
182-
return ExtractCustomMetadata(blobMetadata.Value.Metadata);
183-
}
184-
catch (Exception ex)
185-
{
186-
_logger.LogError(ex, "Error getting custom metadata for: {BlobName}", blobName);
187-
return new Dictionary<string, string>();
188-
}
157+
var metadata = await GetBlobInfoAsync(blobName, cancellationToken);
158+
return metadata?.Metadata is { } values
159+
? ExtractCustomMetadata(values)
160+
: new Dictionary<string, string>();
189161
}
190162

191163
public override async Task<BlobMetadata?> GetBlobInfoAsync(
192164
string blobName,
193165
CancellationToken cancellationToken = default)
194166
{
195-
_logger.LogDebug("Getting blob info for: {BlobName}", blobName);
196-
197-
try
198-
{
199-
var result = await _storage.GetBlobMetadataAsync(blobName, cancellationToken);
200-
return result.IsSuccess ? result.Value : null;
201-
}
202-
catch (Exception ex)
167+
cancellationToken.ThrowIfCancellationRequested();
168+
var result = await _storage.GetBlobMetadataAsync(blobName, cancellationToken);
169+
// Portable providers may return cancellation as a failed Result. It must
170+
// neither become a missing file nor populate the VFS metadata cache.
171+
cancellationToken.ThrowIfCancellationRequested();
172+
if (result.IsFailed && result.Problem.StatusCode == 404)
203173
{
204-
_logger.LogDebug(ex, "Blob not found or error getting blob info: {BlobName}", blobName);
205174
return null;
206175
}
176+
result.ThrowIfProblem();
177+
return result.Value;
207178
}
208179
}
209180

‎Storages/ManagedCode.Storage.Aws/AWSStorage.cs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ protected override async Task<Result<BlobMetadata>> GetBlobMetadataInternalAsync
312312

313313
return Result<BlobMetadata>.Succeed(metadata);
314314
}
315+
catch (AmazonS3Exception ex) when (ex.StatusCode == HttpStatusCode.NotFound)
316+
{
317+
return Result<BlobMetadata>.Fail(Problem.FromException(ex, 404));
318+
}
315319
catch (Exception ex)
316320
{
317321
_logger.LogException(ex);

‎Storages/ManagedCode.Storage.Azure.DataLake/AzureDataLakeStorage.cs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Azure;
12
using System;
23
using System.Collections.Generic;
34
using System.IO;
@@ -265,6 +266,10 @@ protected override async Task<Result<BlobMetadata>> GetBlobMetadataInternalAsync
265266
MimeType = properties.Value.ContentType
266267
});
267268
}
269+
catch (RequestFailedException ex) when (ex.Status == 404)
270+
{
271+
return Result<BlobMetadata>.Fail(Problem.FromException(ex, 404));
272+
}
268273
catch (Exception ex)
269274
{
270275
_logger.LogException(ex);

‎Storages/ManagedCode.Storage.Browser/BrowserStorage.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ protected override async Task<Result<BlobMetadata>> GetBlobMetadataInternalAsync
230230
{
231231
var storedBlob = await ReadStoredBlobAsync(options, cancellationToken);
232232
return storedBlob is null
233-
? Result<BlobMetadata>.Fail("File not found")
233+
? Result<BlobMetadata>.FailNotFound("File not found")
234234
: Result<BlobMetadata>.Succeed(ToBlobMetadata(storedBlob));
235235
}
236236
catch (Exception ex)

‎Storages/ManagedCode.Storage.FileSystem/FileSystemStorage.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ protected override async Task<Result<BlobMetadata>> GetBlobMetadataInternalAsync
294294

295295
var fileInfo = new FileInfo(filePath);
296296
if (!fileInfo.Exists)
297-
return Result<BlobMetadata>.Fail("File not found");
297+
return Result<BlobMetadata>.FailNotFound("File not found");
298298

299299
var relativePath = Path.GetRelativePath(StorageClient, filePath)
300300
.Replace('\\', '/');

‎Storages/ManagedCode.Storage.Google/GCPStorage.cs‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ protected override async Task<Result<BlobMetadata>> GetBlobMetadataInternalAsync
325325
Length = obj.Size ?? 0
326326
});
327327
}
328+
catch (GoogleApiException ex) when (ex.HttpStatusCode == HttpStatusCode.NotFound)
329+
{
330+
return Result<BlobMetadata>.Fail(Problem.FromException(ex, 404));
331+
}
328332
catch (Exception ex)
329333
{
330334
_logger.LogException(ex);

‎Storages/ManagedCode.Storage.Sftp/SftpStorage.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ protected override async Task<Result<BlobMetadata>> GetBlobMetadataInternalAsync
400400
var remotePath = BuildPath(options.FullPath);
401401
if (!StorageClient.Exists(remotePath))
402402
{
403-
return Result<BlobMetadata>.Fail("File not found");
403+
return Result<BlobMetadata>.FailNotFound("File not found");
404404
}
405405

406406
var attributes = StorageClient.GetAttributes(remotePath);

‎Tests/ManagedCode.Storage.Tests/Storages/Abstracts/BlobTests.cs‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,17 @@ namespace ManagedCode.Storage.Tests.Storages.Abstracts;
1111

1212
public abstract class BlobTests<T> : BaseContainer<T> where T : IContainer
1313
{
14+
[Fact]
15+
public async Task MissingBlobMetadata_PreservesNotFoundAfterARealWriteAndDelete()
16+
{
17+
var file = await UploadTestFileAsync();
18+
(await Storage.GetBlobMetadataAsync(file.Name, TestContext.Current.CancellationToken)).IsSuccess.ShouldBeTrue();
19+
(await Storage.DeleteAsync(file.Name, TestContext.Current.CancellationToken)).IsSuccess.ShouldBeTrue();
20+
var missing = await Storage.GetBlobMetadataAsync(file.Name, TestContext.Current.CancellationToken);
21+
missing.IsFailed.ShouldBeTrue();
22+
missing.Problem.StatusCode.ShouldBe(404);
23+
}
24+
1425
[Fact]
1526
public async Task GetBlobListAsync_WithoutOptions()
1627
{

‎Tests/ManagedCode.Storage.Tests/Storages/DataLake/AzureDataLakeProtocolTests.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ public async Task FilesAndStreams_RoundTripThroughRealAzureSdk(string? directory
7373
}
7474
(await storage.DeleteAsync(key, token)).IsSuccess.ShouldBeTrue();
7575
(await storage.ExistsAsync(key, token)).Value.ShouldBeFalse();
76+
var missingMetadata = await storage.GetBlobMetadataAsync(key, token);
77+
missingMetadata.IsFailed.ShouldBeTrue();
78+
missingMetadata.Problem.StatusCode.ShouldBe(404);
7679
(await storage.RemoveContainerAsync(token)).IsSuccess.ShouldBeTrue();
7780
}
7881

0 commit comments

Comments
 (0)