Skip to content

Commit 4353568

Browse files
Merge pull request #91 from SixLabors/js/multiple-azure
Add Support for Multiple Azure Connections and Containers.
2 parents 22e193b + f7fc293 commit 4353568

File tree

4 files changed

+83
-16
lines changed

4 files changed

+83
-16
lines changed

ImageSharp.Web.sln

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{B815
4545
EndProjectSection
4646
EndProject
4747
Global
48+
GlobalSection(SharedMSBuildProjectFiles) = preSolution
49+
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{2f1b36e2-5d92-4442-b816-d2a978246435}*SharedItemsImports = 5
50+
shared-infrastructure\src\SharedInfrastructure\SharedInfrastructure.projitems*{e2a545ec-b909-4ead-b95f-397f68588be3}*SharedItemsImports = 5
51+
EndGlobalSection
4852
GlobalSection(SolutionConfigurationPlatforms) = preSolution
4953
Debug|Any CPU = Debug|Any CPU
5054
Debug|x64 = Debug|x64

src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProvider.cs

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Threading.Tasks;
67
using Azure.Storage.Blobs;
78
using Microsoft.AspNetCore.Http;
@@ -22,9 +23,10 @@ public class AzureBlobStorageImageProvider : IImageProvider
2223
private static readonly char[] SlashChars = { '\\', '/' };
2324

2425
/// <summary>
25-
/// The container in the blob service.
26+
/// The containers for the blob services.
2627
/// </summary>
27-
private readonly BlobContainerClient container;
28+
private readonly Dictionary<string, BlobContainerClient> containers
29+
= new Dictionary<string, BlobContainerClient>();
2830

2931
/// <summary>
3032
/// The blob storage options.
@@ -55,7 +57,12 @@ public AzureBlobStorageImageProvider(
5557
this.storageOptions = storageOptions.Value;
5658
this.formatUtilities = formatUtilities;
5759

58-
this.container = new BlobContainerClient(this.storageOptions.ConnectionString, this.storageOptions.ContainerName);
60+
foreach (AzureBlobContainerClientOptions container in this.storageOptions.BlobContainers)
61+
{
62+
this.containers.Add(
63+
container.ContainerName,
64+
new BlobContainerClient(container.ConnectionString, container.ContainerName));
65+
}
5966
}
6067

6168
/// <inheritdoc/>
@@ -74,16 +81,40 @@ public async Task<IImageResolver> GetAsync(HttpContext context)
7481
// Strip the leading slash and container name from the HTTP request path and treat
7582
// the remaining path string as the blob name.
7683
// Path has already been correctly parsed before here.
77-
string blobName = context.Request.Path.Value.TrimStart(SlashChars)
78-
.Substring(this.storageOptions.ContainerName.Length)
79-
.TrimStart(SlashChars);
84+
string containerName = string.Empty;
85+
BlobContainerClient container = null;
86+
87+
// We want an exact match here to ensure that container names starting with
88+
// the same prefix are not mixed up.
89+
string path = context.Request.Path.Value.TrimStart(SlashChars);
90+
int index = path.IndexOfAny(SlashChars);
91+
string nameToMatch = index != -1 ? path.Substring(index) : path;
92+
93+
foreach (string key in this.containers.Keys)
94+
{
95+
if (nameToMatch.Equals(key, StringComparison.OrdinalIgnoreCase))
96+
{
97+
containerName = key;
98+
container = this.containers[key];
99+
break;
100+
}
101+
}
102+
103+
// Something has gone horribly wrong for this to happen but check anyway.
104+
if (container is null)
105+
{
106+
return null;
107+
}
108+
109+
// Blob name should be the remaining path string.
110+
string blobName = path.Substring(containerName.Length).TrimStart(SlashChars);
80111

81112
if (string.IsNullOrWhiteSpace(blobName))
82113
{
83114
return null;
84115
}
85116

86-
BlobClient blob = this.container.GetBlobClient(blobName);
117+
BlobClient blob = container.GetBlobClient(blobName);
87118

88119
if (!await blob.ExistsAsync())
89120
{
@@ -99,8 +130,18 @@ public bool IsValidRequest(HttpContext context)
99130

100131
private bool IsMatch(HttpContext context)
101132
{
133+
// Only match loosly here for performance.
134+
// Path matching conflicts should be dealt with by configuration.
102135
string path = context.Request.Path.Value.TrimStart(SlashChars);
103-
return path.StartsWith(this.storageOptions.ContainerName, StringComparison.OrdinalIgnoreCase);
136+
foreach (string container in this.containers.Keys)
137+
{
138+
if (path.StartsWith(container, StringComparison.OrdinalIgnoreCase))
139+
{
140+
return true;
141+
}
142+
}
143+
144+
return false;
104145
}
105146
}
106147
}

