Skip to content

Commit b3a5b00

Browse files
committed
update dependencies and isolate client downloads
1 parent 38dbd8e commit b3a5b00

6 files changed

Lines changed: 70 additions & 16 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.0.17</Version>
33-
<PackageVersion>10.0.17</PackageVersion>
32+
<Version>10.1.0</Version>
33+
<PackageVersion>10.1.0</PackageVersion>
3434

3535
</PropertyGroup>
3636

‎Directory.Packages.props‎

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,23 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
55
<ItemGroup>
6-
<PackageVersion Include="AWSSDK.S3" Version="4.0.103.3" />
6+
<PackageVersion Include="AWSSDK.S3" Version="4.0.104.1" />
77
<PackageVersion Include="Azure.Identity" Version="1.21.0" />
8-
<PackageVersion Include="Azure.Storage.Blobs" Version="12.29.2" />
9-
<PackageVersion Include="Azure.Storage.Files.DataLake" Version="12.27.1" />
8+
<PackageVersion Include="Azure.Storage.Blobs" Version="12.30.0" />
9+
<PackageVersion Include="Azure.Storage.Files.DataLake" Version="12.28.0" />
1010
<PackageVersion Include="Cartograph.Catalog" Version="0.1.0-alpha" />
11-
<PackageVersion Include="coverlet.collector" Version="10.0.1" />
12-
<PackageVersion Include="coverlet.msbuild" Version="10.0.1" />
11+
<PackageVersion Include="coverlet.collector" Version="10.1.0" />
12+
<PackageVersion Include="coverlet.msbuild" Version="10.1.0" />
1313
<PackageVersion Include="CsvHelper" Version="33.1.0" />
1414
<PackageVersion Include="DotNet.ReproducibleBuilds" Version="2.0.5" />
1515
<PackageVersion Include="Dropbox.Api" Version="7.4.0" />
16-
<PackageVersion Include="Google.Api.Gax" Version="4.15.0" />
17-
<PackageVersion Include="Google.Api.Gax.Rest" Version="4.15.0" />
18-
<PackageVersion Include="Google.Apis.Drive.v3" Version="1.76.0.4261" />
16+
<PackageVersion Include="Google.Api.Gax" Version="4.15.1" />
17+
<PackageVersion Include="Google.Api.Gax.Rest" Version="4.15.1" />
18+
<PackageVersion Include="Google.Apis.Drive.v3" Version="1.77.0.4276" />
1919
<PackageVersion Include="Google.Apis.Storage.v1" Version="1.76.0.4271" />
2020
<PackageVersion Include="Google.Cloud.Storage.V1" Version="5.0.0" />
2121
<PackageVersion Include="Humanizer.Core" Version="3.0.10" />
22-
<PackageVersion Include="ManagedCode.Communication" Version="10.2.6" />
22+
<PackageVersion Include="ManagedCode.Communication" Version="10.3.1" />
2323
<PackageVersion Include="ManagedCode.MimeTypes" Version="10.1.1" />
2424
<PackageVersion Include="Microsoft.AspNetCore.Http" Version="2.3.13" />
2525
<PackageVersion Include="Microsoft.AspNetCore.Http.Connections.Client" Version="10.0.12" />
@@ -36,10 +36,10 @@
3636
<PackageVersion Include="Microsoft.Extensions.Options" Version="10.0.12" />
3737
<PackageVersion Include="Microsoft.Graph" Version="6.7.0" />
3838
<PackageVersion Include="Microsoft.JSInterop" Version="10.0.12" />
39-
<PackageVersion Include="Microsoft.Playwright" Version="1.62.0" />
39+
<PackageVersion Include="Microsoft.Playwright" Version="1.63.0" />
4040
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.10.1" />
41-
<PackageVersion Include="Microsoft.Orleans.Runtime" Version="10.3.1" />
42-
<PackageVersion Include="Microsoft.Orleans.TestingHost" Version="10.3.1" />
41+
<PackageVersion Include="Microsoft.Orleans.Runtime" Version="10.4.0" />
42+
<PackageVersion Include="Microsoft.Orleans.TestingHost" Version="10.4.0" />
4343
<PackageVersion Include="NetArchTest.Rules" Version="1.3.2" />
4444
<PackageVersion Include="Shouldly" Version="4.3.0" />
4545
<PackageVersion Include="SSH.NET" Version="2026.0.0" />

