Skip to content

Commit 44689d3

Browse files
authored
Add DbGate support for Redis (#471)
* Add DbGate support for redis * Add tests * Update READEME * Update CODEOWNERS
1 parent 559ccd4 commit 44689d3

File tree

19 files changed

+508
-2
lines changed

19 files changed

+508
-2
lines changed

CODEOWNERS

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,4 +92,9 @@
9292
# CommunityToolkit.Aspire.Hosting.MongoDB.Extensions
9393
/src/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions/ @Alirexaa
9494
/tests/CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.Tests/ @Alirexaa
95-
/examples/mongodb-ext/ @Alirexaa
95+
/examples/mongodb-ext/ @Alirexaa
96+
97+
# CommunityToolkit.Aspire.Hosting.Redis.Extensions
98+
/src/CommunityToolkit.Aspire.Hosting.Redis.Extensions/ @Alirexaa
99+
/tests/CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests/ @Alirexaa
100+
/examples/redis-ext/ @Alirexaa

CommunityToolkit.Aspire.sln

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "dbgate", "dbgate", "{50FBAF
317317
EndProject
318318
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.DbGate.AppHost", "examples\dbgate\CommunityToolkit.Aspire.Hosting.DbGate.AppHost\CommunityToolkit.Aspire.Hosting.DbGate.AppHost.csproj", "{AFEAF08C-4959-4CF2-8806-4E75F8F73B2E}"
319319
EndProject
320+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.Redis.Extensions", "src\CommunityToolkit.Aspire.Hosting.Redis.Extensions\CommunityToolkit.Aspire.Hosting.Redis.Extensions.csproj", "{50D628FD-9E2B-4ECB-B219-FBC008A5EBDA}"
321+
EndProject
322+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.Redis.Extensions.AppHost", "examples\redis-ext\CommunityToolkit.Aspire.Hosting.Redis.Extensions.AppHost\CommunityToolkit.Aspire.Hosting.Redis.Extensions.AppHost.csproj", "{CB491C52-A3D5-4F36-97C4-75C482F90A30}"
323+
EndProject
324+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "redis-ext", "redis-ext", "{734EF69D-EE4D-4E9B-96BD-A44E53C5D1EC}"
325+
EndProject
326+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests", "tests\CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests\CommunityToolkit.Aspire.Hosting.Redis.Extensions.Tests.csproj", "{958A251E-9D2A-4D67-9D1C-47D6A9E36B3A}"
327+
EndProject
320328
Global
321329
GlobalSection(SolutionConfigurationPlatforms) = preSolution
322330
Debug|Any CPU = Debug|Any CPU
@@ -835,6 +843,18 @@ Global
835843
{AFEAF08C-4959-4CF2-8806-4E75F8F73B2E}.Debug|Any CPU.Build.0 = Debug|Any CPU
836844
{AFEAF08C-4959-4CF2-8806-4E75F8F73B2E}.Release|Any CPU.ActiveCfg = Release|Any CPU
837845
{AFEAF08C-4959-4CF2-8806-4E75F8F73B2E}.Release|Any CPU.Build.0 = Release|Any CPU
846+
{50D628FD-9E2B-4ECB-B219-FBC008A5EBDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
847+
{50D628FD-9E2B-4ECB-B219-FBC008A5EBDA}.Debug|Any CPU.Build.0 = Debug|Any CPU
848+
{50D628FD-9E2B-4ECB-B219-FBC008A5EBDA}.Release|Any CPU.ActiveCfg = Release|Any CPU
849+
{50D628FD-9E2B-4ECB-B219-FBC008A5EBDA}.Release|Any CPU.Build.0 = Release|Any CPU
850+
{CB491C52-A3D5-4F36-97C4-75C482F90A30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
851+
{CB491C52-A3D5-4F36-97C4-75C482F90A30}.Debug|Any CPU.Build.0 = Debug|Any CPU
852+
{CB491C52-A3D5-4F36-97C4-75C482F90A30}.Release|Any CPU.ActiveCfg = Release|Any CPU
853+
{CB491C52-A3D5-4F36-97C4-75C482F90A30}.Release|Any CPU.Build.0 = Release|Any CPU
854+
{958A251E-9D2A-4D67-9D1C-47D6A9E36B3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
855+
{958A251E-9D2A-4D67-9D1C-47D6A9E36B3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
856+
{958A251E-9D2A-4D67-9D1C-47D6A9E36B3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
857+
{958A251E-9D2A-4D67-9D1C-47D6A9E36B3A}.Release|Any CPU.Build.0 = Release|Any CPU
838858
EndGlobalSection
839859
GlobalSection(SolutionProperties) = preSolution
840860
HideSolutionNode = FALSE
@@ -994,6 +1014,10 @@ Global
9941014
{A461FE7E-2458-428C-B794-6CC388031F16} = {8406E585-3329-48C5-B268-8C2140B720B6}
9951015
{50FBAF3E-E0BB-44FF-884F-660357C1CC54} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
9961016
{AFEAF08C-4959-4CF2-8806-4E75F8F73B2E} = {50FBAF3E-E0BB-44FF-884F-660357C1CC54}
1017+
{50D628FD-9E2B-4ECB-B219-FBC008A5EBDA} = {414151D4-7009-4E78-A5C6-D99EBD1E67D1}
1018+
{CB491C52-A3D5-4F36-97C4-75C482F90A30} = {734EF69D-EE4D-4E9B-96BD-A44E53C5D1EC}
1019+
{734EF69D-EE4D-4E9B-96BD-A44E53C5D1EC} = {8519CC01-1370-47C8-AD94-B0F326B1563F}
1020+
{958A251E-9D2A-4D67-9D1C-47D6A9E36B3A} = {899F0713-7FC6-4750-BAFC-AC650B35B453}
9971021
EndGlobalSection
9981022
GlobalSection(ExtensibilityGlobals) = postSolution
9991023
SolutionGuid = {08B1D4B8-D2C5-4A64-BB8B-E1A2B29525F0}

Directory.Packages.props

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<PackageVersion Include="Aspire.Hosting.PostgreSQL" Version="$(AspireVersion)" />
1313
<PackageVersion Include="Aspire.Hosting.Python" Version="$(AspireVersion)" />
1414
<PackageVersion Include="Aspire.Hosting.Rabbitmq" Version="$(AspireVersion)" />
15+
<PackageVersion Include="Aspire.Hosting.Redis" Version="$(AspireVersion)" />
1516
<PackageVersion Include="Aspire.Hosting.MongoDB" Version="$(AspireVersion)" />
1617
<PackageVersion Include="Aspire.Hosting.SqlServer" Version="$(AspireVersion)" />
1718
<!-- AspNetCore packages -->

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ This repository contains the source code for the .NET Aspire Community Toolkit,
4242
| - **Learn More**: [`GoFeatureFlag`][go-feature-flag-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.GoFeatureFlag][go-feature-flag-client-shields]][go-feature-flag-client-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.GoFeatureFlag][go-feature-flag-client-shields-preview]][go-feature-flag-client-nuget-preview] | An Aspire client integration for the [GoFeatureFlag](https://github.com/open-feature/dotnet-sdk-contrib/tree/main/src/OpenFeature.Contrib.Providers.GOFeatureFlag) package. |
4343
| - **Learn More**: [`Hosting.MongoDB.Extensions`][mongodb-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.MongoDB.Extensions][mongodb-ext-shields]][mongodb-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.MongoDB.Extensions][mongodb-ext-shields-preview]][mongodb-ext-nuget-preview] | An integration that contains some additional extensions for hosting MongoDB container. |
4444
| - **Learn More**: [`Hosting.PostgreSQL.Extensions`][postgres-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.PostgreSQL.Extensions][postgres-ext-shields]][postgres-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions][postgres-ext-shields-preview]][postgres-ext-nuget-preview] | An integration that contains some additional extensions for hosting PostgreSQL container. |
45+
| - **Learn More**: [`Hosting.Redis.Extensions`][redis-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Redis.Extensions][redis-ext-shields]][redis-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Redis.Extensions][redis-ext-shields-preview]][redis-ext-nuget-preview] | An integration that contains some additional extensions for hosting Redis container. |
4546

