diff --git a/Directory.Packages.props b/Directory.Packages.props
index 79222b5b3..62c4b4cb1 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -28,6 +28,7 @@
+
diff --git a/Testcontainers.sln b/Testcontainers.sln
index e8c10a811..51790f98f 100644
--- a/Testcontainers.sln
+++ b/Testcontainers.sln
@@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ActiveMq", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ArangoDb", "src\Testcontainers.ArangoDb\Testcontainers.ArangoDb.csproj", "{AB9C1563-07C7-4685-BACD-BB1FF64B3611}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.AzureAppConfiguration", "src\Testcontainers.AzureAppConfiguration\Testcontainers.AzureAppConfiguration.csproj", "{5C03BAF1-8CC7-421D-A457-9FBEF923E06E}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Azurite", "src\Testcontainers.Azurite\Testcontainers.Azurite.csproj", "{3F2E254F-C203-43FD-A078-DC3E2CBC0F9F}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.BigQuery", "src\Testcontainers.BigQuery\Testcontainers.BigQuery.csproj", "{A9FF9C7F-BBA0-4B44-90B7-48A60F9E00F3}"
@@ -105,6 +107,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ActiveMq.Tes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.ArangoDb.Tests", "tests\Testcontainers.ArangoDb.Tests\Testcontainers.ArangoDb.Tests.csproj", "{8E1E0A6D-EEBB-4455-B8E8-A55AF9B2062C}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.AzureAppConfiguration.Tests", "tests\Testcontainers.AzureAppConfiguration.Tests\Testcontainers.AzureAppConfiguration.Tests.csproj", "{A7C87D4E-540F-4AD2-8A42-C7F86700688D}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.Azurite.Tests", "tests\Testcontainers.Azurite.Tests\Testcontainers.Azurite.Tests.csproj", "{B272FDDE-5E01-425D-B9E1-10FF883DDAAA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Testcontainers.BigQuery.Tests", "tests\Testcontainers.BigQuery.Tests\Testcontainers.BigQuery.Tests.csproj", "{03E60673-078A-4508-99AD-8537CE6F78F1}"
@@ -580,6 +584,14 @@ Global
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5C03BAF1-8CC7-421D-A457-9FBEF923E06E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5C03BAF1-8CC7-421D-A457-9FBEF923E06E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5C03BAF1-8CC7-421D-A457-9FBEF923E06E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5C03BAF1-8CC7-421D-A457-9FBEF923E06E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A7C87D4E-540F-4AD2-8A42-C7F86700688D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A7C87D4E-540F-4AD2-8A42-C7F86700688D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A7C87D4E-540F-4AD2-8A42-C7F86700688D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A7C87D4E-540F-4AD2-8A42-C7F86700688D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{5365F780-0E6C-41F0-B1B9-7DC34368F80C} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
@@ -675,5 +687,7 @@ Global
{1A1983E6-5297-435F-B467-E8E1F11277D6} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{27CDB869-A150-4593-958F-6F26E5391E7C} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
{EBA72C3B-57D5-43FF-A5B4-3D55B3B6D4C2} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
+ {5C03BAF1-8CC7-421D-A457-9FBEF923E06E} = {673F23AE-7694-4BB9-ABD4-136D6C13634E}
+ {A7C87D4E-540F-4AD2-8A42-C7F86700688D} = {7164F1FB-7F24-444A-ACD2-2C329C2B3CCF}
EndGlobalSection
EndGlobal
diff --git a/src/Testcontainers.AzureAppConfiguration/.editorconfig b/src/Testcontainers.AzureAppConfiguration/.editorconfig
new file mode 100644
index 000000000..6f066619d
--- /dev/null
+++ b/src/Testcontainers.AzureAppConfiguration/.editorconfig
@@ -0,0 +1 @@
+root = true
\ No newline at end of file
diff --git a/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs b/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs
new file mode 100644
index 000000000..c2a00552b
--- /dev/null
+++ b/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationBuilder.cs
@@ -0,0 +1,108 @@
+namespace Testcontainers.AzureAppConfiguration;
+
+///
+[PublicAPI]
+public sealed class AzureAppConfigurationBuilder : ContainerBuilder
+{
+ public const string AzureAppConfigurationImage = "tnc1997/azure-app-configuration-emulator:1.0";
+
+ public const ushort AzureAppConfigurationPort = 8080;
+
+ public const string DefaultCredential = "abcd";
+
+ public const string DefaultSecret = "c2VjcmV0";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public AzureAppConfigurationBuilder()
+ : this(new AzureAppConfigurationConfiguration())
+ {
+ DockerResourceConfiguration = Init().DockerResourceConfiguration;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Docker resource configuration.
+ private AzureAppConfigurationBuilder(AzureAppConfigurationConfiguration resourceConfiguration)
+ : base(resourceConfiguration)
+ {
+ DockerResourceConfiguration = resourceConfiguration;
+ }
+
+ ///
+ protected override AzureAppConfigurationConfiguration DockerResourceConfiguration { get; }
+
+ ///
+ /// Sets the Azure App Configuration credential.
+ ///
+ /// The Azure App Configuration credential.
+ /// A configured instance of .
+ public AzureAppConfigurationBuilder WithCredential(string credential)
+ {
+ return Merge(DockerResourceConfiguration, new AzureAppConfigurationConfiguration(credential: credential))
+ .WithEnvironment("Authentication__Schemes__Hmac__Credential", credential);
+ }
+
+ ///
+ /// Sets the Azure App Configuration secret.
+ ///
+ /// The Azure App Configuration secret.
+ /// A configured instance of .
+ public AzureAppConfigurationBuilder WithSecret(string secret)
+ {
+ return Merge(DockerResourceConfiguration, new AzureAppConfigurationConfiguration(secret: secret))
+ .WithEnvironment("Authentication__Schemes__Hmac__Secret", secret);
+ }
+
+ ///
+ public override AzureAppConfigurationContainer Build()
+ {
+ Validate();
+ return new AzureAppConfigurationContainer(DockerResourceConfiguration);
+ }
+
+ ///
+ protected override AzureAppConfigurationBuilder Init()
+ {
+ return base.Init()
+ .WithImage(AzureAppConfigurationImage)
+ .WithPortBinding(AzureAppConfigurationPort, true)
+ .WithCredential(DefaultCredential)
+ .WithSecret(DefaultSecret)
+ .WithWaitStrategy(Wait.ForUnixContainer().UntilMessageIsLogged("Now listening on"));
+ }
+
+ ///
+ protected override void Validate()
+ {
+ base.Validate();
+
+ _ = Guard.Argument(DockerResourceConfiguration.Credential, nameof(DockerResourceConfiguration.Credential))
+ .NotNull()
+ .NotEmpty();
+
+ _ = Guard.Argument(DockerResourceConfiguration.Secret, nameof(DockerResourceConfiguration.Secret))
+ .NotNull()
+ .NotEmpty();
+ }
+
+ ///
+ protected override AzureAppConfigurationBuilder Clone(IResourceConfiguration resourceConfiguration)
+ {
+ return Merge(DockerResourceConfiguration, new AzureAppConfigurationConfiguration(resourceConfiguration));
+ }
+
+ ///
+ protected override AzureAppConfigurationBuilder Clone(IContainerConfiguration resourceConfiguration)
+ {
+ return Merge(DockerResourceConfiguration, new AzureAppConfigurationConfiguration(resourceConfiguration));
+ }
+
+ ///
+ protected override AzureAppConfigurationBuilder Merge(AzureAppConfigurationConfiguration oldValue, AzureAppConfigurationConfiguration newValue)
+ {
+ return new AzureAppConfigurationBuilder(new AzureAppConfigurationConfiguration(oldValue, newValue));
+ }
+}
\ No newline at end of file
diff --git a/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cs b/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cs
new file mode 100644
index 000000000..514c9a8e7
--- /dev/null
+++ b/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationConfiguration.cs
@@ -0,0 +1,69 @@
+namespace Testcontainers.AzureAppConfiguration;
+
+///
+[PublicAPI]
+public sealed class AzureAppConfigurationConfiguration : ContainerConfiguration
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Azure App Configuration credential.
+ /// The Azure App Configuration secret.
+ public AzureAppConfigurationConfiguration(string credential = null, string secret = null)
+ {
+ Credential = credential;
+ Secret = secret;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Docker resource configuration.
+ public AzureAppConfigurationConfiguration(IResourceConfiguration resourceConfiguration)
+ : base(resourceConfiguration)
+ {
+ // Passes the configuration upwards to the base implementations to create an updated immutable copy.
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Docker resource configuration.
+ public AzureAppConfigurationConfiguration(IContainerConfiguration resourceConfiguration)
+ : base(resourceConfiguration)
+ {
+ // Passes the configuration upwards to the base implementations to create an updated immutable copy.
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The Docker resource configuration.
+ public AzureAppConfigurationConfiguration(AzureAppConfigurationConfiguration resourceConfiguration)
+ : this(new AzureAppConfigurationConfiguration(), resourceConfiguration)
+ {
+ // Passes the configuration upwards to the base implementations to create an updated immutable copy.
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The old Docker resource configuration.
+ /// The new Docker resource configuration.
+ public AzureAppConfigurationConfiguration(AzureAppConfigurationConfiguration oldValue, AzureAppConfigurationConfiguration newValue)
+ : base(oldValue, newValue)
+ {
+ Credential = BuildConfiguration.Combine(oldValue.Credential, newValue.Credential);
+ Secret = BuildConfiguration.Combine(oldValue.Secret, newValue.Secret);
+ }
+
+ ///
+ /// Gets the Azure App Configuration credential.
+ ///
+ public string Credential { get; }
+
+ ///
+ /// Gets the Azure App Configuration secret.
+ ///
+ public string Secret { get; }
+}
\ No newline at end of file
diff --git a/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs b/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs
new file mode 100644
index 000000000..3c1a95765
--- /dev/null
+++ b/src/Testcontainers.AzureAppConfiguration/AzureAppConfigurationContainer.cs
@@ -0,0 +1,31 @@
+namespace Testcontainers.AzureAppConfiguration;
+
+///
+[PublicAPI]
+public sealed class AzureAppConfigurationContainer : DockerContainer
+{
+ private readonly AzureAppConfigurationConfiguration _configuration;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The container configuration.
+ public AzureAppConfigurationContainer(AzureAppConfigurationConfiguration configuration)
+ : base(configuration)
+ {
+ _configuration = configuration;
+ }
+
+ ///
+ /// Gets the Azure App Configuration connection string.
+ ///
+ /// The Azure App Configuration connection string.
+ public string GetConnectionString()
+ {
+ var properties = new Dictionary();
+ properties.Add("Endpoint", new UriBuilder(Uri.UriSchemeHttp, Hostname, GetMappedPublicPort(AzureAppConfigurationBuilder.AzureAppConfigurationPort)).ToString());
+ properties.Add("Id", _configuration.Credential);
+ properties.Add("Secret", _configuration.Secret);
+ return string.Join(";", properties.Select(property => string.Join("=", property.Key, property.Value)));
+ }
+}
\ No newline at end of file
diff --git a/src/Testcontainers.AzureAppConfiguration/Testcontainers.AzureAppConfiguration.csproj b/src/Testcontainers.AzureAppConfiguration/Testcontainers.AzureAppConfiguration.csproj
new file mode 100644
index 000000000..f23847217
--- /dev/null
+++ b/src/Testcontainers.AzureAppConfiguration/Testcontainers.AzureAppConfiguration.csproj
@@ -0,0 +1,12 @@
+
+
+ net6.0;net8.0;netstandard2.0;netstandard2.1
+ latest
+
+
+
+
+
+
+
+
diff --git a/src/Testcontainers.AzureAppConfiguration/Usings.cs b/src/Testcontainers.AzureAppConfiguration/Usings.cs
new file mode 100644
index 000000000..7a7b31226
--- /dev/null
+++ b/src/Testcontainers.AzureAppConfiguration/Usings.cs
@@ -0,0 +1,9 @@
+global using System;
+global using System.Collections.Generic;
+global using System.Linq;
+global using Docker.DotNet.Models;
+global using DotNet.Testcontainers;
+global using DotNet.Testcontainers.Builders;
+global using DotNet.Testcontainers.Configurations;
+global using DotNet.Testcontainers.Containers;
+global using JetBrains.Annotations;
\ No newline at end of file
diff --git a/tests/Testcontainers.AzureAppConfiguration.Tests/.editorconfig b/tests/Testcontainers.AzureAppConfiguration.Tests/.editorconfig
new file mode 100644
index 000000000..6f066619d
--- /dev/null
+++ b/tests/Testcontainers.AzureAppConfiguration.Tests/.editorconfig
@@ -0,0 +1 @@
+root = true
\ No newline at end of file
diff --git a/tests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cs b/tests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cs
new file mode 100644
index 000000000..0f00f5dd0
--- /dev/null
+++ b/tests/Testcontainers.AzureAppConfiguration.Tests/AzureAppConfigurationContainerTest.cs
@@ -0,0 +1,34 @@
+namespace Testcontainers.AzureAppConfiguration;
+
+public sealed class AzureAppConfigurationContainerTest : IAsyncLifetime
+{
+ private readonly AzureAppConfigurationContainer _azureAppConfigurationContainer = new AzureAppConfigurationBuilder().Build();
+
+ public Task InitializeAsync()
+ {
+ return _azureAppConfigurationContainer.StartAsync();
+ }
+
+ public Task DisposeAsync()
+ {
+ return _azureAppConfigurationContainer.DisposeAsync().AsTask();
+ }
+
+ [Fact]
+ [Trait(nameof(DockerCli.DockerPlatform), nameof(DockerCli.DockerPlatform.Linux))]
+ public async Task GetConfigurationSettingReturnsSetConfigurationSetting()
+ {
+ // Given
+ var client = new ConfigurationClient(_azureAppConfigurationContainer.GetConnectionString());
+
+ // When
+ await client.SetConfigurationSettingAsync(nameof(ConfigurationSetting.Key), nameof(ConfigurationSetting.Value))
+ .ConfigureAwait(true);
+
+ var response = await client.GetConfigurationSettingAsync(nameof(ConfigurationSetting.Key))
+ .ConfigureAwait(true);
+
+ // Then
+ Assert.Equal(nameof(ConfigurationSetting.Value), response.Value.Value);
+ }
+}
\ No newline at end of file
diff --git a/tests/Testcontainers.AzureAppConfiguration.Tests/Testcontainers.AzureAppConfiguration.Tests.csproj b/tests/Testcontainers.AzureAppConfiguration.Tests/Testcontainers.AzureAppConfiguration.Tests.csproj
new file mode 100644
index 000000000..f3d1dfff6
--- /dev/null
+++ b/tests/Testcontainers.AzureAppConfiguration.Tests/Testcontainers.AzureAppConfiguration.Tests.csproj
@@ -0,0 +1,18 @@
+
+
+ net8.0
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/Testcontainers.AzureAppConfiguration.Tests/Usings.cs b/tests/Testcontainers.AzureAppConfiguration.Tests/Usings.cs
new file mode 100644
index 000000000..9366fb9a1
--- /dev/null
+++ b/tests/Testcontainers.AzureAppConfiguration.Tests/Usings.cs
@@ -0,0 +1,4 @@
+global using System.Threading.Tasks;
+global using Azure.Data.AppConfiguration;
+global using DotNet.Testcontainers.Commons;
+global using Xunit;
\ No newline at end of file