Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dapr component schema #460

Open
wants to merge 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
<PackageVersion Include="RavenDB.Client" Version="6.2.1" />
<PackageVersion Include="RavenDB.TestDriver" Version="6.2.1" />
<PackageVersion Include="AspNetCore.HealthChecks.RavenDB" Version="9.0.0" />
<PackageVersion Include="YamlDotNet" Version="16.3.0" />
<PackageVersion Include="Swashbuckle.AspNetCore" Version="7.2.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
apiVersion: dapr.io/v1alpha1
kind: Component
auth:
secretStore: secretstore
metadata:
name: pubsub
spec:
type: pubsub.redis
version: v1
metadata:
- name: redisPassword
value: ''
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<Sdk Name="Aspire.AppHost.Sdk" Version="$(AspireAppHostSdkVersion)" />

Expand All @@ -10,9 +10,13 @@
<UserSecretsId>e7f9178b-87a6-4047-b90a-a1fa9d8137b9</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<None Include=".dapr\components\pubsub.yaml" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" />
<PackageReference Include="Aspire.Hosting.RabbitMQ" />
<PackageReference Include="Aspire.Hosting.Azure.Redis" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
var builder = DistributedApplication.CreateBuilder(args);

var rmq = builder.AddRabbitMQ("rabbitMQ")
.WithManagementPlugin()
.WithEndpoint("tcp", e => e.Port = 5672)
.WithEndpoint("management", e => e.Port = 15672);
var redis = builder.AddRedis("redis").WithRedisInsight();


var stateStore = builder.AddDaprStateStore("statestore");

var pubSub = builder.AddDaprPubSub("pubsub")
.WaitFor(rmq);
.WithMetadata("redisHost", "localhost:6379")
.WaitFor(redis);

builder.AddProject<Projects.CommunityToolkit_Aspire_Hosting_Dapr_ServiceA>("servicea")
.WithDaprSidecar()
.WithReference(stateStore)
.WithReference(pubSub);
.WithReference(pubSub)
.WithDaprSidecar()
.WaitFor(redis);

builder.AddProject<Projects.CommunityToolkit_Aspire_Hosting_Dapr_ServiceB>("serviceb")
.WithReference(pubSub)
.WithDaprSidecar()
Comment on lines +19 to 20
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From a developer standpoint I would more expect something like:

.WithDaprSidecar()
  .WithReference(pubSub)

Because you configure the sidecare to use the pubSub reference as a pubsub. Not the project.
That would also mean that we would need to break with the Fluent API their or have some WithDaprSidecar parameter that accepts a action or so to configure the sidecar.

You can look for the AzurePostgreSql resource of aspire how you can configure the development contianer. I would prefer an API like their

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To prevent breaking changes for now closing this comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is up to the developer the both work the same

.WithReference(pubSub);
.WaitFor(redis);

// console app with no appPort (sender only)
builder.AddProject<Projects.CommunityToolkit_Aspire_Hosting_Dapr_ServiceC>("servicec")
.WithReference(stateStore)
.WithDaprSidecar();
.WithDaprSidecar()
.WaitFor(redis);

builder.Build().Run();

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/secrets", (DaprClient client) =>
{
var secrets = client.GetBulkSecretAsync("secretstore");
return secrets;
});

