Skip to content
This repository was archived by the owner on Jan 12, 2024. It is now read-only.

Commit 2080f80

Browse files
authored
Adding ability to provide content type and encoding for Azure blobs (#887)
1 parent 5985170 commit 2080f80

File tree

8 files changed

+133
-51
lines changed

8 files changed

+133
-51
lines changed

src/Azure/Azure.Quantum.Client/Microsoft.Azure.Quantum.Client.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@
2020
</PropertyGroup>
2121

2222
<ItemGroup>
23-
<PackageReference Include="Azure.Core" Version="1.14.0" />
23+
<PackageReference Include="Azure.Core" Version="1.19.0" />
2424
<PackageReference Include="Azure.Identity" Version="1.4.0" />
2525
<PackageReference Include="Azure.Quantum.Jobs" Version="1.0.0-beta.2" />
26-
<PackageReference Include="Azure.Storage.Blobs" Version="12.2.0" />
26+
<PackageReference Include="Azure.Storage.Blobs" Version="12.10.0" />
2727
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
2828
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
2929
<PrivateAssets>all</PrivateAssets>

src/Azure/Azure.Quantum.Client/Storage/IJobStorageHelper.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ public interface IJobStorageHelper
2929
Stream input,
3030
CancellationToken cancellationToken = default);
3131

32+
/// <summary>
33+
/// Uploads the job input.
34+
/// </summary>
35+
/// <param name="jobId">The job id.</param>
36+
/// <param name="input">The input.</param>
37+
/// <param name="contentType">The MIME type indicating the content of the payload.</param>
38+
/// <param name="compress">A flag to indicate if the payload should be uploaded compressed to storage.</param>
39+
/// <param name="cancellationToken">The cancellation token.</param>
40+
/// <returns>Container uri + Input uri.</returns>
41+
Task<(string containerUri, string inputUri)> UploadJobInputAsync(
42+
string jobId,
43+
Stream input,
44+
string contentType,
45+
bool compress,
46+
CancellationToken cancellationToken = default);
47+
3248
/// <summary>
3349
/// Uploads the job program output mapping.
3450
/// </summary>

src/Azure/Azure.Quantum.Client/Storage/IStorageHelper.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
// Copyright (c) Microsoft Corporation. All rights reserved.
1+
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4+
#nullable enable
5+
46
namespace Microsoft.Azure.Quantum.Storage
57
{
68
using System;
@@ -32,14 +34,32 @@ Task DownloadBlobAsync(
3234
/// <param name="containerClient">Container client.</param>
3335
/// <param name="blobName">Name of the BLOB.</param>
3436
/// <param name="input">The input.</param>
37+
/// <param name="contentType">The MIME type indicating the content of the payload.</param>
38+
/// <param name="contentEncoding">The blob encoding.</param>
3539
/// <param name="cancellationToken">The cancellation token.</param>
3640
/// <returns>async task.</returns>
3741
Task UploadBlobAsync(
3842
BlobContainerClient containerClient,
3943
string blobName,
4044
Stream input,
45+
string? contentType,
46+
string? contentEncoding,
4147
CancellationToken cancellationToken = default);
4248

49+
/// <summary>
50+
/// Uploads the BLOB.
51+
/// </summary>
52+
/// <param name="containerClient">Container client.</param>
53+
/// <param name="blobName">Name of the BLOB.</param>
54+
/// <param name="input">The input.</param>
55+
/// <param name="cancellationToken">The cancellation token.</param>
56+
/// <returns>async task.</returns>
57+
Task UploadBlobAsync(
58+
BlobContainerClient containerClient,
59+
string blobName,
60+
Stream input,
61+
CancellationToken cancellationToken = default) => this.UploadBlobAsync(containerClient, blobName, input, null, null, cancellationToken);
62+
4363
/// <summary>
4464
/// Gets the BLOB sas URI.
4565
/// </summary>

src/Azure/Azure.Quantum.Client/Storage/JobStorageHelper.cs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,34 @@ public JobStorageHelper(string connectionString)
3737
}
3838
}
3939

