Skip to content

Commit 9b3810a

Browse files
Better sync-over-async
1 parent d8b3379 commit 9b3810a

3 files changed

Lines changed: 81 additions & 75 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright (c) Six Labors.
2+
// Licensed under the Apache License, Version 2.0.
3+
4+
using System;
5+
using System.Globalization;
6+
using System.Threading;
7+
using System.Threading.Tasks;
8+
9+
namespace SixLabors.ImageSharp.Web
10+
{
11+
/// <summary>
12+
/// <see href="https://github.com/aspnet/AspNetIdentity/blob/b7826741279450c58b230ece98bd04b4815beabf/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs"/>
13+
/// </summary>
14+
internal static class AsyncHelper
15+
{
16+
private static readonly TaskFactory TaskFactory = new
17+
(CancellationToken.None,
18+
TaskCreationOptions.None,
19+
TaskContinuationOptions.None,
20+
TaskScheduler.Default);
21+
22+
/// <summary>
23+
/// Executes an async <see cref="Task"/> method synchronously.
24+
/// </summary>
25+
/// <param name="task">The task to excecute.</param>
26+
public static void RunSync(Func<Task> task)
27+
{
28+
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
29+
CultureInfo culture = CultureInfo.CurrentCulture;
30+
TaskFactory.StartNew(() =>
31+
{
32+
Thread.CurrentThread.CurrentCulture = culture;
33+
Thread.CurrentThread.CurrentUICulture = cultureUi;
34+
return task();
35+
}).Unwrap().GetAwaiter().GetResult();
36+
}
37+
38+
/// <summary>
39+
/// Executes an async <see cref="Task{TResult}"/> method which has
40+
/// a <paramref name="task"/> return type synchronously.
41+
/// </summary>
42+
/// <typeparam name="TResult">The type of result to return.</typeparam>
43+
/// <param name="task">The task to excecute.</param>
44+
/// <returns>The <typeparamref name="TResult"/>.</returns>
45+
public static TResult RunSync<TResult>(Func<Task<TResult>> task)
46+
{
47+
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
48+
CultureInfo culture = CultureInfo.CurrentCulture;
49+
return TaskFactory.StartNew(() =>
50+
{
51+
Thread.CurrentThread.CurrentCulture = culture;
52+
Thread.CurrentThread.CurrentUICulture = cultureUi;
53+
return task();
54+
}).Unwrap().GetAwaiter().GetResult();
55+
}
56+
}
57+
}

src/ImageSharp.Web.Providers.AWS/Caching/AWSS3StorageCache.cs

Lines changed: 8 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Apache License, Version 2.0.
33

4-
using System;
54
using System.Collections.Generic;
6-
using System.Globalization;
75
using System.IO;
8-
using System.Threading;
96
using System.Threading.Tasks;
107
using Amazon.S3;
118
using Amazon.S3.Model;
@@ -21,12 +18,6 @@ namespace SixLabors.ImageSharp.Web.Caching.AWS
2118
/// </summary>
2219
public class AWSS3StorageCache : IImageCache
2320
{
24-
private static readonly TaskFactory TaskFactory = new
25-
(CancellationToken.None,
26-
TaskCreationOptions.None,
27-
TaskContinuationOptions.None,
28-
TaskScheduler.Default);
29-
3021
private readonly IAmazonS3 amazonS3Client;
3122
private readonly string bucket;
3223

@@ -70,8 +61,7 @@ public Task SetAsync(string key, Stream stream, ImageCacheMetadata metadata)
7061
AutoCloseStream = false
7162
};
7263

