Skip to content

Commit

Permalink
Add more RunWith/PublishWith extension methods (#9)
Browse files Browse the repository at this point in the history
* Add RunWith/PublishWith methods for IResourceBuilder<ContainerResource>

* MORE EXTENSION METHODS

* Some more extension methods

* Add Aspirant.Hosting.Redis
  • Loading branch information
DamianEdwards authored Jun 2, 2024
1 parent 827d194 commit a8e5337
Show file tree
Hide file tree
Showing 9 changed files with 1,035 additions and 5 deletions.
17 changes: 12 additions & 5 deletions Aspirant.sln
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WebApplication2", "samples\
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{25313666-00D4-4FD9-9759-49D96BE94BEC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SamplesTests", "tests\SamplesTests\SamplesTests.csproj", "{B9B6EF97-17DE-4E0B-B1CF-2F5134F5558E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SamplesTests", "tests\SamplesTests\SamplesTests.csproj", "{B9B6EF97-17DE-4E0B-B1CF-2F5134F5558E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspirant.Hosting.Yarp", "src\Aspirant.Hosting.Yarp\Aspirant.Hosting.Yarp.csproj", "{82915081-DF0A-49E3-A310-FD356DC508FA}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspirant.Hosting.Yarp", "src\Aspirant.Hosting.Yarp\Aspirant.Hosting.Yarp.csproj", "{82915081-DF0A-49E3-A310-FD356DC508FA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspirant.Hosting.Testing", "src\Aspirant.Hosting.Testing\Aspirant.Hosting.Testing.csproj", "{9A87F6D8-2C5C-4365-8201-1EF8EFC58771}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspirant.Hosting.Testing", "src\Aspirant.Hosting.Testing\Aspirant.Hosting.Testing.csproj", "{9A87F6D8-2C5C-4365-8201-1EF8EFC58771}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspirant.Hosting.Testing.xunit", "src\Aspirant.Hosting.Testing.xunit\Aspirant.Hosting.Testing.xunit.csproj", "{3DC79FE3-C731-48AF-9F46-958FA3866C2B}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspirant.Hosting.Testing.xunit", "src\Aspirant.Hosting.Testing.xunit\Aspirant.Hosting.Testing.xunit.csproj", "{3DC79FE3-C731-48AF-9F46-958FA3866C2B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspirant.Hosting.UnitTests", "tests\Aspirant.Hosting.UnitTests\Aspirant.Hosting.UnitTests.csproj", "{C298B315-F532-4135-8B56-40CCE3AD3B82}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Aspirant.Hosting.UnitTests", "tests\Aspirant.Hosting.UnitTests\Aspirant.Hosting.UnitTests.csproj", "{C298B315-F532-4135-8B56-40CCE3AD3B82}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Aspirant.Hosting.Redis", "src\Aspirant.Hosting.Redis\Aspirant.Hosting.Redis.csproj", "{1A0397EA-A6C6-468B-A111-253EE6EA17A1}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -86,6 +88,10 @@ Global
{C298B315-F532-4135-8B56-40CCE3AD3B82}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C298B315-F532-4135-8B56-40CCE3AD3B82}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C298B315-F532-4135-8B56-40CCE3AD3B82}.Release|Any CPU.Build.0 = Release|Any CPU
{1A0397EA-A6C6-468B-A111-253EE6EA17A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A0397EA-A6C6-468B-A111-253EE6EA17A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A0397EA-A6C6-468B-A111-253EE6EA17A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A0397EA-A6C6-468B-A111-253EE6EA17A1}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -102,6 +108,7 @@ Global
{9A87F6D8-2C5C-4365-8201-1EF8EFC58771} = {6E773CFD-9758-4C09-96F6-5EDCED0E3A34}
{3DC79FE3-C731-48AF-9F46-958FA3866C2B} = {6E773CFD-9758-4C09-96F6-5EDCED0E3A34}
{C298B315-F532-4135-8B56-40CCE3AD3B82} = {25313666-00D4-4FD9-9759-49D96BE94BEC}
{1A0397EA-A6C6-468B-A111-253EE6EA17A1} = {6E773CFD-9758-4C09-96F6-5EDCED0E3A34}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {52627286-38AF-4E95-BDA0-B21166B2B18C}
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<!-- Aspire -->
<PackageVersion Include="Aspire.Hosting" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Redis" Version="$(AspireVersion)" />
<PackageVersion Include="Aspire.Hosting.Testing" Version="$(AspireVersion)" />
<!-- Microsoft.Extensions -->
<PackageVersion Include="Microsoft.Extensions.Http.Resilience" Version="8.5.0" />
Expand Down
17 changes: 17 additions & 0 deletions src/Aspirant.Hosting.Redis/Aspirant.Hosting.Redis.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Description>A set of useful extensions and experiments for Redis for .NET Aspire App Host projects.</Description>
<PackageTags>aspire hosting redis</PackageTags>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Aspirant.Hosting\Aspirant.Hosting.csproj" />
<PackageReference Include="Aspire.Hosting.Redis" />
<PackageReference Include="Microsoft.SourceLink.GitHub" PrivateAssets="All" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using Aspire.Hosting;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Redis;

namespace Aspirant.Hosting;

public static partial class RedisResourceBuilderExtensions
{
/// <summary>
/// Configures the host port that the Redis Commander resource is exposed on instead of using randomly assigned port when
/// <see cref="DistributedApplicationExecutionContext.IsPublishMode"/> is <c>true</c>..
/// </summary>
/// <param name="builder">The resource builder for Redis Commander.</param>
/// <param name="port">The port to bind on the host. If <see langword="null"/> is used random port will be assigned.</param>
/// <returns>The resource builder for PGAdmin.</returns>
public static IResourceBuilder<RedisCommanderResource> PublishWithHostPort(this IResourceBuilder<RedisCommanderResource> builder, int? port)
{
if (builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
builder.WithHostPort(port);
}

return builder;
}

/// <summary>
/// Adds a named volume for the data folder to a Redis container resource and enables Redis persistence when
/// <see cref="DistributedApplicationExecutionContext.IsPublishMode"/> is <c>true</c>.
/// </summary>
/// <remarks>
/// Use <see cref="PublishWithPersistence(IResourceBuilder{RedisResource}, TimeSpan?, long)"/> to adjust Redis persistence configuration, e.g.:
/// <code>
/// var cache = builder.AddRedis("cache")
/// .PublishWithDataVolume()
/// .PublishWithPersistence(TimeSpan.FromSeconds(10), 5);
/// </code>
/// </remarks>
/// <param name="builder">The resource builder.</param>
/// <param name="name">The name of the volume. Defaults to an auto-generated name based on the application and resource names.</param>
/// <param name="isReadOnly">
/// A flag that indicates if this is a read-only volume. Setting this to <c>true</c> will disable Redis persistence.<br/>
/// Defaults to <c>false</c>.
/// </param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RedisResource> PublishWithDataVolume(this IResourceBuilder<RedisResource> builder, string? name = null, bool isReadOnly = false)
{
if (builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
builder.WithDataVolume(name, isReadOnly);
}

return builder;
}

/// <summary>
/// Adds a bind mount for the data folder to a Redis container resource and enables Redis persistence
/// when <see cref="DistributedApplicationExecutionContext.IsPublishMode"/> is <c>true</c>.
/// </summary>
/// <remarks>
/// Use <see cref="PublishWithPersistence(IResourceBuilder{RedisResource}, TimeSpan?, long)"/> to adjust Redis persistence configuration, e.g.:
/// <code>
/// var cache = builder.AddRedis("cache")
/// .PublishWithDataBindMount()
/// .PublishWithPersistence(TimeSpan.FromSeconds(10), 5);
/// </code>
/// </remarks>
/// <param name="builder">The resource builder.</param>
/// <param name="source">The source directory on the host to mount into the container.</param>
/// <param name="isReadOnly">
/// A flag that indicates if this is a read-only mount. Setting this to <c>true</c> will disable Redis persistence.<br/>
/// Defaults to <c>false</c>.
/// </param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RedisResource> PublishWithDataBindMount(this IResourceBuilder<RedisResource> builder, string source, bool isReadOnly = false)
{
if (builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
builder.WithDataBindMount(source, isReadOnly);
}

return builder;
}

/// <summary>
/// Configures a Redis container resource for persistence when <see cref="DistributedApplicationExecutionContext.IsPublishMode"/> is <c>true</c>.
/// </summary>
/// <remarks>
/// Use with <see cref="PublishWithDataBindMount(IResourceBuilder{RedisResource}, string, bool)"/>
/// or <see cref="PublishWithDataVolume(IResourceBuilder{RedisResource}, string?, bool)"/> to persist Redis data across sessions with custom persistence configuration, e.g.:
/// <code>
/// var cache = builder.AddRedis("cache")
/// .WithDataVolume()
/// .WithPersistence(TimeSpan.FromSeconds(10), 5);
/// </code>
/// </remarks>
/// <param name="builder">The resource builder.</param>
/// <param name="interval">The interval between snapshot exports. Defaults to 60 seconds.</param>
/// <param name="keysChangedThreshold">The number of key change operations required to trigger a snapshot at the interval. Defaults to 1.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RedisResource> PublishWithPersistence(this IResourceBuilder<RedisResource> builder, TimeSpan? interval = null, long keysChangedThreshold = 1)
{
if (builder.ApplicationBuilder.ExecutionContext.IsPublishMode)
{
builder.WithPersistence(interval, keysChangedThreshold);
}

return builder;
}
}
113 changes: 113 additions & 0 deletions src/Aspirant.Hosting.Redis/RedisResourceBuilderExtensions.RunWith.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
using System.Xml.Linq;
using Aspire.Hosting;
using Aspire.Hosting.ApplicationModel;
using Aspire.Hosting.Redis;

namespace Aspirant.Hosting;

/// <summary>
/// Extension methods for <see cref="IResourceBuilder{RedisResource}"/>.
/// </summary>
public static partial class RedisResourceBuilderExtensions
{
/// <summary>
/// Configures the host port that the Redis Commander resource is exposed on instead of using randomly assigned port when
/// <see cref="DistributedApplicationExecutionContext.IsRunMode"/> is <c>true</c>..
/// </summary>
/// <param name="builder">The resource builder for Redis Commander.</param>
/// <param name="port">The port to bind on the host. If <see langword="null"/> is used random port will be assigned.</param>
/// <returns>The resource builder for PGAdmin.</returns>
public static IResourceBuilder<RedisCommanderResource> RunWithHostPort(this IResourceBuilder<RedisCommanderResource> builder, int? port)
{
if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
{
builder.WithHostPort(port);
}

return builder;
}

/// <summary>
/// Adds a named volume for the data folder to a Redis container resource and enables Redis persistence when
/// <see cref="DistributedApplicationExecutionContext.IsRunMode"/> is <c>true</c>.
/// </summary>
/// <remarks>
/// Use <see cref="RunWithPersistence(IResourceBuilder{RedisResource}, TimeSpan?, long)"/> to adjust Redis persistence configuration, e.g.:
/// <code>
/// var cache = builder.AddRedis("cache")
/// .RunWithDataVolume()
/// .RunWithPersistence(TimeSpan.FromSeconds(10), 5);
/// </code>
/// </remarks>
/// <param name="builder">The resource builder.</param>
/// <param name="name">The name of the volume. Defaults to an auto-generated name based on the application and resource names.</param>
/// <param name="isReadOnly">
/// A flag that indicates if this is a read-only volume. Setting this to <c>true</c> will disable Redis persistence.<br/>
/// Defaults to <c>false</c>.
/// </param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RedisResource> RunWithDataVolume(this IResourceBuilder<RedisResource> builder, string? name = null, bool isReadOnly = false)
{
if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
{
builder.WithDataVolume(name, isReadOnly);
}

return builder;
}

/// <summary>
/// Adds a bind mount for the data folder to a Redis container resource and enables Redis persistence
/// when <see cref="DistributedApplicationExecutionContext.IsRunMode"/> is <c>true</c>.
/// </summary>
/// <remarks>
/// Use <see cref="RunWithPersistence(IResourceBuilder{RedisResource}, TimeSpan?, long)"/> to adjust Redis persistence configuration, e.g.:
/// <code>
/// var cache = builder.AddRedis("cache")
/// .RunWithDataBindMount()
/// .RunWithPersistence(TimeSpan.FromSeconds(10), 5);
/// </code>
/// </remarks>
/// <param name="builder">The resource builder.</param>
/// <param name="source">The source directory on the host to mount into the container.</param>
/// <param name="isReadOnly">
/// A flag that indicates if this is a read-only mount. Setting this to <c>true</c> will disable Redis persistence.<br/>
/// Defaults to <c>false</c>.
/// </param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RedisResource> RunWithDataBindMount(this IResourceBuilder<RedisResource> builder, string source, bool isReadOnly = false)
{
if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
{
builder.WithDataBindMount(source, isReadOnly);
}

return builder;
}

/// <summary>
/// Configures a Redis container resource for persistence when <see cref="DistributedApplicationExecutionContext.IsRunMode"/> is <c>true</c>.
/// </summary>
/// <remarks>
/// Use with <see cref="RunWithDataBindMount(IResourceBuilder{RedisResource}, string, bool)"/>
/// or <see cref="RunWithDataVolume(IResourceBuilder{RedisResource}, string?, bool)"/> to persist Redis data across sessions with custom persistence configuration, e.g.:
/// <code>
/// var cache = builder.AddRedis("cache")
/// .WithDataVolume()
/// .WithPersistence(TimeSpan.FromSeconds(10), 5);
/// </code>
/// </remarks>
/// <param name="builder">The resource builder.</param>
/// <param name="interval">The interval between snapshot exports. Defaults to 60 seconds.</param>
/// <param name="keysChangedThreshold">The number of key change operations required to trigger a snapshot at the interval. Defaults to 1.</param>
/// <returns>The <see cref="IResourceBuilder{T}"/>.</returns>
public static IResourceBuilder<RedisResource> RunWithPersistence(this IResourceBuilder<RedisResource> builder, TimeSpan? interval = null, long keysChangedThreshold = 1)
{
if (builder.ApplicationBuilder.ExecutionContext.IsRunMode)
{
builder.WithPersistence(interval, keysChangedThreshold);
}

return builder;
}
}
Loading

0 comments on commit a8e5337

Please sign in to comment.