40-
/// <summary>
41-
/// Uploads the job input.
42-
/// </summary>
43-
/// <param name="jobId">The job id.</param>
44-
/// <param name="input">The input.</param>
45-
/// <param name="cancellationToken">The cancellation token.</param>
46-
/// <returns>
47-
/// Container uri + Input uri.
48-
/// </returns>
40+
/// <inheritdoc/>
4941
public override async Task<(string containerUri, string inputUri)> UploadJobInputAsync(
5042
string jobId,
5143
Stream input,
44+
string contentType,
45+
bool compress,
5246
CancellationToken cancellationToken = default)
5347
{
5448
string containerName = GetContainerName(jobId);
49+
string encoding = null;
50+
Stream data = input;
51+
52+
if (compress)
53+
{
54+
var compressedInput = new MemoryStream();
55+
await Compression.Compress(input, compressedInput);
56+
data = compressedInput;
57+
encoding = "gzip";
58+
}
5559

5660
BlobContainerClient containerClient = await this.GetContainerClient(containerName);
5761

5862
await this.StorageHelper.UploadBlobAsync(
5963
containerClient,
6064
Constants.Storage.InputBlobName,
61-
input,
65+
input: data,
66+
contentType: contentType,
67+
contentEncoding: encoding,
6268
cancellationToken);
6369

6470
string containerUri = this.StorageHelper.GetBlobContainerSasUri(

src/Azure/Azure.Quantum.Client/Storage/JobStorageHelperBase.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ namespace Microsoft.Azure.Quantum.Storage
77
using System.IO;
88
using System.Threading;
99
using System.Threading.Tasks;
10+
1011
using global::Azure.Storage.Blobs;
12+
1113
using Microsoft.Azure.Quantum.Utility;
1214

1315
public abstract class JobStorageHelperBase : IJobStorageHelper
@@ -54,17 +56,20 @@ await this.StorageHelper.DownloadBlobAsync(
5456
return;
5557
}
5658

57-
/// <summary>
58-
/// Uploads the job input.
59-
/// </summary>
60-
/// <param name="jobId">The job id.</param>
61-
/// <param name="input">The input.</param>
62-
/// <param name="cancellationToken">The cancellation token.</param>
63-
/// <returns>Container uri + Input uri.</returns>
59+
/// <inheritdoc/>
6460
public abstract Task<(string containerUri, string inputUri)> UploadJobInputAsync(
65-
string jobId,
66-
Stream input,
67-
CancellationToken cancellationToken = default);
61+
string jobId,
62+
Stream input,
63+
string contentType,
64+
bool compress,
65+
CancellationToken cancellationToken = default);
66+
67+
/// <inheritdoc/>
68+
public Task<(string containerUri, string inputUri)> UploadJobInputAsync(
69+
string jobId,
70+
Stream input,
71+
CancellationToken cancellationToken = default) =>
72+
this.UploadJobInputAsync(jobId, input, null, false, cancellationToken);
6873

6974
/// <summary>
7075
/// Uploads the job program output mapping.

src/Azure/Azure.Quantum.Client/Storage/LinkedStorageJobHelper.cs

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -23,28 +23,34 @@ public LinkedStorageJobHelper(IWorkspace workspace)
2323
this.workspace = workspace;
2424
}
2525