73-
var dt = metadata.ToDictionary();
74-
foreach (KeyValuePair<string, string> d in dt)
64+
foreach (KeyValuePair<string, string> d in metadata.ToDictionary())
7565
{
7666
request.Metadata.Add(d.Key, d.Value);
7767
}
@@ -97,11 +87,16 @@ public Task SetAsync(string key, Stream stream, ImageCacheMetadata metadata)
9787
public static PutBucketResponse CreateIfNotExists(
9888
AWSS3BucketClientOptions options,
9989
S3CannedACL acl)
90+
=> AsyncHelper.RunSync(() => CreateIfNotExistsAsync(options, acl));
91+
92+
private static async Task<PutBucketResponse> CreateIfNotExistsAsync(
93+
AWSS3BucketClientOptions options,
94+
S3CannedACL acl)
10095
{
10196
AmazonS3Client client = AmazonS3ClientFactory.CreateClient(options);
10297

10398
bool foundBucket = false;
104-
ListBucketsResponse listBucketsResponse = RunSync(() => client.ListBucketsAsync());
99+
ListBucketsResponse listBucketsResponse = await client.ListBucketsAsync();
105100
foreach (S3Bucket b in listBucketsResponse.Buckets)
106101
{
107102
if (b.BucketName == options.BucketName)
@@ -120,30 +115,10 @@ public static PutBucketResponse CreateIfNotExists(
120115
CannedACL = acl
121116
};
122117

123-
return RunSync(() => client.PutBucketAsync(putBucketRequest));
118+
return await client.PutBucketAsync(putBucketRequest);
124119
}
125120

126121
return null;
127122
}
128-
129-
/// <summary>
130-
/// Executes an async <see cref="Task{TResult}"/> method which has
131-
/// a <paramref name="task"/> return type synchronously.
132-
/// <see href="https://github.com/aspnet/AspNetIdentity/blob/b7826741279450c58b230ece98bd04b4815beabf/src/Microsoft.AspNet.Identity.Core/AsyncHelper.cs"/>
133-
/// </summary>
134-
/// <typeparam name="TResult">The type of result to return.</typeparam>
135-
/// <param name="task">The task to excecute.</param>
136-
/// <returns>The <typeparamref name="TResult"/>.</returns>
137-
private static TResult RunSync<TResult>(Func<Task<TResult>> task)
138-
{
139-
CultureInfo cultureUi = CultureInfo.CurrentUICulture;
140-
CultureInfo culture = CultureInfo.CurrentCulture;
141-
return TaskFactory.StartNew(() =>
142-
{
143-
Thread.CurrentThread.CurrentCulture = culture;
144-
Thread.CurrentThread.CurrentUICulture = cultureUi;
145-
return task();
146-
}).Unwrap().GetAwaiter().GetResult();
147-
}
148123
}
149124
}

tests/ImageSharp.Web.Tests/TestUtilities/AWSS3StorageImageProviderFactory.cs

Lines changed: 16 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,13 @@
55
using System.IO;
66
using System.Linq;
77
using System.Net.Http.Headers;
8-
using Amazon;
8+
using System.Threading.Tasks;
99
using Amazon.S3;
1010
using Amazon.S3.Model;
1111
using Microsoft.AspNetCore.Hosting;
1212
using Microsoft.Extensions.DependencyInjection;
1313
using Microsoft.Extensions.FileProviders;
1414
using Microsoft.Extensions.Options;
15-
using SixLabors.ImageSharp.Web.Providers;
1615
using SixLabors.ImageSharp.Web.Providers.AWS;
1716

1817
namespace SixLabors.ImageSharp.Web.Tests.TestUtilities
@@ -23,44 +22,19 @@ public static AWSS3StorageImageProvider Create(IServiceProvider services)
2322
{
2423
IOptions<AWSS3StorageImageProviderOptions> options = services.GetRequiredService<IOptions<AWSS3StorageImageProviderOptions>>();
2524
FormatUtilities utilities = services.GetRequiredService<FormatUtilities>();
26-
InitializeAWSStorage(services, options.Value);
25+
AsyncHelper.RunSync(() => InitializeAWSStorageAsync(services, options.Value));
2726

2827
return new AWSS3StorageImageProvider(options, utilities);
2928
}
3029