app.MapGet("/weatherforecast", async (DaprClient client) =>
{
await client.PublishEventAsync("pubsub", "weather", new WeatherForecastMessage("Weather forecast requested!"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "https://localhost:54626;http://localhost:54627"
"applicationUrl": "https://localhost:52786;http://localhost:52787"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<AdditionalPackageTags>aspire integration hosting dapr</AdditionalPackageTags>
Expand All @@ -11,6 +11,7 @@

<ItemGroup>
<PackageReference Include="Aspire.Hosting" />
<PackageReference Include="YamlDotNet" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Dapr;
internal sealed record DaprComponentConfigurationAnnotation(Action<DaprComponentSchema> Configure) : IResourceAnnotation;
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,4 @@ namespace CommunityToolkit.Aspire.Hosting.Dapr;
/// Indicates that a Dapr component should be used with the sidecar for the associated resource.
/// </summary>
/// <param name="Component">The Dapr component to use.</param>
public sealed record DaprComponentReferenceAnnotation(IDaprComponentResource Component) : IResourceAnnotation
{
}
public sealed record DaprComponentReferenceAnnotation(IDaprComponentResource Component) : IResourceAnnotation;
134 changes: 134 additions & 0 deletions src/CommunityToolkit.Aspire.Hosting.Dapr/DaprComponentSchema.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

namespace CommunityToolkit.Aspire.Hosting.Dapr;

internal interface IDaprComponentSpecMetadata : IList<DaprComponentSpecMetadata>;

internal class DaprComponentSchema
{
private static readonly ISerializer serializer = BuildSerializer();
private static readonly IDeserializer deserializer = BuildDeSerializer();

public string ApiVersion { get; init; } = "dapr.io/v1alpha1";
public string Kind { get; init; } = "Component";
public DaprComponentAuth? Auth { get; set; }
public DaprComponentMetadata Metadata { get; init; } = default!;
public DaprComponentSpec Spec { get; init; } = default!;

// Required for deserialization
public DaprComponentSchema() { }

public DaprComponentSchema(string name, string type)
{
Metadata = new DaprComponentMetadata { Name = name };
Spec = new DaprComponentSpec
{
Type = type,
Metadata = []
};
}
public override string ToString() => serializer.Serialize(this);

public static DaprComponentSchema FromYaml(string yamlContent) =>
deserializer.Deserialize<DaprComponentSchema>(yamlContent);
private static IDeserializer BuildDeSerializer()
{
DeserializerBuilder builder = new();
builder.WithNamingConvention(CamelCaseNamingConvention.Instance)
.WithTypeDiscriminatingNodeDeserializer(static o =>
{
Dictionary<string, Type> keyMappings = new()
{
["value"] = typeof(DaprComponentSpecMetadataValue),
["secretKeyRef"] = typeof(DaprComponentSpecMetadataSecret)
};
o.AddUniqueKeyTypeDiscriminator<DaprComponentSpecMetadata>(keyMappings);
});
return builder.Build();
}

private static ISerializer BuildSerializer()
{
SerializerBuilder builder = new();
builder.WithNamingConvention(CamelCaseNamingConvention.Instance)
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitDefaults);
return builder.Build();
}

}
internal class DaprComponentMetadata
{
public required string Name { get; init; }
public string? Namespace { get; init; }

}

internal class DaprComponentAuth
{
public required string SecretStore { get; init; }
}

internal class GenericDaprComponentSpecMetadata : List<DaprComponentSpecMetadata>, IDaprComponentSpecMetadata;

internal class DaprComponentSpec : DaprComponentSpec<GenericDaprComponentSpecMetadata> { }

internal class DaprComponentSpec<TSpecMetadata> where TSpecMetadata : IDaprComponentSpecMetadata
{
public required string Type { get; init; }
public string Version { get; init; } = "v1";
public required TSpecMetadata Metadata { get; init; }
}

/// <summary>
/// Represents a Dapr component spec metadata item
/// </summary>
public abstract class DaprComponentSpecMetadata
{
/// <summary>
/// The name of the metadata item
/// </summary>
[YamlMember(Order = 1)]
public required string Name { get; init; }
}

/// <summary>
/// Represents a Dapr component spec metadata item with a value
/// </summary>
public sealed class DaprComponentSpecMetadataValue : DaprComponentSpecMetadata
{
/// <summary>
/// The value of the metadata item
/// </summary>
[YamlMember(Order = 2)]
public required string Value { get; set; }
}

/// <summary>
/// Represents a Dapr component spec metadata item with a secret key reference
/// </summary>
public sealed class DaprComponentSpecMetadataSecret : DaprComponentSpecMetadata
{
/// <summary>
/// The secret key reference of the metadata item
/// </summary>
[YamlMember(Order = 2)]
public required DaprSecretKeyRef SecretKeyRef { get; set; }

}

/// <summary>
/// Represents a Dapr secret key reference
/// </summary>
public sealed class DaprSecretKeyRef
{
/// <summary>
/// The name of the secret
/// </summary>
public required string Name { get; init; }
/// <summary>
/// The key of the secret
/// </summary>
public required string Key { get; init; }
};

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Dapr;

internal record DaprComponentSecretAnnotation(string Key, string Value) : IResourceAnnotation;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ internal static class DaprConstants
public static class BuildingBlocks
{
public const string PubSub = "pubsub";

public const string StateStore = "state";
public const string SecretStore = "secretstore";
}
}
Loading
Loading