26-
/// <summary>
27-
/// Uploads the job input.
28-
/// </summary>
29-
/// <param name="jobId">The job id.</param>
30-
/// <param name="input">The input.</param>
31-
/// <param name="cancellationToken">The cancellation token.</param>
32-
/// <returns>
33-
/// Container uri + Input uri without SAS.
34-
/// </returns>
26+
/// <inheritdoc/>
3527
public override async Task<(string containerUri, string inputUri)> UploadJobInputAsync(
3628
string jobId,
3729
Stream input,
30+
string contentType,
31+
bool compress,
3832
CancellationToken cancellationToken = default)
3933
{
4034
string containerName = GetContainerName(jobId);
35+
string encoding = null;
36+
Stream data = input;
4137

4238
BlobContainerClient containerClient = await this.GetContainerClient(containerName);
4339

40+
if (compress)
41+
{
42+
var compressedInput = new MemoryStream();
43+
await Compression.Compress(input, compressedInput);
44+
data = compressedInput;
45+
encoding = "gzip";
46+
}
47+
4448
await this.StorageHelper.UploadBlobAsync(
45-
containerClient,
46-
Constants.Storage.InputBlobName,
47-
input,
49+
containerClient: containerClient,
50+
blobName: Constants.Storage.InputBlobName,
51+
input: data,
52+
contentType: contentType,
53+
contentEncoding: encoding,
4854
cancellationToken);
4955

5056
Uri inputUri = containerClient
@@ -54,13 +60,7 @@ await this.StorageHelper.UploadBlobAsync(
5460
return (GetUriPath(containerClient.Uri), GetUriPath(inputUri));
5561
}
5662

57-
/// <summary>
58-
/// Uploads the job program output mapping.
59-
/// </summary>
60-
/// <param name="jobId">The job id.</param>
61-
/// <param name="mapping">The job program output mapping.</param>
62-
/// <param name="cancellationToken">The cancellation token.</param>
63-
/// <returns>Container uri + Mapping uri without SAS.</returns>
63+
/// <inheritdoc/>
6464
public override async Task<(string containerUri, string mappingUri)> UploadJobMappingAsync(
6565
string jobId,
6666
Stream mapping,

src/Azure/Azure.Quantum.Client/Storage/StorageHelper.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ namespace Microsoft.Azure.Quantum.Storage
55
{
66
using System;
77
using System.IO;
8+
using System.Net.Mime;
9+
using System.Text;
810
using System.Threading;
911
using System.Threading.Tasks;
1012
using global::Azure.Storage.Blobs;
@@ -42,28 +44,34 @@ public async Task DownloadBlobAsync(
4244
return;
4345
}
4446

45-
/// <summary>
46-
/// Uploads the BLOB.
47-
/// </summary>
48-
/// <param name="containerClient">Container client.</param>
49-
/// <param name="blobName">Name of the BLOB.</param>
50-
/// <param name="input">The input.</param>
51-
/// <param name="cancellationToken">The cancellation token.</param>
52-
/// <returns>Async task.</returns>
47+
/// <inheritdoc/>
5348
public async Task UploadBlobAsync(
5449
BlobContainerClient containerClient,
5550
string blobName,
5651
Stream input,
52+
string contentType,
53+
string contentEncoding,
5754
CancellationToken cancellationToken = default)
5855
{
5956
try
6057
{
6158
// Ensure container is created
6259
await containerClient.CreateIfNotExistsAsync(PublicAccessType.None, cancellationToken: cancellationToken);
6360

61+
var headers = new BlobHttpHeaders
62+
{
63+
ContentEncoding = contentEncoding,
64+
ContentType = contentType,
65+
};
66+
67+
var options = new BlobUploadOptions
68+
{
69+
HttpHeaders = headers,
70+
};
71+
6472
// Upload blob
6573
BlobClient blob = containerClient.GetBlobClient(blobName);
66-
await blob.UploadAsync(input, overwrite: true, cancellationToken);
74+
await blob.UploadAsync(input, options, cancellationToken);
6775
}
6876
catch (Exception ex)
6977
{
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT License.
3+
4+
namespace Microsoft.Azure.Quantum.Utility
5+
{
6+
using System.IO;
7+
using System.IO.Compression;
8+
using System.Threading.Tasks;
9+
10+
internal class Compression
11+
{
12+
public static async Task Compress(Stream data, Stream compressedData)
13+
{
14+
using (var auxStream = new MemoryStream())
15+
using (var zipStream = new GZipStream(auxStream, CompressionMode.Compress))
16+
{
17+
await data.CopyToAsync(zipStream);
18+
await zipStream.FlushAsync();
19+
auxStream.Position = 0;
20+
await auxStream.CopyToAsync(compressedData);
21+
await compressedData.FlushAsync();
22+
}
23+
24+
compressedData.Position = 0;
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)