src/ImageSharp.Web.Providers.Azure/Providers/AzureBlobStorageImageProviderOptions.cs

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

4+
using System.Collections.Generic;
5+
46
namespace SixLabors.ImageSharp.Web.Providers
57
{
68
/// <summary>
@@ -9,12 +11,23 @@ namespace SixLabors.ImageSharp.Web.Providers
911
public class AzureBlobStorageImageProviderOptions
1012
{
1113
/// <summary>
12-
/// Gets or sets the connection string.
14+
/// Gets or sets the collection of blob container client options.
15+
/// </summary>
16+
public ICollection<AzureBlobContainerClientOptions> BlobContainers { get; set; } = new HashSet<AzureBlobContainerClientOptions>();
17+
}
18+
19+
/// <summary>
20+
/// Represents a single Azure Blob Storage connection and container.
21+
/// </summary>
22+
public class AzureBlobContainerClientOptions
23+
{
24+
/// <summary>
25+
/// Gets or sets the Azure Blob Storage connection string.
1326
/// </summary>
1427
public string ConnectionString { get; set; }
1528

1629
/// <summary>
17-
/// Gets or sets the container name.
30+
/// Gets or sets the Azure Blob Storage container name.
1831
/// Must conform to Azure Blob Storage containiner naming guidlines.
1932
/// <see href="https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names"/>
2033
/// </summary>

tests/ImageSharp.Web.Tests/ImageSharpTestServer.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ public static class ImageSharpTestServer
5353
.AddProvider(PhysicalProviderFactory)
5454
.Configure<AzureBlobStorageImageProviderOptions>(options =>
5555
{
56-
options.ConnectionString = AzureConnectionString;
57-
options.ContainerName = AzureContainerName;
56+
options.BlobContainers.Add(new AzureBlobContainerClientOptions
57+
{
58+
ConnectionString = AzureConnectionString,
59+
ContainerName = AzureContainerName
60+
});
5861
})
5962
.AddProvider<AzureBlobStorageImageProvider>()
6063
.AddProcessor<ResizeWebProcessor>();
@@ -80,8 +83,11 @@ public static class ImageSharpTestServer
8083
.SetCacheHash<CacheHash>()
8184
.Configure<AzureBlobStorageImageProviderOptions>(options =>
8285
{
83-
options.ConnectionString = AzureConnectionString;
84-
options.ContainerName = AzureContainerName;
86+
options.BlobContainers.Add(new AzureBlobContainerClientOptions
87+
{
88+
ConnectionString = AzureConnectionString,
89+
ContainerName = AzureContainerName
90+
});
8591
})
8692
.AddProvider<AzureBlobStorageImageProvider>()
8793
.AddProcessor<ResizeWebProcessor>();
@@ -116,8 +122,11 @@ void ConfigureServices(IServiceCollection services)
116122
.AddProvider(PhysicalProviderFactory)
117123
.Configure<AzureBlobStorageImageProviderOptions>(options =>
118124
{
119-
options.ConnectionString = AzureConnectionString;
120-
options.ContainerName = AzureContainerName;
125+
options.BlobContainers.Add(new AzureBlobContainerClientOptions
126+
{
127+
ConnectionString = AzureConnectionString,
128+
ContainerName = AzureContainerName
129+
});
121130
})
122131
.AddProvider<AzureBlobStorageImageProvider>()
123132
.AddProcessor<ResizeWebProcessor>();

0 commit comments

Comments
 (0)