‎Integraions/ManagedCode.Storage.Client/StorageClient.cs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ public async Task<Result<LocalFile>> DownloadFile(string fileName, string apiUrl
120120
{
121121
using var response = await httpClient.GetStreamAsync($"{apiUrl}/{fileName}", cancellationToken);
122122
var localFile = path is null
123-
? await LocalFile.FromStreamAsync(response, fileName, cancellationToken)
123+
? await LocalFile.FromStreamAsync(response, cancellationToken)
124124
: await LocalFile.FromStreamAsync(response, path, fileName, cancellationToken);
125125
return Result<LocalFile>.Succeed(localFile);
126126
}

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Cloud storage vendors expose distinct SDKs, option models, and authentication pa
104104
- Keyed dependency-injection registrations plus default provider helpers to fan out files per tenant, region, or workload without manual service plumbing.
105105
- `ManagedCode.Storage.Orleans` lets Orleans grains persist `IPersistentState<TState>` through any registered ManagedCode `IStorage`, including typed and keyed DI setups.
106106
- ASP.NET storage controllers, chunk orchestration services, and a SignalR hub/client pair that deliver resumable uploads, ranged downloads, CRC32 validation, and real-time progress.
107-
- `ManagedCode.Storage.Client` brings streaming uploads/downloads, CRC32 helpers, and MIME discovery via `MimeHelper` to any .NET app.
107+
- `ManagedCode.Storage.Client` brings streaming uploads/downloads, CRC32 helpers, and MIME discovery via `MimeHelper` to any .NET app. Downloads without an explicit destination use independent temporary files, so identical remote filenames cannot overwrite one another. Dispose each returned `LocalFile` after use.
108108
- Strongly typed option objects (`UploadOptions`, `DownloadOptions`, `DeleteOptions`, `MetadataOptions`, `LegalHoldOptions`, etc.) let you configure directories, metadata, and legal holds in one place.
109109
- Azure object listings return bounded pages with opaque continuation tokens and `null` after the last page, including empty listings. Listing and properties reads expose the same opaque ETag for the same revision.
110110
- Azure metadata preserves Unicode filenames and other logical string values through a provider-owned ASCII transport envelope; ordinary native ASCII metadata remains interoperable. See [metadata transport](https://github.com/managed-code-hub/Storage/blob/main/docs/Features/provider-azure-blob.md#metadata-transport).
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using System;
2+
using System.IO;
3+
using System.Net;
4+
using System.Net.Http;
5+
using System.Text;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
using ManagedCode.Storage.Client;
9+
using Shouldly;
10+
using Xunit;
11+
12+
namespace ManagedCode.Storage.Tests.Core;
13+
14+
public class StorageClientDownloadTests
15+
{
16+
[Fact]
17+
public async Task DownloadFile_DefaultDestinationKeepsSameNamedDownloadsIndependent()
18+
{
19+
using var handler = new DownloadHandler();
20+
using var httpClient = new HttpClient(handler) { BaseAddress = new Uri("https://localhost") };
21+
var client = new StorageClient(httpClient);
22+
23+
var firstResult = await client.DownloadFile("shared.bin", "/download");
24+
firstResult.IsSuccess.ShouldBeTrue();
25+
await using var first = firstResult.Value!;
26+
27+
var secondResult = await client.DownloadFile("shared.bin", "/download");
28+
secondResult.IsSuccess.ShouldBeTrue();
29+
await using var second = secondResult.Value!;
30+
31+
first.FilePath.ShouldNotBe(second.FilePath);
32+
(await File.ReadAllTextAsync(first.FilePath)).ShouldBe("first payload");
33+
(await File.ReadAllTextAsync(second.FilePath)).ShouldBe("second payload");
34+
}
35+
36+
private sealed class DownloadHandler : HttpMessageHandler
37+
{
38+
private int _requests;
39+
40+
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
41+
{
42+
request.RequestUri!.AbsolutePath.ShouldBe("/download/shared.bin");
43+
var payload = Interlocked.Increment(ref _requests) == 1 ? "first payload" : "second payload";
44+
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
45+
{
46+
Content = new ByteArrayContent(Encoding.UTF8.GetBytes(payload))
47+
});
48+
}
49+
}
50+
}

‎docs/Architecture.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,7 @@ flowchart LR
234234
- Behavior specs: [./Features/index.md](./Features/index.md)
235235
- API docs: [./API/index.md](./API/index.md)
236236
- Setup and verification: [./Development/setup.md](./Development/setup.md), [./Testing/index.md](./Testing/index.md)
237+
238+
### HTTP client download destinations
239+
240+
`StorageClient.DownloadFile` allocates a unique temporary file when no destination path is provided. Same-named downloads retain independent contents and lifetimes. An explicit destination continues to use the caller-selected directory and filename. Callers dispose the returned `LocalFile` to remove temporary content.

0 commit comments

Comments
 (0)