4647
## 🙌 Getting Started
4748

@@ -216,3 +217,8 @@ This project is supported by the [.NET Foundation](https://dotnetfoundation.org)
216217
[postgres-ext-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/
217218
[postgres-ext-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions?label=nuget%20(preview)
218219
[postgres-ext-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/absoluteLatest
220+
[redis-ext-integration-docs]: https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-redis-extensions
221+
[redis-ext-shields]: https://img.shields.io/nuget/v/CommunityToolkit.Aspire.Hosting.Redis.Extensions
222+
[redis-ext-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Redis.Extensions/
223+
[redis-ext-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Redis.Extensions?label=nuget%20(preview)
224+
[redis-ext-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Redis.Extensions/absoluteLatest

examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost/CommunityToolkit.Aspire.Hosting.DbGate.AppHost.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.DbGate\CommunityToolkit.Aspire.Hosting.DbGate.csproj" IsAspireProjectResource="false" />
1717
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.MongoDB.Extensions\CommunityToolkit.Aspire.Hosting.MongoDB.Extensions.csproj" IsAspireProjectResource="false" />
1818
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions\CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj" IsAspireProjectResource="false" />
19+
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.Redis.Extensions\CommunityToolkit.Aspire.Hosting.Redis.Extensions.csproj" IsAspireProjectResource="false" />
1920
</ItemGroup>
2021

2122

examples/dbgate/CommunityToolkit.Aspire.Hosting.DbGate.AppHost/Program.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,7 @@
1818
mongodb2.AddDatabase("db7");
1919
mongodb2.AddDatabase("db8");
2020

21+
var redis1 = builder.AddRedis("redis1").WithDbGate();
22+
var redis2 = builder.AddRedis("redis2").WithDbGate();
23+
2124
builder.Build().Run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<Sdk Name="Aspire.AppHost.Sdk" Version="$(AspireAppHostSdkVersion)" />
3+
4+
<PropertyGroup>
5+
<OutputType>Exe</OutputType>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<IsAspireHost>true</IsAspireHost>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="Aspire.Hosting.AppHost" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.Redis.Extensions\CommunityToolkit.Aspire.Hosting.Redis.Extensions.csproj" IsAspireProjectResource="false" />
17+
</ItemGroup>
18+
19+
20+
</Project>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
var builder = DistributedApplication.CreateBuilder(args);
2+
3+
builder.AddRedis("redis1").WithDbGate(c => c.WithHostPort(8068));
4+
builder.AddRedis("redis2").WithDbGate();
5+
6+
builder.Build().Run();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"$schema": "https://json.schemastore.org/launchsettings.json",
3+
"profiles": {
4+
"https": {
5+
"commandName": "Project",
6+
"dotnetRunMessages": true,
7+
"launchBrowser": true,
8+
"applicationUrl": "https://localhost:17271;http://localhost:15267",
9+
"environmentVariables": {
10+
"ASPNETCORE_ENVIRONMENT": "Development",
11+
"DOTNET_ENVIRONMENT": "Development",
12+
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21222",
13+
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22001"
14+
}
15+
},
16+
"http": {
17+
"commandName": "Project",
18+
"dotnetRunMessages": true,
19+
"launchBrowser": true,
20+
"applicationUrl": "http://localhost:15267",
21+
"environmentVariables": {
22+
"ASPNETCORE_ENVIRONMENT": "Development",
23+
"DOTNET_ENVIRONMENT": "Development",
24+
"DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19048",
25+
"DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20086"
26+
}
27+
}
28+
}
29+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning",
6+
"Aspire.Hosting.Dcp": "Warning"
7+
}
8+
}
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<AdditionalPackageTags>hosting redis dbgate</AdditionalPackageTags>
5+
<Description>A .NET Aspire integration for extending redis hosting.</Description>
6+
</PropertyGroup>
7+
8+
<ItemGroup>
9+
<PackageReference Include="Aspire.Hosting" />
10+
<PackageReference Include="Aspire.Hosting.Redis" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<Compile Include="$(SharedDir)\VolumeNameGenerator.cs" Link="Utils\VolumeNameGenerator.cs" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<ProjectReference Include="..\CommunityToolkit.Aspire.Hosting.DbGate\CommunityToolkit.Aspire.Hosting.DbGate.csproj" />
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#nullable enable
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Aspire.Hosting.RedisBuilderExtensions
2+
static Aspire.Hosting.RedisBuilderExtensions.WithDbGate(this Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.RedisResource!>! builder, System.Action<Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.DbGateContainerResource!>!>? configureContainer = null, string? containerName = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder<Aspire.Hosting.ApplicationModel.RedisResource!>!
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# CommunityToolkit.Aspire.Hosting.Redis.Extensions library
2+
3+
This integration contains extensions for the [Redis hosting package](https://nuget.org/packages/Aspire.Hosting.Redis) for .NET Aspire.
4+
5+
The integration provides support for running [DbGate](https://github.com/dbgate/dbgate) to interact with the Redis database.
6+
7+
## Getting Started
8+
9+
### Install the package
10+
11+
In your AppHost project, install the package using the following command:
12+
13+
```dotnetcli
14+
dotnet add package CommunityToolkit.Aspire.Hosting.Redis.Extensions
15+
```
16+
17+
### Example usage
18+
19+
Then, in the _Program.cs_ file of `AppHost`, define an Redis resource, then call `AddRedis`:
20+
21+
```csharp
22+
var redis = builder.AddRedis("redis")
23+
.WithDbGate();
24+
```
25+
26+
## Additional Information
27+
28+
https://learn.microsoft.com/dotnet/aspire/community-toolkit/hosting-redis-extensions
29+
30+
## Feedback & contributing
31+
32+
https://github.com/CommunityToolkit/Aspire
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
using Aspire.Hosting.ApplicationModel;
2+
using System.Text;
3+
4+
namespace Aspire.Hosting;
5+
6+
/// <summary>
7+
/// Provides extension methods for adding Redis resources to an <see cref="IDistributedApplicationBuilder"/>.
8+
/// </summary>
9+
public static class RedisBuilderExtensions
10+
{
11+
/// <summary>
12+
/// Adds an administration and development platform for Redis to the application model using DbGate.
13+
/// </summary>
14+
/// <remarks>
15+
/// This version of the package defaults to the <inheritdoc cref="DbGateContainerImageTags.Tag"/> tag of the <inheritdoc cref="DbGateContainerImageTags.Image"/> container image.
16+
/// </remarks>
17+
/// <param name="builder">The Redis server resource builder.</param>
18+
/// <param name="configureContainer">Configuration callback for DbGate container resource.</param>
19+
/// <param name="containerName">The name of the container (Optional).</param>
20+
/// <example>
21+
/// Use in application host with a Redis resource
22+
/// <code lang="csharp">
23+
/// var builder = DistributedApplication.CreateBuilder(args);
24+
///
25+
/// var redis = builder.AddRedis("redis")
26+
/// .WithDbGate();
27+
///
28+
/// var api = builder.AddProject&lt;Projects.Api&gt;("api")
29+
/// .WithReference(redis);
30+
///
31+
/// builder.Build().Run();
32+
/// </code>
33+
/// </example>
34+
/// <returns>A reference to the <see cref="IResourceBuilder{T}"/>.</returns>
35+
public static IResourceBuilder<RedisResource> WithDbGate(this IResourceBuilder<RedisResource> builder, Action<IResourceBuilder<DbGateContainerResource>>? configureContainer = null, string? containerName = null)
36+
{
37+
ArgumentNullException.ThrowIfNull(builder);
38+
39+
containerName ??= $"{builder.Resource.Name}-dbgate";
40+
41+
var dbGateBuilder = DbGateBuilderExtensions.AddDbGate(builder.ApplicationBuilder, containerName);
42+
43+
dbGateBuilder
44+
.WithEnvironment(context => ConfigureDbGateContainer(context, builder.ApplicationBuilder))
45+
.WaitFor(builder);
46+
47+
configureContainer?.Invoke(dbGateBuilder);
48+
49+
return builder;
50+
}
51+
52+
private static void ConfigureDbGateContainer(EnvironmentCallbackContext context, IDistributedApplicationBuilder applicationBuilder)
53+
{
54+
var reidsInstances = applicationBuilder.Resources.OfType<RedisResource>();
55+
56+
var counter = 1;
57+
58+
// Multiple WithDbGate calls will be ignored
59+
if (context.EnvironmentVariables.ContainsKey($"LABEL_redis{counter}"))
60+
{
61+
return;
62+
}
63+
64+
foreach (var redisResource in reidsInstances)
65+
{
66+
67+
// DbGate assumes Redis is being accessed over a default Aspire container network and hardcodes the resource address
68+
// This will need to be refactored once updated service discovery APIs are available
69+
context.EnvironmentVariables.Add($"LABEL_redis{counter}", redisResource.Name);
70+
context.EnvironmentVariables.Add($"URL_redis{counter}", redisResource.ConnectionStringExpression);
71+
context.EnvironmentVariables.Add($"ENGINE_redis{counter}", "redis@dbgate-plugin-redis");
72+
73+
counter++;
74+
}
75+
76+
var instancesCount = reidsInstances.Count();
77+
if (instancesCount > 0)
78+
{
79+
var strBuilder = new StringBuilder();
80+
strBuilder.AppendJoin(',', Enumerable.Range(1, instancesCount).Select(i => $"redis{i}"));
81+
var connections = strBuilder.ToString();
82+
83+
string CONNECTIONS = context.EnvironmentVariables.GetValueOrDefault("CONNECTIONS")?.ToString() ?? string.Empty;
84+
if (string.IsNullOrEmpty(CONNECTIONS))
85+
{
86+
context.EnvironmentVariables["CONNECTIONS"] = connections;
87+
}
88+
else
89+
{
90+
context.EnvironmentVariables["CONNECTIONS"] += $",{connections}";
91+
}
92+
}
93+
}
94+
}

0 commit comments

Comments
 (0)