31-
private static void InitializeAWSStorage(IServiceProvider services, AWSS3StorageImageProviderOptions options)
30+
private static async Task InitializeAWSStorageAsync(IServiceProvider services, AWSS3StorageImageProviderOptions options)
3231
{
3332
// Upload an image to the AWS Test Storage;
3433
AWSS3BucketClientOptions bucketOptions = options.S3Buckets.First();
35-
AmazonS3Client amazonS3Client = null;
36-
bool foundBucket = false;
37-
38-
if (!string.IsNullOrEmpty(bucketOptions.Endpoint) &&
39-
bucketOptions.AccessKey != null &&
40-
bucketOptions.AccessSecret != null)
41-
{
42-
var config = new AmazonS3Config
43-
{
44-
ServiceURL = bucketOptions.Endpoint,
45-
ForcePathStyle = true
46-
};
47-
amazonS3Client = new AmazonS3Client(string.Empty, string.Empty, config);
48-
}
49-
else if (!string.IsNullOrEmpty(bucketOptions.AccessKey) &&
50-
!string.IsNullOrEmpty(bucketOptions.AccessSecret) &&
51-
!string.IsNullOrEmpty(bucketOptions.Region))
52-
{
53-
var region = RegionEndpoint.GetBySystemName(bucketOptions.Region);
54-
amazonS3Client = new AmazonS3Client(bucketOptions.AccessKey, bucketOptions.AccessSecret, region);
55-
}
56-
else
57-
{
58-
var region = RegionEndpoint.GetBySystemName(bucketOptions.Region);
59-
amazonS3Client = new AmazonS3Client(region);
60-
}
61-
62-
ListBucketsResponse listBucketsResponse = amazonS3Client.ListBucketsAsync().GetAwaiter().GetResult();
34+
AmazonS3Client amazonS3Client = AmazonS3ClientFactory.CreateClient(bucketOptions);
35+
ListBucketsResponse listBucketsResponse = await amazonS3Client.ListBucketsAsync();
6336

37+
bool foundBucket = false;
6438
foreach (S3Bucket b in listBucketsResponse.Buckets)
6539
{
6640
if (b.BucketName == bucketOptions.BucketName)
@@ -79,7 +53,7 @@ private static void InitializeAWSStorage(IServiceProvider services, AWSS3Storage
7953
CannedACL = S3CannedACL.PublicRead
8054
};
8155

82-
amazonS3Client.PutBucketAsync(putBucketRequest).GetAwaiter().GetResult();
56+
await amazonS3Client.PutBucketAsync(putBucketRequest);
8357
}
8458

8559
#if NETCOREAPP2_1
@@ -88,22 +62,22 @@ private static void InitializeAWSStorage(IServiceProvider services, AWSS3Storage
8862
IWebHostEnvironment environment = services.GetRequiredService<IWebHostEnvironment>();
8963
#endif
9064

91-
var request = new GetObjectRequest()
92-
{
93-
BucketName = bucketOptions.BucketName,
94-
Key = TestConstants.ImagePath
95-
};
96-
9765
try
9866
{
99-
amazonS3Client.GetObjectAsync(request).GetAwaiter().GetResult();
67+
GetObjectRequest request = new()
68+
{
69+
BucketName = bucketOptions.BucketName,
70+
Key = TestConstants.ImagePath
71+
};
72+
73+
await amazonS3Client.GetObjectAsync(request);
10074
}
10175
catch
10276
{
10377
IFileInfo file = environment.WebRootFileProvider.GetFileInfo(TestConstants.ImagePath);
10478
using Stream stream = file.CreateReadStream();
10579

106-
// Set the max-age property so we get coverage for testing is in our Azure provider.
80+
// Set the max-age property so we get coverage for testing is in our AWS provider.
10781
var cacheControl = new CacheControlHeaderValue
10882
{
10983
Public = true,
@@ -123,7 +97,7 @@ private static void InitializeAWSStorage(IServiceProvider services, AWSS3Storage
12397
InputStream = stream
12498
};
12599

126-
amazonS3Client.PutObjectAsync(putRequest).GetAwaiter().GetResult();
100+
await amazonS3Client.PutObjectAsync(putRequest);
127101
}
128102
}
129103
}

0 commit comments

Comments
 (0)