From f956d0db702e80cd61ade8be604189d6ca6d05a4 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Wed, 30 Oct 2024 14:35:14 -0700 Subject: [PATCH 01/17] wip --- .../AzureEventHubsExtensions.cs | 6 +- .../EventHubsEmulatorContainerImageTags.cs | 6 +- .../Aspire.Hosting.Azure.ServiceBus.csproj | 7 + .../AzureServiceBusEmulatorResource.cs | 23 ++ .../AzureServiceBusExtensions.cs | 204 ++++++++++++++++++ .../ServiceBusEmulatorContainerImageTags.cs | 16 ++ 6 files changed, 256 insertions(+), 6 deletions(-) create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs index 2074fcb0d1..9072c4776d 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsExtensions.cs @@ -78,9 +78,6 @@ public static IResourceBuilder AddAzureEventHubs( /// /// Adds an Azure Event Hubs hub resource to the application model. This resource requires an to be added to the application model. /// - /// - /// This version of the package defaults to the tag of the / container image. - /// /// The Azure Event Hubs resource builder. /// The name of the Event Hub. public static IResourceBuilder AddEventHub(this IResourceBuilder builder, [ResourceName] string name) @@ -92,6 +89,9 @@ public static IResourceBuilder AddEventHub(this IResourc /// /// Configures an Azure Event Hubs resource to be emulated. This resource requires an to be added to the application model. /// + /// + /// This version of the package defaults to the tag of the / container image. + /// /// The Azure Event Hubs resource builder. /// Callback that exposes underlying container used for emulation to allow for customization. /// A reference to the . diff --git a/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs b/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs index 8a50e3ab20..f32e098277 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs @@ -5,12 +5,12 @@ namespace Aspire.Hosting.Azure.EventHubs; internal static class EventHubsEmulatorContainerImageTags { - /// mcr.microsoft.com + /// mcr.microsoft.com public const string Registry = "mcr.microsoft.com"; - /// azure-messaging/eventhubs-emulator + /// azure-messaging/eventhubs-emulator public const string Image = "azure-messaging/eventhubs-emulator"; - /// latest + /// latest public const string Tag = "latest"; // latest is the only arch-agnostic tag } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj index a4690f2c2d..1ad88cb7c0 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj +++ b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj @@ -13,9 +13,16 @@ + + + + + + + diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs new file mode 100644 index 0000000000..4187dcd9ac --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Aspire.Hosting.ApplicationModel; + +namespace Aspire.Hosting.Azure; + +/// +/// Wraps an in a type that exposes container extension methods. +/// +/// The inner resource used to store annotations. +public class AzureServiceBusEmulatorResource(AzureServiceBusResource innerResource) : ContainerResource(innerResource.Name), IResource +{ + internal const string EmulatorConfigJsonPath = "/Eventhubs_Emulator/ConfigFiles/Config.json"; + + private readonly AzureServiceBusResource _innerResource = innerResource; + + /// + public override string Name => _innerResource.Name; + + /// + public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index ec7c4b7720..a0b1d5f43c 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -1,11 +1,16 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Azure; +using Aspire.Hosting.Azure.ServiceBus; +using Aspire.Hosting.Utils; +using Azure.Messaging.ServiceBus; using Azure.Provisioning; using Azure.Provisioning.Expressions; using Azure.Provisioning.ServiceBus; +using Microsoft.Extensions.DependencyInjection; namespace Aspire.Hosting; @@ -140,4 +145,203 @@ public static IResourceBuilder AddSubscription(this IRe builder.Resource.Subscriptions.Add((topicName, subscriptionName)); return builder; } + + /// + /// Configures an Azure Service Bus resource to be emulated. This resource requires an to be added to the application model. + /// + /// + /// This version of the package defaults to the tag of the / container image. + /// + /// The Azure Service Bus resource builder. + /// Callback that exposes underlying container used for emulation to allow for customization. + /// A reference to the . + /// + /// The following example creates an Azure Service Bus resource that runs locally is an emulator and referencing that + /// resource in a .NET project. + /// + /// var builder = DistributedApplication.CreateBuilder(args); + /// + /// var serviceBus = builder.AddAzureServiceBus("myservicebus") + /// .RunAsEmulator() + /// .AddQueue("queue"); + /// + /// builder.AddProject<Projects.InventoryService>() + /// .WithReference(serviceBus); + /// + /// builder.Build().Run(); + /// + /// + public static IResourceBuilder RunAsEmulator(this IResourceBuilder builder, Action>? configureContainer = null) + { + if (builder.ApplicationBuilder.ExecutionContext.IsPublishMode) + { + return builder; + } + + // Add emulator container + var configHostFile = Path.GetTempFileName(); + if (!OperatingSystem.IsWindows()) + { + File.SetUnixFileMode(configHostFile, + UnixFileMode.UserRead | UnixFileMode.UserWrite + | UnixFileMode.GroupRead | UnixFileMode.GroupWrite + | UnixFileMode.OtherRead | UnixFileMode.OtherWrite); + } + + builder + .WithEndpoint(name: "emulator", targetPort: 5672) + .WithAnnotation(new ContainerImageAnnotation + { + Registry = ServiceBusEmulatorContainerImageTags.Registry, + Image = ServiceBusEmulatorContainerImageTags.Image, + Tag = ServiceBusEmulatorContainerImageTags.Tag + }) + .WithAnnotation(new ContainerMountAnnotation( + configHostFile, + AzureServiceBusEmulatorResource.EmulatorConfigJsonPath, + ContainerMountType.BindMount, + isReadOnly: false)); + + // Create a separate storage emulator for the Event Hub one + var storageResource = builder.ApplicationBuilder + .AddAzureStorage($"{builder.Resource.Name}-storage") + .RunAsEmulator(); + + var storage = storageResource.Resource; + + builder.WithAnnotation(new EnvironmentCallbackAnnotation((EnvironmentCallbackContext context) => + { + var blobEndpoint = storage.GetEndpoint("blob"); + var tableEndpoint = storage.GetEndpoint("table"); + + context.EnvironmentVariables.Add("ACCEPT_EULA", "Y"); + context.EnvironmentVariables.Add("BLOB_SERVER", $"{blobEndpoint.Resource.Name}:{blobEndpoint.TargetPort}"); + context.EnvironmentVariables.Add("METADATA_SERVER", $"{tableEndpoint.Resource.Name}:{tableEndpoint.TargetPort}"); + })); + + ServiceBusClient? client = null; + + builder.ApplicationBuilder.Eventing.Subscribe(builder.Resource, async (@event, ct) => + { + var connectionString = await builder.Resource.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false) + ?? throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{builder.Resource.Name}' resource but the connection string was null."); + + // For the purposes of the health check we only need to know a queue name. If we don't have a queue + // name we can't configure a valid producer client connection so we should throw. What good is + // an queue namespace without a queue? :) + if (builder.Resource.Queues is { Count: > 0 } && builder.Resource.Queues[0] is string hub) + { + var healthCheckConnectionString = $"{connectionString};EntityPath={hub};"; + client = new ServiceBusClient(healthCheckConnectionString); + } + else + { + throw new DistributedApplicationException($"The '{builder.Resource.Name}' resource does not have any Event Hubs."); + } + }); + + var healthCheckKey = $"{builder.Resource.Name}_check"; + builder.ApplicationBuilder.Services.AddHealthChecks().AddAzureServiceBusQueue( + sp => connectionString ?? throw new DistributedApplicationException("EventHubProducerClient is not initialized"), + healthCheckKey + ); + + builder.WithHealthCheck(healthCheckKey); + + if (configureContainer != null) + { + var surrogate = new AzureServiceBusEmulatorResource(builder.Resource); + var surrogateBuilder = builder.ApplicationBuilder.CreateResourceBuilder(surrogate); + configureContainer(surrogateBuilder); + } + + builder.ApplicationBuilder.Eventing.Subscribe((e, ct) => + { + var serviceBusEmulatorResources = builder.ApplicationBuilder.Resources.OfType().Where(x => x is { } serviceBusResource && serviceBusResource.IsEmulator); + + if (!serviceBusEmulatorResources.Any()) + { + // No-op if there is no Azure Service Bus emulator resource. + return Task.CompletedTask; + } + + foreach (var emulatorResource in serviceBusEmulatorResources) + { + var configFileMount = emulatorResource.Annotations.OfType().Single(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath); + + using var stream = new FileStream(configFileMount.Source!, FileMode.Create); + using var writer = new Utf8JsonWriter(stream); + + writer.WriteStartObject(); // { + writer.WriteStartObject("UserConfig"); // "UserConfig": { + writer.WriteStartArray("NamespaceConfig"); // "NamespaceConfig": [ + writer.WriteStartObject(); // { + writer.WriteString("Type", "EventHub"); // "Type": "EventHub", + + // This name is currently required by the emulator + writer.WriteString("Name", "emulatorNs1"); // "Name": "emulatorNs1" + writer.WriteStartArray("Entities"); // "Entities": [ + + foreach (var hub in emulatorResource.Hubs) + { + // The default consumer group ('$default') is automatically created + + writer.WriteStartObject(); // { + writer.WriteString("Name", hub); // "Name": "hub", + writer.WriteString("PartitionCount", "2"); // "PartitionCount": "2", + writer.WriteStartArray("ConsumerGroups"); // "ConsumerGroups": [ + writer.WriteEndArray(); // ] + writer.WriteEndObject(); // } + } + + writer.WriteEndArray(); // ] (/Entities) + writer.WriteEndObject(); // } + writer.WriteEndArray(); // ], (/NamespaceConfig) + writer.WriteStartObject("LoggingConfig"); // "LoggingConfig": { + writer.WriteString("Type", "File"); // "Type": "File" + writer.WriteEndObject(); // } (/LoggingConfig) + + writer.WriteEndObject(); // } (/UserConfig) + writer.WriteEndObject(); // } (/Root) + + } + + return Task.CompletedTask; + + }); + + return builder; + } + + /// + /// Adds a bind mount for the data folder to an Azure Service Bus emulator resource. + /// + /// The builder for the . + /// Relative path to the AppHost where emulator storage is persisted between runs. Defaults to the path '.servicebus/{builder.Resource.Name}' + /// A builder for the . + public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string? path = null) + => builder.WithBindMount(path ?? $".servicebus/{builder.Resource.Name}", "/data", isReadOnly: false); + + /// + /// Adds a named volume for the data folder to an Azure Service Bus emulator resource. + /// + /// The builder for the . + /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. + /// A builder for the . + public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null) + => builder.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/data", isReadOnly: false); + + /// + /// Configures the gateway port for the Azure Service Bus emulator. + /// + /// Builder for the Azure Service Bus emulator container + /// Host port to bind to the emulator gateway port. + /// Azure Service Bus emulator resource builder. + public static IResourceBuilder WithGatewayPort(this IResourceBuilder builder, int? port) + { + return builder.WithEndpoint("emulator", endpoint => + { + endpoint.Port = port; + }); + } } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs new file mode 100644 index 0000000000..1edbbf1831 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs @@ -0,0 +1,16 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus; + +internal static class ServiceBusEmulatorContainerImageTags +{ + /// mcr.microsoft.com + public const string Registry = "mcr.microsoft.com"; + + /// azure-messaging/eventhubs-emulator + public const string Image = "azure-messaging/servicebus-emulator"; + + /// latest + public const string Tag = "latest"; // latest is the only arch-agnostic tag +} From 000b32f556009fa1242267135f4e17116dbc955f Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 15 Nov 2024 18:15:05 -0800 Subject: [PATCH 02/17] It's alive --- Aspire.sln | 17 + .../ServiceBus.AppHost/Program.cs | 43 ++ .../Properties/launchSettings.json | 45 ++ .../ServiceBus.AppHost.csproj | 21 + .../appsettings.Development.json | 8 + .../ServiceBus.AppHost/appsettings.json | 9 + .../ServiceBusWorker/Consumer.cs | 44 ++ .../ServiceBusWorker/Producer.cs | 30 + .../ServiceBusWorker/Program.cs | 19 + .../Properties/launchSettings.json | 12 + .../ServiceBusWorker/ServiceBusWorker.csproj | 16 + .../appsettings.Development.json | 8 + .../ServiceBusWorker/appsettings.json | 8 + .../AzureEventHubsEmulatorResource.cs | 1 + .../Aspire.Hosting.Azure.ServiceBus.csproj | 2 + .../AzureServiceBusEmulatorResource.cs | 3 +- .../AzureServiceBusExtensions.cs | 553 +++++++++++++++--- .../AzureServiceBusResource.cs | 21 +- .../PublicAPI.Shipped.txt | 3 - .../PublicAPI.Unshipped.txt | 14 + .../ServiceBusEmulatorContainerImageTags.cs | 17 +- 21 files changed, 796 insertions(+), 98 deletions(-) create mode 100644 playground/AzureServiceBus/ServiceBus.AppHost/Program.cs create mode 100644 playground/AzureServiceBus/ServiceBus.AppHost/Properties/launchSettings.json create mode 100644 playground/AzureServiceBus/ServiceBus.AppHost/ServiceBus.AppHost.csproj create mode 100644 playground/AzureServiceBus/ServiceBus.AppHost/appsettings.Development.json create mode 100644 playground/AzureServiceBus/ServiceBus.AppHost/appsettings.json create mode 100644 playground/AzureServiceBus/ServiceBusWorker/Consumer.cs create mode 100644 playground/AzureServiceBus/ServiceBusWorker/Producer.cs create mode 100644 playground/AzureServiceBus/ServiceBusWorker/Program.cs create mode 100644 playground/AzureServiceBus/ServiceBusWorker/Properties/launchSettings.json create mode 100644 playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj create mode 100644 playground/AzureServiceBus/ServiceBusWorker/appsettings.Development.json create mode 100644 playground/AzureServiceBus/ServiceBusWorker/appsettings.json diff --git a/Aspire.sln b/Aspire.sln index 7972b48f7b..12c663dce9 100644 --- a/Aspire.sln +++ b/Aspire.sln @@ -643,6 +643,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HealthChecksSandbox.AppHost EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DaprServiceC", "playground\dapr\ServiceC\DaprServiceC.csproj", "{B26653B9-439E-4850-A7F8-43C6E5121952}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AzureServiceBus", "AzureServiceBus", "{D2938171-1DBB-4E8D-AF16-97F75F1AE6DE}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceBusWorker", "playground\AzureServiceBus\ServiceBusWorker\ServiceBusWorker.csproj", "{162F0B66-E88F-4735-8CE0-BE8950F74CC6}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceBus.AppHost", "playground\AzureServiceBus\ServiceBus.AppHost\ServiceBus.AppHost.csproj", "{A7EC9111-F3CC-46E8-B95E-3768481D67B4}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1689,6 +1695,14 @@ Global {B26653B9-439E-4850-A7F8-43C6E5121952}.Debug|Any CPU.Build.0 = Debug|Any CPU {B26653B9-439E-4850-A7F8-43C6E5121952}.Release|Any CPU.ActiveCfg = Release|Any CPU {B26653B9-439E-4850-A7F8-43C6E5121952}.Release|Any CPU.Build.0 = Release|Any CPU + {162F0B66-E88F-4735-8CE0-BE8950F74CC6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {162F0B66-E88F-4735-8CE0-BE8950F74CC6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {162F0B66-E88F-4735-8CE0-BE8950F74CC6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {162F0B66-E88F-4735-8CE0-BE8950F74CC6}.Release|Any CPU.Build.0 = Release|Any CPU + {A7EC9111-F3CC-46E8-B95E-3768481D67B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A7EC9111-F3CC-46E8-B95E-3768481D67B4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A7EC9111-F3CC-46E8-B95E-3768481D67B4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A7EC9111-F3CC-46E8-B95E-3768481D67B4}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1998,6 +2012,9 @@ Global {B7345F72-712F-436C-AE18-CAF7CDD4A990} = {D173887B-AF42-4576-B9C1-96B9E9B3D9C0} {042DD8C6-A26C-4B06-80A1-FE7F8659C5BC} = {B7345F72-712F-436C-AE18-CAF7CDD4A990} {B26653B9-439E-4850-A7F8-43C6E5121952} = {57A42144-739E-49A7-BADB-BB8F5F20FA17} + {D2938171-1DBB-4E8D-AF16-97F75F1AE6DE} = {D173887B-AF42-4576-B9C1-96B9E9B3D9C0} + {162F0B66-E88F-4735-8CE0-BE8950F74CC6} = {D2938171-1DBB-4E8D-AF16-97F75F1AE6DE} + {A7EC9111-F3CC-46E8-B95E-3768481D67B4} = {D2938171-1DBB-4E8D-AF16-97F75F1AE6DE} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {6DCEDFEC-988E-4CB3-B45B-191EB5086E0C} diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs new file mode 100644 index 0000000000..b5cf57f3e6 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs @@ -0,0 +1,43 @@ +var builder = DistributedApplication.CreateBuilder(args); + +var serviceBus = builder.AddAzureServiceBus("sbemulator") + .RunAsEmulator(); + +serviceBus.AddQueue("myQueue", queue => +{ + queue.Name = "queue.1"; + queue.DeadLetteringOnMessageExpiration = false; + queue.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + queue.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + queue.ForwardDeadLetteredMessagesTo = ""; + queue.ForwardTo = ""; + queue.LockDuration = TimeSpan.FromMinutes(1); + queue.MaxDeliveryCount = 10; + queue.RequiresDuplicateDetection = false; + queue.RequiresSession = false; +}); + +serviceBus.AddTopic("myTopic", topic => +{ + topic.Name = "topic.1"; + topic.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + topic.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + topic.RequiresDuplicateDetection = false; +}); + +serviceBus.AddSubscription("myTopic", "mySubscription", sub => +{ + sub.Name = "subscription.1"; + sub.DeadLetteringOnMessageExpiration = false; + sub.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + sub.LockDuration = TimeSpan.FromMinutes(1); + sub.MaxDeliveryCount = 10; + sub.ForwardDeadLetteredMessagesTo = ""; + sub.ForwardTo = ""; + sub.RequiresSession = false; +}); + +builder.AddProject("worker") + .WithReference(serviceBus).WaitFor(serviceBus); + +builder.Build().Run(); diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/Properties/launchSettings.json b/playground/AzureServiceBus/ServiceBus.AppHost/Properties/launchSettings.json new file mode 100644 index 0000000000..2ebadb448d --- /dev/null +++ b/playground/AzureServiceBus/ServiceBus.AppHost/Properties/launchSettings.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + + "profiles": { + "https": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "https://localhost:15887;http://localhost:15888", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:16175", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:17037", + "DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true" + } + }, + "http": { + "commandName": "Project", + "dotnetRunMessages": true, + "launchBrowser": true, + "applicationUrl": "http://localhost:15888", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16175", + "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:17038", + "DOTNET_ASPIRE_SHOW_DASHBOARD_RESOURCES": "true", + "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true" + } + }, + "generate-manifest": { + "commandName": "Project", + "launchBrowser": true, + "dotnetRunMessages": true, + "commandLineArgs": "--publisher manifest --output-path aspire-manifest.json", + "applicationUrl": "http://localhost:15888", + "environmentVariables": { + "ASPNETCORE_ENVIRONMENT": "Development", + "DOTNET_ENVIRONMENT": "Development", + "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:16175" + } + } + } +} diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/ServiceBus.AppHost.csproj b/playground/AzureServiceBus/ServiceBus.AppHost/ServiceBus.AppHost.csproj new file mode 100644 index 0000000000..0657e9bf23 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBus.AppHost/ServiceBus.AppHost.csproj @@ -0,0 +1,21 @@ + + + + Exe + $(DefaultTargetFramework) + enable + enable + true + c12f723f-2545-4f8f-8c3b-fb7bdeadbd55 + + + + + + + + + + + + diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/appsettings.Development.json b/playground/AzureServiceBus/ServiceBus.AppHost/appsettings.Development.json new file mode 100644 index 0000000000..0c208ae918 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBus.AppHost/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning" + } + } +} diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/appsettings.json b/playground/AzureServiceBus/ServiceBus.AppHost/appsettings.json new file mode 100644 index 0000000000..31c092aa45 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBus.AppHost/appsettings.json @@ -0,0 +1,9 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.AspNetCore": "Warning", + "Aspire.Hosting.Dcp": "Warning" + } + } +} diff --git a/playground/AzureServiceBus/ServiceBusWorker/Consumer.cs b/playground/AzureServiceBus/ServiceBusWorker/Consumer.cs new file mode 100644 index 0000000000..744ae0fbad --- /dev/null +++ b/playground/AzureServiceBus/ServiceBusWorker/Consumer.cs @@ -0,0 +1,44 @@ +using System.Text; +using Azure.Messaging.ServiceBus; + +namespace ServiceBusWorker; + +internal sealed class Consumer(ServiceBusClient client, ILogger logger) : BackgroundService +{ + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + var processor = client.CreateProcessor("queue.1", new ServiceBusProcessorOptions + { + AutoCompleteMessages = true, + MaxConcurrentCalls = 1, // Process one message at a time + }); + + // Whenever a message is available on the queue + processor.ProcessMessageAsync += MessageHandler; + + processor.ProcessErrorAsync += ErrorHandler; + + await processor.StartProcessingAsync(cancellationToken); + } + + private static Task MessageHandler(ProcessMessageEventArgs args) + { + // Process the message + Console.WriteLine($"Received message: {Encoding.UTF8.GetString(args.Message.Body)}"); + + return Task.CompletedTask; + } + + private Task ErrorHandler(ProcessErrorEventArgs args) + { + logger.LogError(args.Exception, "Error processing message"); + + return Task.CompletedTask; + } + + public override Task StopAsync(CancellationToken cancellationToken) + { + logger.LogInformation("Stopping consumer..."); + return Task.CompletedTask; + } +} diff --git a/playground/AzureServiceBus/ServiceBusWorker/Producer.cs b/playground/AzureServiceBus/ServiceBusWorker/Producer.cs new file mode 100644 index 0000000000..556023701d --- /dev/null +++ b/playground/AzureServiceBus/ServiceBusWorker/Producer.cs @@ -0,0 +1,30 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +using Azure.Messaging.ServiceBus; + +namespace ServiceBusWorker; + +internal sealed class Producer(ServiceBusClient client, ILogger logger) : BackgroundService +{ + protected override async Task ExecuteAsync(CancellationToken cancellationToken) + { + logger.LogInformation("Starting producer..."); + + await using var sender = client.CreateSender("queue.1"); + + var periodicTimer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + while (!cancellationToken.IsCancellationRequested) + { + await periodicTimer.WaitForNextTickAsync(cancellationToken); + + await sender.SendMessageAsync(new ServiceBusMessage($"Hello, World! It's {DateTime.Now} here."), cancellationToken); + } + } + + public override Task StopAsync(CancellationToken cancellationToken) + { + logger.LogInformation("Stopping producer..."); + return Task.CompletedTask; + } +} diff --git a/playground/AzureServiceBus/ServiceBusWorker/Program.cs b/playground/AzureServiceBus/ServiceBusWorker/Program.cs new file mode 100644 index 0000000000..830721fef7 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBusWorker/Program.cs @@ -0,0 +1,19 @@ +using ServiceBusWorker; + +var builder = Host.CreateApplicationBuilder(args); + +builder.AddServiceDefaults(); + +builder.AddAzureServiceBusClient("sbemulator"); + +Console.WriteLine("ServiceBus producer/consumer test"); + +builder.Services.AddHostedService(); +Console.WriteLine("Starting Service Bus consumer..."); + +builder.Services.AddHostedService(); +Console.WriteLine("Starting Service Bus producer..."); + +var host = builder.Build(); + +await host.RunAsync(); diff --git a/playground/AzureServiceBus/ServiceBusWorker/Properties/launchSettings.json b/playground/AzureServiceBus/ServiceBusWorker/Properties/launchSettings.json new file mode 100644 index 0000000000..e5d9dbdb85 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBusWorker/Properties/launchSettings.json @@ -0,0 +1,12 @@ +{ + "$schema": "http://json.schemastore.org/launchsettings.json", + "profiles": { + "WorkerService1": { + "commandName": "Project", + "dotnetRunMessages": true, + "environmentVariables": { + "DOTNET_ENVIRONMENT": "Development" + } + } + } +} diff --git a/playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj b/playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj new file mode 100644 index 0000000000..a551003f1a --- /dev/null +++ b/playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj @@ -0,0 +1,16 @@ + + + + $(DefaultTargetFramework) + enable + enable + 9c946452-f682-49a4-9209-29ed63174447 + + + + + + + + + diff --git a/playground/AzureServiceBus/ServiceBusWorker/appsettings.Development.json b/playground/AzureServiceBus/ServiceBusWorker/appsettings.Development.json new file mode 100644 index 0000000000..b2dcdb6742 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBusWorker/appsettings.Development.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/playground/AzureServiceBus/ServiceBusWorker/appsettings.json b/playground/AzureServiceBus/ServiceBusWorker/appsettings.json new file mode 100644 index 0000000000..b2dcdb6742 --- /dev/null +++ b/playground/AzureServiceBus/ServiceBusWorker/appsettings.json @@ -0,0 +1,8 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + } +} diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs index aab693e0fe..910d7b55cd 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs @@ -11,6 +11,7 @@ namespace Aspire.Hosting.Azure; /// The inner resource used to store annotations. public class AzureEventHubsEmulatorResource(AzureEventHubsResource innerResource) : ContainerResource(innerResource.Name), IResource { + // The path to the emulator configuration file in the container. internal const string EmulatorConfigJsonPath = "/Eventhubs_Emulator/ConfigFiles/Config.json"; private readonly AzureEventHubsResource _innerResource = innerResource; diff --git a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj index 1ad88cb7c0..d2e5b5ce10 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj +++ b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj @@ -6,6 +6,7 @@ aspire integration hosting azure Azure Service Bus resource types for .NET Aspire. $(SharedDir)AzureServiceBus_256x.png + @@ -14,6 +15,7 @@ + diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs index 4187dcd9ac..260e39dc28 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs @@ -11,7 +11,8 @@ namespace Aspire.Hosting.Azure; /// The inner resource used to store annotations. public class AzureServiceBusEmulatorResource(AzureServiceBusResource innerResource) : ContainerResource(innerResource.Name), IResource { - internal const string EmulatorConfigJsonPath = "/Eventhubs_Emulator/ConfigFiles/Config.json"; + // The path to the emulator configuration file in the container. + internal const string EmulatorConfigJsonPath = "/ServiceBus_Emulator/ConfigFiles/Config.json"; private readonly AzureServiceBusResource _innerResource = innerResource; diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index a0b1d5f43c..a09bd3757a 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -2,15 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; +using System.Xml; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Azure; using Aspire.Hosting.Azure.ServiceBus; using Aspire.Hosting.Utils; -using Azure.Messaging.ServiceBus; using Azure.Provisioning; using Azure.Provisioning.Expressions; using Azure.Provisioning.ServiceBus; -using Microsoft.Extensions.DependencyInjection; namespace Aspire.Hosting; @@ -58,33 +57,23 @@ public static IResourceBuilder AddAzureServiceBus(this foreach (var queue in azureResource.Queues) { - var queueResource = new ServiceBusQueue(Infrastructure.NormalizeIdentifierName(queue)) - { - Parent = serviceBusNamespace, - Name = queue - }; - infrastructure.Add(queueResource); + queue.Parent = serviceBusNamespace; + infrastructure.Add(queue); } var topicDictionary = new Dictionary(); foreach (var topic in azureResource.Topics) { - var topicResource = new ServiceBusTopic(Infrastructure.NormalizeIdentifierName(topic)) - { - Parent = serviceBusNamespace, - Name = topic - }; - infrastructure.Add(topicResource); - topicDictionary.Add(topic, topicResource); + topic.Parent = serviceBusNamespace; + infrastructure.Add(topic); + + // Topics are added in the dictionary with their normalized names. + topicDictionary.Add(topic.IdentifierName, topic); } foreach (var subscription in azureResource.Subscriptions) { var topic = topicDictionary[subscription.TopicName]; - var subscriptionResource = new ServiceBusSubscription(Infrastructure.NormalizeIdentifierName(subscription.Name)) - { - Parent = topic, - Name = subscription.Name - }; - infrastructure.Add(subscriptionResource); + subscription.Subscription.Parent = topic; + infrastructure.Add(subscription.Subscription); } }; @@ -102,12 +91,18 @@ public static IResourceBuilder AddAzureServiceBus(this /// The Azure Service Bus resource builder. /// The name of the topic. /// The name of the subscriptions. - public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, string[] subscriptions) + /// An optional method that can be used for customizing the . + public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, string[] subscriptions, Action? configure = null) { - builder.Resource.Topics.Add(name); + var normalizedTopicName = Infrastructure.NormalizeIdentifierName(name); + var topic = new ServiceBusTopic(normalizedTopicName) { Name = name }; + + configure?.Invoke(topic); + + builder.Resource.Topics.Add(topic); foreach (var subscription in subscriptions) { - builder.Resource.Subscriptions.Add((name, subscription)); + builder.Resource.Subscriptions.Add((normalizedTopicName, new ServiceBusSubscription(Infrastructure.NormalizeIdentifierName(subscription)) { Name = subscription })); } return builder; } @@ -117,9 +112,14 @@ public static IResourceBuilder AddTopic(this IResourceB /// /// The Azure Service Bus resource builder. /// The name of the queue. - public static IResourceBuilder AddQueue(this IResourceBuilder builder, [ResourceName] string name) + /// An optional method that can be used for customizing the . + public static IResourceBuilder AddQueue(this IResourceBuilder builder, [ResourceName] string name, Action? configure = null) { - builder.Resource.Queues.Add(name); + var queue = new ServiceBusQueue(Infrastructure.NormalizeIdentifierName(name)) { Name = name }; + + configure?.Invoke(queue); + + builder.Resource.Queues.Add(queue); return builder; } @@ -130,7 +130,9 @@ public static IResourceBuilder AddQueue(this IResourceB /// The name of the topic. public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name) { - builder.Resource.Topics.Add(name); + var topic = new ServiceBusTopic(Infrastructure.NormalizeIdentifierName(name)) { Name = name }; + + builder.Resource.Topics.Add(topic); return builder; } @@ -138,11 +140,51 @@ public static IResourceBuilder AddTopic(this IResourceB /// Adds an Azure Service Bus Topic resource to the application model. This resource requires an to be added to the application model. /// /// The Azure Service Bus resource builder. + /// The name of the topic. + /// An optional method that can be used for customizing the . + public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, Action configure) + { + var topic = new ServiceBusTopic(Infrastructure.NormalizeIdentifierName(name)) { Name = name }; + configure?.Invoke(topic); + + builder.Resource.Topics.Add(topic); + return builder; + } + + /// + /// Adds an Azure Service Bus Subscription resource to the application model. This resource requires an to be added to the application model. + /// + /// The Azure Service Bus resource builder. /// The name of the topic. /// The name of the subscription. - public static IResourceBuilder AddSubscription(this IResourceBuilder builder, string topicName, string subscriptionName) + /// An optional method that can be used for customizing the . + public static IResourceBuilder AddSubscription(this IResourceBuilder builder, string topicName, string subscriptionName, Action? configure = null) { - builder.Resource.Subscriptions.Add((topicName, subscriptionName)); + var normalizedTopicName = Infrastructure.NormalizeIdentifierName(topicName); + var sub = new ServiceBusSubscription(normalizedTopicName) { Name = subscriptionName }; + configure?.Invoke(sub); + builder.Resource.Subscriptions.Add((normalizedTopicName, sub)); + return builder; + } + + /// + /// Adds an Azure Service Bus Rule resource to the application model. This resource requires an to be added to the application model. + /// + /// The Azure Service Bus resource builder. + /// The name of the topic. + /// The name of the subscription. + /// The name of the rule + /// An optional method that can be used for customizing the . + public static IResourceBuilder AddRule(this IResourceBuilder builder, string topicName, string subscriptionName, string ruleName, Action? configure = null) + { + var normalizedTopicName = Infrastructure.NormalizeIdentifierName(topicName); + var normalizedSubscriptionName = Infrastructure.NormalizeIdentifierName(subscriptionName); + var normalizedRuleName = Infrastructure.NormalizeIdentifierName(ruleName); + + var rule = new ServiceBusRule(normalizedRuleName) { Name = ruleName }; + configure?.Invoke(rule); + + builder.Resource.Rules.Add((normalizedTopicName, normalizedSubscriptionName, rule)); return builder; } @@ -179,7 +221,10 @@ public static IResourceBuilder RunAsEmulator(this IReso } // Add emulator container - var configHostFile = Path.GetTempFileName(); + var configHostFile = Path.Combine(Path.GetTempPath(), "AspireServiceBusEmulator", Path.GetRandomFileName() + ".json"); + + Directory.CreateDirectory(Path.GetDirectoryName(configHostFile)!); + if (!OperatingSystem.IsWindows()) { File.SetUnixFileMode(configHostFile, @@ -188,6 +233,8 @@ public static IResourceBuilder RunAsEmulator(this IReso | UnixFileMode.OtherRead | UnixFileMode.OtherWrite); } + var password = PasswordGenerator.Generate(16, true, true, true, true, 0, 0, 0, 0); + builder .WithEndpoint(name: "emulator", targetPort: 5672) .WithAnnotation(new ContainerImageAnnotation @@ -202,51 +249,52 @@ public static IResourceBuilder RunAsEmulator(this IReso ContainerMountType.BindMount, isReadOnly: false)); - // Create a separate storage emulator for the Event Hub one - var storageResource = builder.ApplicationBuilder - .AddAzureStorage($"{builder.Resource.Name}-storage") - .RunAsEmulator(); - - var storage = storageResource.Resource; + var sqlEdgeResource = builder.ApplicationBuilder + .AddContainer($"{builder.Resource.Name}-sqledge", + image: ServiceBusEmulatorContainerImageTags.AzureSqlEdgeImage, + tag: ServiceBusEmulatorContainerImageTags.AzureSqlEdgeTag) + .WithImageRegistry(ServiceBusEmulatorContainerImageTags.AzureSqlEdgeRegistry) + .WithEndpoint(targetPort: 1433, name: "tcp") + .WithEnvironment("ACCEPT_EULA", "Y") + .WithEnvironment("MSSQL_SA_PASSWORD", password); builder.WithAnnotation(new EnvironmentCallbackAnnotation((EnvironmentCallbackContext context) => { - var blobEndpoint = storage.GetEndpoint("blob"); - var tableEndpoint = storage.GetEndpoint("table"); + var sqlEndpoint = sqlEdgeResource.Resource.GetEndpoint("tcp"); context.EnvironmentVariables.Add("ACCEPT_EULA", "Y"); - context.EnvironmentVariables.Add("BLOB_SERVER", $"{blobEndpoint.Resource.Name}:{blobEndpoint.TargetPort}"); - context.EnvironmentVariables.Add("METADATA_SERVER", $"{tableEndpoint.Resource.Name}:{tableEndpoint.TargetPort}"); + context.EnvironmentVariables.Add("SQL_SERVER", $"{sqlEndpoint.Resource.Name}:{sqlEndpoint.TargetPort}"); + context.EnvironmentVariables.Add("MSSQL_SA_PASSWORD", password); })); - ServiceBusClient? client = null; - - builder.ApplicationBuilder.Eventing.Subscribe(builder.Resource, async (@event, ct) => - { - var connectionString = await builder.Resource.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false) - ?? throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{builder.Resource.Name}' resource but the connection string was null."); - - // For the purposes of the health check we only need to know a queue name. If we don't have a queue - // name we can't configure a valid producer client connection so we should throw. What good is - // an queue namespace without a queue? :) - if (builder.Resource.Queues is { Count: > 0 } && builder.Resource.Queues[0] is string hub) - { - var healthCheckConnectionString = $"{connectionString};EntityPath={hub};"; - client = new ServiceBusClient(healthCheckConnectionString); - } - else - { - throw new DistributedApplicationException($"The '{builder.Resource.Name}' resource does not have any Event Hubs."); - } - }); - - var healthCheckKey = $"{builder.Resource.Name}_check"; - builder.ApplicationBuilder.Services.AddHealthChecks().AddAzureServiceBusQueue( - sp => connectionString ?? throw new DistributedApplicationException("EventHubProducerClient is not initialized"), - healthCheckKey - ); - - builder.WithHealthCheck(healthCheckKey); + //ServiceBusClient? client = null; + + //builder.ApplicationBuilder.Eventing.Subscribe(builder.Resource, async (@event, ct) => + //{ + // var connectionString = await builder.Resource.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false) + // ?? throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{builder.Resource.Name}' resource but the connection string was null."); + + // // For the purposes of the health check we only need to know a queue name. If we don't have a queue + // // name we can't configure a valid producer client connection so we should throw. What good is + // // an queue namespace without a queue? :) + // if (builder.Resource.Queues is { Count: > 0 } && builder.Resource.Queues[0] is string hub) + // { + // var healthCheckConnectionString = $"{connectionString};EntityPath={hub};"; + // client = new ServiceBusClient(healthCheckConnectionString); + // } + // else + // { + // throw new DistributedApplicationException($"The '{builder.Resource.Name}' resource does not have any Event Hubs."); + // } + //}); + + //var healthCheckKey = $"{builder.Resource.Name}_check"; + //builder.ApplicationBuilder.Services.AddHealthChecks().AddAzureServiceBusQueue( + // sp => connectionString ?? throw new DistributedApplicationException("EventHubProducerClient is not initialized"), + // healthCheckKey + // ); + + //builder.WithHealthCheck(healthCheckKey); if (configureContainer != null) { @@ -274,30 +322,365 @@ public static IResourceBuilder RunAsEmulator(this IReso writer.WriteStartObject(); // { writer.WriteStartObject("UserConfig"); // "UserConfig": { - writer.WriteStartArray("NamespaceConfig"); // "NamespaceConfig": [ + writer.WriteStartArray("Namespaces"); // "Namespaces": [ writer.WriteStartObject(); // { - writer.WriteString("Type", "EventHub"); // "Type": "EventHub", - - // This name is currently required by the emulator - writer.WriteString("Name", "emulatorNs1"); // "Name": "emulatorNs1" - writer.WriteStartArray("Entities"); // "Entities": [ + // Is this name is currently required by the emulator like it is for EventHub? + writer.WriteString("Name", "sbemulatorns"); // "Name": "sbemulatorns" + writer.WriteStartArray("Queues"); // "Queues": [ - foreach (var hub in emulatorResource.Hubs) + foreach (var queue in emulatorResource.Queues) { - // The default consumer group ('$default') is automatically created + writer.WriteStartObject(); // { + if (queue.Name.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.Name), queue.Name.Value); + } + writer.WriteStartObject("Properties"); // "Properties": { + if (queue.AutoDeleteOnIdle.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.AutoDeleteOnIdle), XmlConvert.ToString(queue.AutoDeleteOnIdle.Value)); + } + if (queue.DeadLetteringOnMessageExpiration.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusQueue.DeadLetteringOnMessageExpiration), queue.DeadLetteringOnMessageExpiration.Value); + } + if (queue.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.DefaultMessageTimeToLive), XmlConvert.ToString(queue.DefaultMessageTimeToLive.Value)); + } + if (queue.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(queue.DuplicateDetectionHistoryTimeWindow.Value)); + } + if (queue.EnableBatchedOperations.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusQueue.EnableBatchedOperations), queue.EnableBatchedOperations.Value); + } + if (queue.EnableExpress.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusQueue.EnableExpress), queue.EnableExpress.Value); + } + if (queue.EnablePartitioning.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusQueue.EnablePartitioning), queue.EnablePartitioning.Value); + } + if (queue.ForwardDeadLetteredMessagesTo.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.ForwardDeadLetteredMessagesTo), queue.ForwardDeadLetteredMessagesTo.Value); + } + if (queue.ForwardTo.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.ForwardTo), queue.ForwardTo.Value); + } + if (queue.LockDuration.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.LockDuration), XmlConvert.ToString(queue.LockDuration.Value)); + } + if (queue.MaxDeliveryCount.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusQueue.MaxDeliveryCount), queue.MaxDeliveryCount.Value); + } + if (queue.MaxMessageSizeInKilobytes.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusQueue.MaxMessageSizeInKilobytes), queue.MaxMessageSizeInKilobytes.Value); + } + if (queue.MaxSizeInMegabytes.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusQueue.MaxSizeInMegabytes), queue.MaxSizeInMegabytes.Value); + } + if (queue.RequiresDuplicateDetection.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusQueue.RequiresDuplicateDetection), queue.RequiresDuplicateDetection.Value); + } + if (queue.RequiresSession.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusQueue.RequiresSession), queue.RequiresSession.Value); + } + if (queue.Status.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusTopic.Status), queue.Status.Value.ToString()); + } + writer.WriteEndObject(); // } (/Properties) + + writer.WriteEndObject(); // } (/Queue) + } + writer.WriteEndArray(); // ] (/Queues) + writer.WriteStartArray("Topics"); // "Topics": [ + foreach (var topic in emulatorResource.Topics) + { writer.WriteStartObject(); // { - writer.WriteString("Name", hub); // "Name": "hub", - writer.WriteString("PartitionCount", "2"); // "PartitionCount": "2", - writer.WriteStartArray("ConsumerGroups"); // "ConsumerGroups": [ - writer.WriteEndArray(); // ] - writer.WriteEndObject(); // } + if (topic.Name.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusTopic.Name), topic.Name.Value); + } + writer.WriteStartObject("Properties"); // "Properties": { + if (topic.AutoDeleteOnIdle.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusTopic.AutoDeleteOnIdle), XmlConvert.ToString(topic.AutoDeleteOnIdle.Value)); + } + if (topic.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusTopic.DefaultMessageTimeToLive), XmlConvert.ToString(topic.DefaultMessageTimeToLive.Value)); + } + if (topic.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusTopic.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(topic.DuplicateDetectionHistoryTimeWindow.Value)); + } + if (topic.EnableBatchedOperations.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusTopic.EnableBatchedOperations), topic.EnableBatchedOperations.Value); + } + if (topic.EnableExpress.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusTopic.EnableExpress), topic.EnableExpress.Value); + } + if (topic.EnablePartitioning.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusTopic.EnablePartitioning), topic.EnablePartitioning.Value); + } + if (topic.MaxMessageSizeInKilobytes.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusTopic.MaxMessageSizeInKilobytes), topic.MaxMessageSizeInKilobytes.Value); + } + if (topic.MaxSizeInMegabytes.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusTopic.MaxSizeInMegabytes), topic.MaxSizeInMegabytes.Value); + } + if (topic.RequiresDuplicateDetection.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusTopic.RequiresDuplicateDetection), topic.RequiresDuplicateDetection.Value); + } + if (topic.Status.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusTopic.Status), topic.Status.Value.ToString()); + } + writer.WriteEndObject(); // } (/Properties) + + writer.WriteStartArray("Subscriptions"); // "Subscriptions": [ + foreach (var entry in emulatorResource.Subscriptions) + { + if (entry.TopicName != topic.IdentifierName) + { + continue; + } + + var sub = entry.Subscription; + + writer.WriteStartObject(); // { + if (topic.Name.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.Name), sub.Name.Value); + } + + writer.WriteStartObject("Properties"); // "Properties": { + if (sub.Status.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusSubscription.AutoDeleteOnIdle), XmlConvert.ToString(sub.AutoDeleteOnIdle.Value)); + } + + if (sub.ClientAffineProperties.Kind != BicepValueKind.Unset && sub.ClientAffineProperties.Value != null) + { + writer.WriteStartObject("ClientAffineProperties"); // "ClientAffineProperties": { + + if (sub.ClientAffineProperties.Value.ClientId.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), sub.ClientAffineProperties.Value.ClientId.Value); + } + if (sub.ClientAffineProperties.Value.IsDurable.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), sub.ClientAffineProperties.Value.IsDurable.Value); + } + if (sub.ClientAffineProperties.Value.IsShared.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), sub.ClientAffineProperties.Value.IsShared.Value); + } + + writer.WriteEndObject(); // } (/ClientAffineProperties) + } + + if (sub.DeadLetteringOnFilterEvaluationExceptions.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions), sub.DeadLetteringOnFilterEvaluationExceptions.Value); + } + if (sub.DeadLetteringOnMessageExpiration.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnMessageExpiration), sub.DeadLetteringOnMessageExpiration.Value); + } + if (sub.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusSubscription.DefaultMessageTimeToLive), XmlConvert.ToString(sub.DefaultMessageTimeToLive.Value)); + } + if (sub.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(sub.DuplicateDetectionHistoryTimeWindow.Value)); + } + if (sub.EnableBatchedOperations.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusSubscription.EnableBatchedOperations), sub.EnableBatchedOperations.Value); + } + if (sub.ForwardDeadLetteredMessagesTo.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusSubscription.ForwardDeadLetteredMessagesTo), sub.ForwardDeadLetteredMessagesTo.Value); + } + if (sub.ForwardTo.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.ForwardTo), sub.ForwardTo.Value); + } + if (sub.IsClientAffine.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusSubscription.IsClientAffine), sub.IsClientAffine.Value); + } + if (sub.LockDuration.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusSubscription.LockDuration), XmlConvert.ToString(sub.LockDuration.Value)); + } + if (sub.MaxDeliveryCount.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusSubscription.MaxDeliveryCount), sub.MaxDeliveryCount.Value); + } + if (sub.RequiresSession.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusSubscription.RequiresSession), sub.RequiresSession.Value); + } + if (sub.Status.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusSubscription.Status), sub.Status.Value.ToString()); + } + writer.WriteEndObject(); // } (/Properties) + + #region Rules + writer.WriteStartArray("Rules"); // "Rules": [ + foreach (var ruleEntry in emulatorResource.Rules) + { + if (ruleEntry.TopicName != topic.IdentifierName && ruleEntry.SubscriptionName != sub.IdentifierName) + { + continue; + } + + var rule = ruleEntry.Rule; + + writer.WriteStartObject(); // { + if (rule.Name.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusQueue.Name), rule.Name.Value); + } + writer.WriteStartObject("Properties"); // "Properties": { + + if (rule.Action.Kind != BicepValueKind.Unset && rule.Action.Value != null) + { + writer.WriteStartObject(nameof(ServiceBusRule.Action)); + if (rule.Action.Value.SqlExpression.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusFilterAction.SqlExpression), rule.Action.Value.SqlExpression.Value); + } + if (rule.Action.Value.CompatibilityLevel.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusFilterAction.CompatibilityLevel), rule.Action.Value.CompatibilityLevel.Value); + } + if (rule.Action.Value.RequiresPreprocessing.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusFilterAction.RequiresPreprocessing), rule.Action.Value.RequiresPreprocessing.Value); + } + writer.WriteEndObject(); + } + + if (rule.CorrelationFilter.Kind != BicepValueKind.Unset && rule.CorrelationFilter.Value != null) + { + writer.WriteStartObject(nameof(ServiceBusRule.CorrelationFilter)); + + if (rule.CorrelationFilter.Value.ApplicationProperties.Kind != BicepValueKind.Unset && rule.CorrelationFilter.Value.ApplicationProperties != null) + { + var dic = new Dictionary(); + + foreach (var applicationProperty in rule.CorrelationFilter.Value.ApplicationProperties) + { + dic.Add(applicationProperty.Key, applicationProperty.Value); + } + + JsonSerializer.Serialize(writer, dic); + } + if (rule.CorrelationFilter.Value.CorrelationId.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.CorrelationId), rule.CorrelationFilter.Value.CorrelationId.Value); + } + if (rule.CorrelationFilter.Value.MessageId.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.MessageId), rule.CorrelationFilter.Value.MessageId.Value); + } + if (rule.CorrelationFilter.Value.SendTo.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.SendTo), rule.CorrelationFilter.Value.SendTo.Value); + } + if (rule.CorrelationFilter.Value.ReplyTo.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyTo), rule.CorrelationFilter.Value.ReplyTo.Value); + } + if (rule.CorrelationFilter.Value.Subject.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.Subject), rule.CorrelationFilter.Value.Subject.Value); + } + if (rule.CorrelationFilter.Value.SessionId.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.SessionId), rule.CorrelationFilter.Value.SessionId.Value); + } + if (rule.CorrelationFilter.Value.ReplyToSessionId.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyToSessionId), rule.CorrelationFilter.Value.ReplyToSessionId.Value); + } + if (rule.CorrelationFilter.Value.ContentType.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ContentType), rule.CorrelationFilter.Value.ContentType.Value); + } + if (rule.CorrelationFilter.Value.RequiresPreprocessing.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusCorrelationFilter.RequiresPreprocessing), rule.CorrelationFilter.Value.RequiresPreprocessing.Value); + } + + writer.WriteEndObject(); + } + + if (rule.FilterType.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusRule.FilterType), rule.FilterType.Value.ToString()); + } + + if (rule.SqlFilter.Kind != BicepValueKind.Unset && rule.SqlFilter.Value != null) + { + writer.WriteStartObject(nameof(ServiceBusRule.SqlFilter)); + if (rule.SqlFilter.Value.SqlExpression.Kind != BicepValueKind.Unset) + { + writer.WriteString(nameof(ServiceBusSqlFilter.SqlExpression), rule.SqlFilter.Value.SqlExpression.Value); + } + if (rule.SqlFilter.Value.CompatibilityLevel.Kind != BicepValueKind.Unset) + { + writer.WriteNumber(nameof(ServiceBusSqlFilter.CompatibilityLevel), rule.SqlFilter.Value.CompatibilityLevel.Value); + } + if (rule.SqlFilter.Value.RequiresPreprocessing.Kind != BicepValueKind.Unset) + { + writer.WriteBoolean(nameof(ServiceBusSqlFilter.RequiresPreprocessing), rule.SqlFilter.Value.RequiresPreprocessing.Value); + } + writer.WriteEndObject(); + } + + writer.WriteEndObject(); // } (/Rule) + } + + writer.WriteEndArray(); + #endregion Rules + + writer.WriteEndObject(); // } (/Subscription) + } + + writer.WriteEndArray(); // ] (/Subscriptions) + + writer.WriteEndObject(); // } (/Topic) } + writer.WriteEndArray(); // ] (/Topics) - writer.WriteEndArray(); // ] (/Entities) - writer.WriteEndObject(); // } - writer.WriteEndArray(); // ], (/NamespaceConfig) - writer.WriteStartObject("LoggingConfig"); // "LoggingConfig": { + writer.WriteEndObject(); // } (/Namespace) + writer.WriteEndArray(); // ], (/Namespaces) + writer.WriteStartObject("Logging"); // "Logging": { writer.WriteString("Type", "File"); // "Type": "File" writer.WriteEndObject(); // } (/LoggingConfig) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs index aedd282276..fc4cca046b 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; +using Azure.Provisioning.ServiceBus; namespace Aspire.Hosting.Azure; @@ -11,22 +12,32 @@ namespace Aspire.Hosting.Azure; /// The name of the resource. /// Callback to configure the Azure Service Bus resource. public class AzureServiceBusResource(string name, Action configureInfrastructure) - : AzureProvisioningResource(name, configureInfrastructure), IResourceWithConnectionString, IResourceWithAzureFunctionsConfig + : AzureProvisioningResource(name, configureInfrastructure), IResourceWithConnectionString, IResourceWithAzureFunctionsConfig, IResourceWithEndpoints { - internal List Queues { get; } = []; - internal List Topics { get; } = []; - internal List<(string TopicName, string Name)> Subscriptions { get; } = []; + internal List Queues { get; } = []; + internal List Topics { get; } = []; + internal List<(string TopicName, ServiceBusSubscription Subscription)> Subscriptions { get; } = []; + internal List<(string TopicName, string SubscriptionName, ServiceBusRule Rule)> Rules { get; } = []; /// /// Gets the "serviceBusEndpoint" output reference from the bicep template for the Azure Storage resource. /// public BicepOutputReference ServiceBusEndpoint => new("serviceBusEndpoint", this); + internal EndpointReference EmulatorEndpoint => new(this, "emulator"); + + /// + /// Gets a value indicating whether the Azure Service Bus resource is running in the local emulator. + /// + public bool IsEmulator => this.IsContainer(); + /// /// Gets the connection string template for the manifest for the Azure Service Bus endpoint. /// public ReferenceExpression ConnectionStringExpression => - ReferenceExpression.Create($"{ServiceBusEndpoint}"); + IsEmulator + ? ReferenceExpression.Create($"Endpoint=sb://{EmulatorEndpoint.Property(EndpointProperty.Host)}:{EmulatorEndpoint.Property(EndpointProperty.Port)};SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=SAS_KEY_VALUE;UseDevelopmentEmulator=true;") + : ReferenceExpression.Create($"{ServiceBusEndpoint}"); void IResourceWithAzureFunctionsConfig.ApplyAzureFunctionsConfiguration(IDictionary target, string connectionName) { diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt index d79d439341..0b17f00a68 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt @@ -6,10 +6,7 @@ Aspire.Hosting.Azure.AzureServiceBusResource.ServiceBusEndpoint.get -> Aspire.Ho Aspire.Hosting.AzureServiceBusExtensions static Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusNamespace!>? configureResource) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusQueue!>? configureQueue) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusSubscription!>? configureSubscription) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusTopic!>? configureTopic) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index 1ad817f411..8f65abc839 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -4,4 +4,18 @@ *REMOVED*static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusSubscription!>? configureSubscription) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! *REMOVED*static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusTopic!>? configureTopic) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! *REMOVED*Aspire.Hosting.Azure.AzureServiceBusResource.AzureServiceBusResource(string! name, System.Action! configureConstruct) -> void +Aspire.Hosting.Azure.AzureServiceBusEmulatorResource +Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.AzureServiceBusEmulatorResource(Aspire.Hosting.Azure.AzureServiceBusResource! innerResource) -> void Aspire.Hosting.Azure.AzureServiceBusResource.AzureServiceBusResource(string! name, System.Action! configureInfrastructure) -> void +Aspire.Hosting.Azure.AzureServiceBusResource.IsEmulator.get -> bool +override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Annotations.get -> Aspire.Hosting.ApplicationModel.ResourceAnnotationCollection! +override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Name.get -> string! +static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.RunAsEmulator(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, System.Action!>? configureContainer = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string? path = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.WithDataVolume(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string? name = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.WithGatewayPort(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, int? port) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs index 1edbbf1831..a2120577d5 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs @@ -6,11 +6,20 @@ namespace Aspire.Hosting.Azure.ServiceBus; internal static class ServiceBusEmulatorContainerImageTags { /// mcr.microsoft.com - public const string Registry = "mcr.microsoft.com"; + public const string Registry = "messagingemulators.azurecr.io"; - /// azure-messaging/eventhubs-emulator - public const string Image = "azure-messaging/servicebus-emulator"; + /// internal/azure-messaging/servicebus-emulator + public const string Image = "internal/azure-messaging/servicebus-emulator"; + + /// 1.0.1-alpha + public const string Tag = "1.0.1-alpha"; + + /// mcr.microsoft.com + public const string AzureSqlEdgeRegistry = "mcr.microsoft.com"; + + /// azure-sql-edge + public const string AzureSqlEdgeImage = "azure-sql-edge"; /// latest - public const string Tag = "latest"; // latest is the only arch-agnostic tag + public const string AzureSqlEdgeTag = "latest"; } From c6fdaca56893ffd3aa2e2593006741bbc91b4cbd Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Sat, 16 Nov 2024 11:34:09 -0800 Subject: [PATCH 03/17] Add healthchecks --- .../ServiceBus.AppHost/Program.cs | 68 +++---- .../AzureServiceBusExtensions.cs | 183 ++++++++++-------- .../PublicAPI.Unshipped.txt | 1 + 3 files changed, 135 insertions(+), 117 deletions(-) diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs index b5cf57f3e6..5be126c714 100644 --- a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs +++ b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs @@ -1,41 +1,41 @@ var builder = DistributedApplication.CreateBuilder(args); var serviceBus = builder.AddAzureServiceBus("sbemulator") - .RunAsEmulator(); + //.RunAsEmulator() + ; -serviceBus.AddQueue("myQueue", queue => -{ - queue.Name = "queue.1"; - queue.DeadLetteringOnMessageExpiration = false; - queue.DefaultMessageTimeToLive = TimeSpan.FromHours(1); - queue.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); - queue.ForwardDeadLetteredMessagesTo = ""; - queue.ForwardTo = ""; - queue.LockDuration = TimeSpan.FromMinutes(1); - queue.MaxDeliveryCount = 10; - queue.RequiresDuplicateDetection = false; - queue.RequiresSession = false; -}); - -serviceBus.AddTopic("myTopic", topic => -{ - topic.Name = "topic.1"; - topic.DefaultMessageTimeToLive = TimeSpan.FromHours(1); - topic.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); - topic.RequiresDuplicateDetection = false; -}); - -serviceBus.AddSubscription("myTopic", "mySubscription", sub => -{ - sub.Name = "subscription.1"; - sub.DeadLetteringOnMessageExpiration = false; - sub.DefaultMessageTimeToLive = TimeSpan.FromHours(1); - sub.LockDuration = TimeSpan.FromMinutes(1); - sub.MaxDeliveryCount = 10; - sub.ForwardDeadLetteredMessagesTo = ""; - sub.ForwardTo = ""; - sub.RequiresSession = false; -}); +serviceBus + .AddQueue("myQueue", queue => + { + queue.Name = "queue.1"; + queue.DeadLetteringOnMessageExpiration = false; + queue.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + queue.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + queue.ForwardDeadLetteredMessagesTo = ""; + queue.ForwardTo = ""; + queue.LockDuration = TimeSpan.FromMinutes(1); + queue.MaxDeliveryCount = 10; + queue.RequiresDuplicateDetection = false; + queue.RequiresSession = false; + }) + .AddTopic("myTopic", topic => + { + topic.Name = "topic.1"; + topic.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + topic.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + topic.RequiresDuplicateDetection = false; + }) + .AddSubscription("myTopic", "mySubscription", sub => + { + sub.Name = "subscription.1"; + sub.DeadLetteringOnMessageExpiration = false; + sub.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + sub.LockDuration = TimeSpan.FromMinutes(1); + sub.MaxDeliveryCount = 10; + sub.ForwardDeadLetteredMessagesTo = ""; + sub.ForwardTo = ""; + sub.RequiresSession = false; + }); builder.AddProject("worker") .WithReference(serviceBus).WaitFor(serviceBus); diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index a09bd3757a..8d2099680d 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -7,9 +7,11 @@ using Aspire.Hosting.Azure; using Aspire.Hosting.Azure.ServiceBus; using Aspire.Hosting.Utils; +using Azure.Messaging.ServiceBus; using Azure.Provisioning; using Azure.Provisioning.Expressions; using Azure.Provisioning.ServiceBus; +using Microsoft.Extensions.DependencyInjection; namespace Aspire.Hosting; @@ -69,11 +71,21 @@ public static IResourceBuilder AddAzureServiceBus(this // Topics are added in the dictionary with their normalized names. topicDictionary.Add(topic.IdentifierName, topic); } - foreach (var subscription in azureResource.Subscriptions) + var subscriptionDictionary = new Dictionary<(string, string), ServiceBusSubscription>(); + foreach (var (topicName, subscription) in azureResource.Subscriptions) { - var topic = topicDictionary[subscription.TopicName]; - subscription.Subscription.Parent = topic; - infrastructure.Add(subscription.Subscription); + var topic = topicDictionary[topicName]; + subscription.Parent = topic; + infrastructure.Add(subscription); + + // Subscriptions are added in the dictionary with their normalized names. + subscriptionDictionary.Add((topicName, subscription.IdentifierName), subscription); + } + foreach (var (topicName, subscriptionName, rule) in azureResource.Rules) + { + var subscription = subscriptionDictionary[(topicName, subscriptionName)]; + rule.Parent = subscription; + infrastructure.Add(rule); } }; @@ -100,9 +112,10 @@ public static IResourceBuilder AddTopic(this IResourceB configure?.Invoke(topic); builder.Resource.Topics.Add(topic); - foreach (var subscription in subscriptions) + foreach (var subscriptionName in subscriptions) { - builder.Resource.Subscriptions.Add((normalizedTopicName, new ServiceBusSubscription(Infrastructure.NormalizeIdentifierName(subscription)) { Name = subscription })); + var subscription = new ServiceBusSubscription(Infrastructure.NormalizeIdentifierName(subscriptionName)) { Name = subscriptionName }; + builder.Resource.Subscriptions.Add((normalizedTopicName, subscription)); } return builder; } @@ -161,9 +174,11 @@ public static IResourceBuilder AddTopic(this IResourceB public static IResourceBuilder AddSubscription(this IResourceBuilder builder, string topicName, string subscriptionName, Action? configure = null) { var normalizedTopicName = Infrastructure.NormalizeIdentifierName(topicName); - var sub = new ServiceBusSubscription(normalizedTopicName) { Name = subscriptionName }; - configure?.Invoke(sub); - builder.Resource.Subscriptions.Add((normalizedTopicName, sub)); + var normalizedSubscriptionName = Infrastructure.NormalizeIdentifierName(subscriptionName); + + var subscription = new ServiceBusSubscription(normalizedSubscriptionName) { Name = subscriptionName }; + configure?.Invoke(subscription); + builder.Resource.Subscriptions.Add((normalizedTopicName, subscription)); return builder; } @@ -267,34 +282,32 @@ public static IResourceBuilder RunAsEmulator(this IReso context.EnvironmentVariables.Add("MSSQL_SA_PASSWORD", password); })); - //ServiceBusClient? client = null; - - //builder.ApplicationBuilder.Eventing.Subscribe(builder.Resource, async (@event, ct) => - //{ - // var connectionString = await builder.Resource.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false) - // ?? throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{builder.Resource.Name}' resource but the connection string was null."); - - // // For the purposes of the health check we only need to know a queue name. If we don't have a queue - // // name we can't configure a valid producer client connection so we should throw. What good is - // // an queue namespace without a queue? :) - // if (builder.Resource.Queues is { Count: > 0 } && builder.Resource.Queues[0] is string hub) - // { - // var healthCheckConnectionString = $"{connectionString};EntityPath={hub};"; - // client = new ServiceBusClient(healthCheckConnectionString); - // } - // else - // { - // throw new DistributedApplicationException($"The '{builder.Resource.Name}' resource does not have any Event Hubs."); - // } - //}); - - //var healthCheckKey = $"{builder.Resource.Name}_check"; - //builder.ApplicationBuilder.Services.AddHealthChecks().AddAzureServiceBusQueue( - // sp => connectionString ?? throw new DistributedApplicationException("EventHubProducerClient is not initialized"), - // healthCheckKey - // ); - - //builder.WithHealthCheck(healthCheckKey); + ServiceBusClient? client = null; + string? connectionString = null; + + builder.ApplicationBuilder.Eventing.Subscribe(builder.Resource, async (@event, ct) => + { + connectionString = await builder.Resource.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false); + + if (connectionString == null) + { + throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{builder.Resource.Name}' resource but the connection string was null."); + } + + client = new ServiceBusClient(connectionString); + }); + + var healthCheckKey = $"{builder.Resource.Name}_check"; + builder.ApplicationBuilder.Services.AddHealthChecks().AddAzureServiceBusQueue(connectionStringFactory: sp => + { + return connectionString ?? throw new InvalidOperationException("ServiceBusClient is not initialized."); + }, queueNameFactory: sp => + { + var queueName = builder.Resource.Queues[0].Name.Value?.ToString(); + return queueName ?? throw new InvalidOperationException("Queue name is not initialized."); + }, name: healthCheckKey); + + builder.WithHealthCheck(healthCheckKey); if (configureContainer != null) { @@ -315,7 +328,9 @@ public static IResourceBuilder RunAsEmulator(this IReso foreach (var emulatorResource in serviceBusEmulatorResources) { - var configFileMount = emulatorResource.Annotations.OfType().Single(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath); + // A custom file mount with read-only access is used to mount the emulator configuration file. If it's not found, the read-write mount we defined on the container is used. + var configFileMount = emulatorResource.Annotations.OfType().FirstOrDefault(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath && v.IsReadOnly) + ?? emulatorResource.Annotations.OfType().Single(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath); using var stream = new FileStream(configFileMount.Source!, FileMode.Create); using var writer = new Utf8JsonWriter(stream); @@ -324,7 +339,6 @@ public static IResourceBuilder RunAsEmulator(this IReso writer.WriteStartObject("UserConfig"); // "UserConfig": { writer.WriteStartArray("Namespaces"); // "Namespaces": [ writer.WriteStartObject(); // { - // Is this name is currently required by the emulator like it is for EventHub? writer.WriteString("Name", "sbemulatorns"); // "Name": "sbemulatorns" writer.WriteStartArray("Queues"); // "Queues": [ @@ -458,108 +472,102 @@ public static IResourceBuilder RunAsEmulator(this IReso writer.WriteEndObject(); // } (/Properties) writer.WriteStartArray("Subscriptions"); // "Subscriptions": [ - foreach (var entry in emulatorResource.Subscriptions) + foreach (var (topicName, subscription) in emulatorResource.Subscriptions) { - if (entry.TopicName != topic.IdentifierName) + if (topicName != topic.IdentifierName) { continue; } - var sub = entry.Subscription; - writer.WriteStartObject(); // { if (topic.Name.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusQueue.Name), sub.Name.Value); + writer.WriteString(nameof(ServiceBusQueue.Name), subscription.Name.Value); } writer.WriteStartObject("Properties"); // "Properties": { - if (sub.Status.Kind != BicepValueKind.Unset) + if (subscription.Status.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusSubscription.AutoDeleteOnIdle), XmlConvert.ToString(sub.AutoDeleteOnIdle.Value)); + writer.WriteString(nameof(ServiceBusSubscription.AutoDeleteOnIdle), XmlConvert.ToString(subscription.AutoDeleteOnIdle.Value)); } - - if (sub.ClientAffineProperties.Kind != BicepValueKind.Unset && sub.ClientAffineProperties.Value != null) + if (subscription.ClientAffineProperties.Kind != BicepValueKind.Unset && subscription.ClientAffineProperties.Value != null) { writer.WriteStartObject("ClientAffineProperties"); // "ClientAffineProperties": { - if (sub.ClientAffineProperties.Value.ClientId.Kind != BicepValueKind.Unset) + if (subscription.ClientAffineProperties.Value.ClientId.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), sub.ClientAffineProperties.Value.ClientId.Value); + writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), subscription.ClientAffineProperties.Value.ClientId.Value); } - if (sub.ClientAffineProperties.Value.IsDurable.Kind != BicepValueKind.Unset) + if (subscription.ClientAffineProperties.Value.IsDurable.Kind != BicepValueKind.Unset) { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), sub.ClientAffineProperties.Value.IsDurable.Value); + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), subscription.ClientAffineProperties.Value.IsDurable.Value); } - if (sub.ClientAffineProperties.Value.IsShared.Kind != BicepValueKind.Unset) + if (subscription.ClientAffineProperties.Value.IsShared.Kind != BicepValueKind.Unset) { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), sub.ClientAffineProperties.Value.IsShared.Value); + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), subscription.ClientAffineProperties.Value.IsShared.Value); } writer.WriteEndObject(); // } (/ClientAffineProperties) } - - if (sub.DeadLetteringOnFilterEvaluationExceptions.Kind != BicepValueKind.Unset) + if (subscription.DeadLetteringOnFilterEvaluationExceptions.Kind != BicepValueKind.Unset) { - writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions), sub.DeadLetteringOnFilterEvaluationExceptions.Value); + writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions), subscription.DeadLetteringOnFilterEvaluationExceptions.Value); } - if (sub.DeadLetteringOnMessageExpiration.Kind != BicepValueKind.Unset) + if (subscription.DeadLetteringOnMessageExpiration.Kind != BicepValueKind.Unset) { - writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnMessageExpiration), sub.DeadLetteringOnMessageExpiration.Value); + writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnMessageExpiration), subscription.DeadLetteringOnMessageExpiration.Value); } - if (sub.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) + if (subscription.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusSubscription.DefaultMessageTimeToLive), XmlConvert.ToString(sub.DefaultMessageTimeToLive.Value)); + writer.WriteString(nameof(ServiceBusSubscription.DefaultMessageTimeToLive), XmlConvert.ToString(subscription.DefaultMessageTimeToLive.Value)); } - if (sub.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) + if (subscription.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(sub.DuplicateDetectionHistoryTimeWindow.Value)); + writer.WriteString(nameof(ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(subscription.DuplicateDetectionHistoryTimeWindow.Value)); } - if (sub.EnableBatchedOperations.Kind != BicepValueKind.Unset) + if (subscription.EnableBatchedOperations.Kind != BicepValueKind.Unset) { - writer.WriteBoolean(nameof(ServiceBusSubscription.EnableBatchedOperations), sub.EnableBatchedOperations.Value); + writer.WriteBoolean(nameof(ServiceBusSubscription.EnableBatchedOperations), subscription.EnableBatchedOperations.Value); } - if (sub.ForwardDeadLetteredMessagesTo.Kind != BicepValueKind.Unset) + if (subscription.ForwardDeadLetteredMessagesTo.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusSubscription.ForwardDeadLetteredMessagesTo), sub.ForwardDeadLetteredMessagesTo.Value); + writer.WriteString(nameof(ServiceBusSubscription.ForwardDeadLetteredMessagesTo), subscription.ForwardDeadLetteredMessagesTo.Value); } - if (sub.ForwardTo.Kind != BicepValueKind.Unset) + if (subscription.ForwardTo.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusQueue.ForwardTo), sub.ForwardTo.Value); + writer.WriteString(nameof(ServiceBusQueue.ForwardTo), subscription.ForwardTo.Value); } - if (sub.IsClientAffine.Kind != BicepValueKind.Unset) + if (subscription.IsClientAffine.Kind != BicepValueKind.Unset) { - writer.WriteBoolean(nameof(ServiceBusSubscription.IsClientAffine), sub.IsClientAffine.Value); + writer.WriteBoolean(nameof(ServiceBusSubscription.IsClientAffine), subscription.IsClientAffine.Value); } - if (sub.LockDuration.Kind != BicepValueKind.Unset) + if (subscription.LockDuration.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusSubscription.LockDuration), XmlConvert.ToString(sub.LockDuration.Value)); + writer.WriteString(nameof(ServiceBusSubscription.LockDuration), XmlConvert.ToString(subscription.LockDuration.Value)); } - if (sub.MaxDeliveryCount.Kind != BicepValueKind.Unset) + if (subscription.MaxDeliveryCount.Kind != BicepValueKind.Unset) { - writer.WriteNumber(nameof(ServiceBusSubscription.MaxDeliveryCount), sub.MaxDeliveryCount.Value); + writer.WriteNumber(nameof(ServiceBusSubscription.MaxDeliveryCount), subscription.MaxDeliveryCount.Value); } - if (sub.RequiresSession.Kind != BicepValueKind.Unset) + if (subscription.RequiresSession.Kind != BicepValueKind.Unset) { - writer.WriteBoolean(nameof(ServiceBusSubscription.RequiresSession), sub.RequiresSession.Value); + writer.WriteBoolean(nameof(ServiceBusSubscription.RequiresSession), subscription.RequiresSession.Value); } - if (sub.Status.Kind != BicepValueKind.Unset) + if (subscription.Status.Kind != BicepValueKind.Unset) { - writer.WriteString(nameof(ServiceBusSubscription.Status), sub.Status.Value.ToString()); + writer.WriteString(nameof(ServiceBusSubscription.Status), subscription.Status.Value.ToString()); } writer.WriteEndObject(); // } (/Properties) #region Rules writer.WriteStartArray("Rules"); // "Rules": [ - foreach (var ruleEntry in emulatorResource.Rules) + foreach (var (ruleTopicName, ruleSubscriptionName, rule) in emulatorResource.Rules) { - if (ruleEntry.TopicName != topic.IdentifierName && ruleEntry.SubscriptionName != sub.IdentifierName) + if (ruleTopicName != topic.IdentifierName && ruleSubscriptionName != subscription.IdentifierName) { continue; } - var rule = ruleEntry.Rule; - writer.WriteStartObject(); // { if (rule.Name.Kind != BicepValueKind.Unset) { @@ -714,6 +722,15 @@ public static IResourceBuilder WithDataBindMoun public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null) => builder.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/data", isReadOnly: false); + /// + /// Adds a bind mount for the configuration file of an Azure Service Bus emulator resource. + /// + /// The builder for the . + /// Path to the file on the AppHost where the emulator configuration is located. + /// A builder for the . + public static IResourceBuilder WithConfigJson(this IResourceBuilder builder, string path) + => builder.WithBindMount(path, AzureServiceBusEmulatorResource.EmulatorConfigJsonPath, isReadOnly: true); + /// /// Configures the gateway port for the Azure Service Bus emulator. /// diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index 8f65abc839..c2018cbd8b 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -16,6 +16,7 @@ static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Host static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.RunAsEmulator(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, System.Action!>? configureContainer = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.WithConfigJson(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! path) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string? path = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithDataVolume(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string? name = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithGatewayPort(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, int? port) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! From 8ecc4fd7caa1ba143c4ff3088869df696ea6ed54 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Sat, 16 Nov 2024 11:59:15 -0800 Subject: [PATCH 04/17] React to breaking changes --- .../ServiceBus.AppHost/Program.cs | 2 - .../Aspire.Hosting.Azure.ServiceBus.csproj | 1 - .../AzureServiceBusExtensions.cs | 204 +++++++++--------- 3 files changed, 103 insertions(+), 104 deletions(-) diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs index 5be126c714..c8fc200811 100644 --- a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs +++ b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs @@ -12,7 +12,6 @@ queue.DefaultMessageTimeToLive = TimeSpan.FromHours(1); queue.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); queue.ForwardDeadLetteredMessagesTo = ""; - queue.ForwardTo = ""; queue.LockDuration = TimeSpan.FromMinutes(1); queue.MaxDeliveryCount = 10; queue.RequiresDuplicateDetection = false; @@ -33,7 +32,6 @@ sub.LockDuration = TimeSpan.FromMinutes(1); sub.MaxDeliveryCount = 10; sub.ForwardDeadLetteredMessagesTo = ""; - sub.ForwardTo = ""; sub.RequiresSession = false; }); diff --git a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj index d2e5b5ce10..46610ed3ec 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj +++ b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj @@ -14,7 +14,6 @@ - diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index 883d849243..12aa48792d 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -68,7 +68,7 @@ public static IResourceBuilder AddAzureServiceBus(this infrastructure.Add(topic); // Topics are added in the dictionary with their normalized names. - topicDictionary.Add(topic.IdentifierName, topic); + topicDictionary.Add(topic.BicepIdentifier, topic); } var subscriptionDictionary = new Dictionary<(string, string), ServiceBusSubscription>(); foreach (var (topicName, subscription) in azureResource.Subscriptions) @@ -78,7 +78,7 @@ public static IResourceBuilder AddAzureServiceBus(this infrastructure.Add(subscription); // Subscriptions are added in the dictionary with their normalized names. - subscriptionDictionary.Add((topicName, subscription.IdentifierName), subscription); + subscriptionDictionary.Add((topicName, subscription.BicepIdentifier), subscription); } foreach (var (topicName, subscriptionName, rule) in azureResource.Rules) { @@ -105,7 +105,7 @@ public static IResourceBuilder AddAzureServiceBus(this /// An optional method that can be used for customizing the . public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, string[] subscriptions, Action? configure = null) { - var normalizedTopicName = Infrastructure.NormalizeIdentifierName(name); + var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(name); var topic = new ServiceBusTopic(normalizedTopicName) { Name = name }; configure?.Invoke(topic); @@ -113,7 +113,7 @@ public static IResourceBuilder AddTopic(this IResourceB builder.Resource.Topics.Add(topic); foreach (var subscriptionName in subscriptions) { - var subscription = new ServiceBusSubscription(Infrastructure.NormalizeIdentifierName(subscriptionName)) { Name = subscriptionName }; + var subscription = new ServiceBusSubscription(Infrastructure.NormalizeBicepIdentifier(subscriptionName)) { Name = subscriptionName }; builder.Resource.Subscriptions.Add((normalizedTopicName, subscription)); } return builder; @@ -127,7 +127,7 @@ public static IResourceBuilder AddTopic(this IResourceB /// An optional method that can be used for customizing the . public static IResourceBuilder AddQueue(this IResourceBuilder builder, [ResourceName] string name, Action? configure = null) { - var queue = new ServiceBusQueue(Infrastructure.NormalizeIdentifierName(name)) { Name = name }; + var queue = new ServiceBusQueue(Infrastructure.NormalizeBicepIdentifier(name)) { Name = name }; configure?.Invoke(queue); @@ -142,7 +142,7 @@ public static IResourceBuilder AddQueue(this IResourceB /// The name of the topic. public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name) { - var topic = new ServiceBusTopic(Infrastructure.NormalizeIdentifierName(name)) { Name = name }; + var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name)) { Name = name }; builder.Resource.Topics.Add(topic); return builder; @@ -156,7 +156,7 @@ public static IResourceBuilder AddTopic(this IResourceB /// An optional method that can be used for customizing the . public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, Action configure) { - var topic = new ServiceBusTopic(Infrastructure.NormalizeIdentifierName(name)) { Name = name }; + var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name)) { Name = name }; configure?.Invoke(topic); builder.Resource.Topics.Add(topic); @@ -172,8 +172,8 @@ public static IResourceBuilder AddTopic(this IResourceB /// An optional method that can be used for customizing the . public static IResourceBuilder AddSubscription(this IResourceBuilder builder, string topicName, string subscriptionName, Action? configure = null) { - var normalizedTopicName = Infrastructure.NormalizeIdentifierName(topicName); - var normalizedSubscriptionName = Infrastructure.NormalizeIdentifierName(subscriptionName); + var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(topicName); + var normalizedSubscriptionName = Infrastructure.NormalizeBicepIdentifier(subscriptionName); var subscription = new ServiceBusSubscription(normalizedSubscriptionName) { Name = subscriptionName }; configure?.Invoke(subscription); @@ -191,9 +191,9 @@ public static IResourceBuilder AddSubscription(this IRe /// An optional method that can be used for customizing the . public static IResourceBuilder AddRule(this IResourceBuilder builder, string topicName, string subscriptionName, string ruleName, Action? configure = null) { - var normalizedTopicName = Infrastructure.NormalizeIdentifierName(topicName); - var normalizedSubscriptionName = Infrastructure.NormalizeIdentifierName(subscriptionName); - var normalizedRuleName = Infrastructure.NormalizeIdentifierName(ruleName); + var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(topicName); + var normalizedSubscriptionName = Infrastructure.NormalizeBicepIdentifier(subscriptionName); + var normalizedRuleName = Infrastructure.NormalizeBicepIdentifier(ruleName); var rule = new ServiceBusRule(normalizedRuleName) { Name = ruleName }; configure?.Invoke(rule); @@ -344,72 +344,72 @@ public static IResourceBuilder RunAsEmulator(this IReso foreach (var queue in emulatorResource.Queues) { writer.WriteStartObject(); // { - if (queue.Name.Kind != BicepValueKind.Unset) + if (((IBicepValue)queue.Name).IsSet()) { writer.WriteString(nameof(ServiceBusQueue.Name), queue.Name.Value); } writer.WriteStartObject("Properties"); // "Properties": { - if (queue.AutoDeleteOnIdle.Kind != BicepValueKind.Unset) + if (queue.AutoDeleteOnIdle.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.AutoDeleteOnIdle), XmlConvert.ToString(queue.AutoDeleteOnIdle.Value)); } - if (queue.DeadLetteringOnMessageExpiration.Kind != BicepValueKind.Unset) + if (queue.DeadLetteringOnMessageExpiration.IsSet()) { writer.WriteBoolean(nameof(ServiceBusQueue.DeadLetteringOnMessageExpiration), queue.DeadLetteringOnMessageExpiration.Value); } - if (queue.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) + if (queue.DefaultMessageTimeToLive.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.DefaultMessageTimeToLive), XmlConvert.ToString(queue.DefaultMessageTimeToLive.Value)); } - if (queue.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) + if (queue.DuplicateDetectionHistoryTimeWindow.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(queue.DuplicateDetectionHistoryTimeWindow.Value)); } - if (queue.EnableBatchedOperations.Kind != BicepValueKind.Unset) + if (queue.EnableBatchedOperations.IsSet()) { writer.WriteBoolean(nameof(ServiceBusQueue.EnableBatchedOperations), queue.EnableBatchedOperations.Value); } - if (queue.EnableExpress.Kind != BicepValueKind.Unset) + if (queue.EnableExpress.IsSet()) { writer.WriteBoolean(nameof(ServiceBusQueue.EnableExpress), queue.EnableExpress.Value); } - if (queue.EnablePartitioning.Kind != BicepValueKind.Unset) + if (queue.EnablePartitioning.IsSet()) { writer.WriteBoolean(nameof(ServiceBusQueue.EnablePartitioning), queue.EnablePartitioning.Value); } - if (queue.ForwardDeadLetteredMessagesTo.Kind != BicepValueKind.Unset) + if (queue.ForwardDeadLetteredMessagesTo.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.ForwardDeadLetteredMessagesTo), queue.ForwardDeadLetteredMessagesTo.Value); } - if (queue.ForwardTo.Kind != BicepValueKind.Unset) + if (queue.ForwardTo.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.ForwardTo), queue.ForwardTo.Value); } - if (queue.LockDuration.Kind != BicepValueKind.Unset) + if (queue.LockDuration.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.LockDuration), XmlConvert.ToString(queue.LockDuration.Value)); } - if (queue.MaxDeliveryCount.Kind != BicepValueKind.Unset) + if (queue.MaxDeliveryCount.IsSet()) { writer.WriteNumber(nameof(ServiceBusQueue.MaxDeliveryCount), queue.MaxDeliveryCount.Value); } - if (queue.MaxMessageSizeInKilobytes.Kind != BicepValueKind.Unset) + if (queue.MaxMessageSizeInKilobytes.IsSet()) { writer.WriteNumber(nameof(ServiceBusQueue.MaxMessageSizeInKilobytes), queue.MaxMessageSizeInKilobytes.Value); } - if (queue.MaxSizeInMegabytes.Kind != BicepValueKind.Unset) + if (queue.MaxSizeInMegabytes.IsSet()) { writer.WriteNumber(nameof(ServiceBusQueue.MaxSizeInMegabytes), queue.MaxSizeInMegabytes.Value); } - if (queue.RequiresDuplicateDetection.Kind != BicepValueKind.Unset) + if (queue.RequiresDuplicateDetection.IsSet()) { writer.WriteBoolean(nameof(ServiceBusQueue.RequiresDuplicateDetection), queue.RequiresDuplicateDetection.Value); } - if (queue.RequiresSession.Kind != BicepValueKind.Unset) + if (queue.RequiresSession.IsSet()) { writer.WriteBoolean(nameof(ServiceBusQueue.RequiresSession), queue.RequiresSession.Value); } - if (queue.Status.Kind != BicepValueKind.Unset) + if (queue.Status.IsSet()) { writer.WriteString(nameof(ServiceBusTopic.Status), queue.Status.Value.ToString()); } @@ -423,48 +423,48 @@ public static IResourceBuilder RunAsEmulator(this IReso foreach (var topic in emulatorResource.Topics) { writer.WriteStartObject(); // { - if (topic.Name.Kind != BicepValueKind.Unset) + if (topic.Name.IsSet()) { writer.WriteString(nameof(ServiceBusTopic.Name), topic.Name.Value); } writer.WriteStartObject("Properties"); // "Properties": { - if (topic.AutoDeleteOnIdle.Kind != BicepValueKind.Unset) + if (topic.AutoDeleteOnIdle.IsSet()) { writer.WriteString(nameof(ServiceBusTopic.AutoDeleteOnIdle), XmlConvert.ToString(topic.AutoDeleteOnIdle.Value)); } - if (topic.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) + if (topic.DefaultMessageTimeToLive.IsSet()) { writer.WriteString(nameof(ServiceBusTopic.DefaultMessageTimeToLive), XmlConvert.ToString(topic.DefaultMessageTimeToLive.Value)); } - if (topic.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) + if (topic.DuplicateDetectionHistoryTimeWindow.IsSet()) { writer.WriteString(nameof(ServiceBusTopic.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(topic.DuplicateDetectionHistoryTimeWindow.Value)); } - if (topic.EnableBatchedOperations.Kind != BicepValueKind.Unset) + if (topic.EnableBatchedOperations.IsSet()) { writer.WriteBoolean(nameof(ServiceBusTopic.EnableBatchedOperations), topic.EnableBatchedOperations.Value); } - if (topic.EnableExpress.Kind != BicepValueKind.Unset) + if (topic.EnableExpress.IsSet()) { writer.WriteBoolean(nameof(ServiceBusTopic.EnableExpress), topic.EnableExpress.Value); } - if (topic.EnablePartitioning.Kind != BicepValueKind.Unset) + if (topic.EnablePartitioning.IsSet()) { writer.WriteBoolean(nameof(ServiceBusTopic.EnablePartitioning), topic.EnablePartitioning.Value); } - if (topic.MaxMessageSizeInKilobytes.Kind != BicepValueKind.Unset) + if (topic.MaxMessageSizeInKilobytes.IsSet()) { writer.WriteNumber(nameof(ServiceBusTopic.MaxMessageSizeInKilobytes), topic.MaxMessageSizeInKilobytes.Value); } - if (topic.MaxSizeInMegabytes.Kind != BicepValueKind.Unset) + if (topic.MaxSizeInMegabytes.IsSet()) { writer.WriteNumber(nameof(ServiceBusTopic.MaxSizeInMegabytes), topic.MaxSizeInMegabytes.Value); } - if (topic.RequiresDuplicateDetection.Kind != BicepValueKind.Unset) + if (topic.RequiresDuplicateDetection.IsSet()) { writer.WriteBoolean(nameof(ServiceBusTopic.RequiresDuplicateDetection), topic.RequiresDuplicateDetection.Value); } - if (topic.Status.Kind != BicepValueKind.Unset) + if (topic.Status.IsSet()) { writer.WriteString(nameof(ServiceBusTopic.Status), topic.Status.Value.ToString()); } @@ -473,86 +473,86 @@ public static IResourceBuilder RunAsEmulator(this IReso writer.WriteStartArray("Subscriptions"); // "Subscriptions": [ foreach (var (topicName, subscription) in emulatorResource.Subscriptions) { - if (topicName != topic.IdentifierName) + if (topicName != topic.BicepIdentifier) { continue; } writer.WriteStartObject(); // { - if (topic.Name.Kind != BicepValueKind.Unset) + if (topic.Name.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.Name), subscription.Name.Value); } writer.WriteStartObject("Properties"); // "Properties": { - if (subscription.Status.Kind != BicepValueKind.Unset) + if (subscription.Status.IsSet()) { writer.WriteString(nameof(ServiceBusSubscription.AutoDeleteOnIdle), XmlConvert.ToString(subscription.AutoDeleteOnIdle.Value)); } - if (subscription.ClientAffineProperties.Kind != BicepValueKind.Unset && subscription.ClientAffineProperties.Value != null) + if (subscription.ClientAffineProperties.IsSet() && subscription.ClientAffineProperties != null) { writer.WriteStartObject("ClientAffineProperties"); // "ClientAffineProperties": { - if (subscription.ClientAffineProperties.Value.ClientId.Kind != BicepValueKind.Unset) + if (subscription.ClientAffineProperties.ClientId.IsSet()) { - writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), subscription.ClientAffineProperties.Value.ClientId.Value); + writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), subscription.ClientAffineProperties.ClientId.Value); } - if (subscription.ClientAffineProperties.Value.IsDurable.Kind != BicepValueKind.Unset) + if (subscription.ClientAffineProperties.IsDurable.IsSet()) { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), subscription.ClientAffineProperties.Value.IsDurable.Value); + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), subscription.ClientAffineProperties.IsDurable.Value); } - if (subscription.ClientAffineProperties.Value.IsShared.Kind != BicepValueKind.Unset) + if (subscription.ClientAffineProperties.IsShared.IsSet()) { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), subscription.ClientAffineProperties.Value.IsShared.Value); + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), subscription.ClientAffineProperties.IsShared.Value); } writer.WriteEndObject(); // } (/ClientAffineProperties) } - if (subscription.DeadLetteringOnFilterEvaluationExceptions.Kind != BicepValueKind.Unset) + if (subscription.DeadLetteringOnFilterEvaluationExceptions.IsSet()) { writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions), subscription.DeadLetteringOnFilterEvaluationExceptions.Value); } - if (subscription.DeadLetteringOnMessageExpiration.Kind != BicepValueKind.Unset) + if (subscription.DeadLetteringOnMessageExpiration.IsSet()) { writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnMessageExpiration), subscription.DeadLetteringOnMessageExpiration.Value); } - if (subscription.DefaultMessageTimeToLive.Kind != BicepValueKind.Unset) + if (subscription.DefaultMessageTimeToLive.IsSet()) { writer.WriteString(nameof(ServiceBusSubscription.DefaultMessageTimeToLive), XmlConvert.ToString(subscription.DefaultMessageTimeToLive.Value)); } - if (subscription.DuplicateDetectionHistoryTimeWindow.Kind != BicepValueKind.Unset) + if (subscription.DuplicateDetectionHistoryTimeWindow.IsSet()) { writer.WriteString(nameof(ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(subscription.DuplicateDetectionHistoryTimeWindow.Value)); } - if (subscription.EnableBatchedOperations.Kind != BicepValueKind.Unset) + if (subscription.EnableBatchedOperations.IsSet()) { writer.WriteBoolean(nameof(ServiceBusSubscription.EnableBatchedOperations), subscription.EnableBatchedOperations.Value); } - if (subscription.ForwardDeadLetteredMessagesTo.Kind != BicepValueKind.Unset) + if (subscription.ForwardDeadLetteredMessagesTo.IsSet()) { writer.WriteString(nameof(ServiceBusSubscription.ForwardDeadLetteredMessagesTo), subscription.ForwardDeadLetteredMessagesTo.Value); } - if (subscription.ForwardTo.Kind != BicepValueKind.Unset) + if (subscription.ForwardTo.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.ForwardTo), subscription.ForwardTo.Value); } - if (subscription.IsClientAffine.Kind != BicepValueKind.Unset) + if (subscription.IsClientAffine.IsSet()) { writer.WriteBoolean(nameof(ServiceBusSubscription.IsClientAffine), subscription.IsClientAffine.Value); } - if (subscription.LockDuration.Kind != BicepValueKind.Unset) + if (subscription.LockDuration.IsSet()) { writer.WriteString(nameof(ServiceBusSubscription.LockDuration), XmlConvert.ToString(subscription.LockDuration.Value)); } - if (subscription.MaxDeliveryCount.Kind != BicepValueKind.Unset) + if (subscription.MaxDeliveryCount.IsSet()) { writer.WriteNumber(nameof(ServiceBusSubscription.MaxDeliveryCount), subscription.MaxDeliveryCount.Value); } - if (subscription.RequiresSession.Kind != BicepValueKind.Unset) + if (subscription.RequiresSession.IsSet()) { writer.WriteBoolean(nameof(ServiceBusSubscription.RequiresSession), subscription.RequiresSession.Value); } - if (subscription.Status.Kind != BicepValueKind.Unset) + if (subscription.Status.IsSet()) { writer.WriteString(nameof(ServiceBusSubscription.Status), subscription.Status.Value.ToString()); } @@ -562,110 +562,110 @@ public static IResourceBuilder RunAsEmulator(this IReso writer.WriteStartArray("Rules"); // "Rules": [ foreach (var (ruleTopicName, ruleSubscriptionName, rule) in emulatorResource.Rules) { - if (ruleTopicName != topic.IdentifierName && ruleSubscriptionName != subscription.IdentifierName) + if (ruleTopicName != topic.BicepIdentifier && ruleSubscriptionName != subscription.BicepIdentifier) { continue; } writer.WriteStartObject(); // { - if (rule.Name.Kind != BicepValueKind.Unset) + if (rule.Name.IsSet()) { writer.WriteString(nameof(ServiceBusQueue.Name), rule.Name.Value); } writer.WriteStartObject("Properties"); // "Properties": { - if (rule.Action.Kind != BicepValueKind.Unset && rule.Action.Value != null) + if (rule.Action.IsSet() && rule.Action != null) { writer.WriteStartObject(nameof(ServiceBusRule.Action)); - if (rule.Action.Value.SqlExpression.Kind != BicepValueKind.Unset) + if (rule.Action.SqlExpression.IsSet()) { - writer.WriteString(nameof(ServiceBusFilterAction.SqlExpression), rule.Action.Value.SqlExpression.Value); + writer.WriteString(nameof(ServiceBusFilterAction.SqlExpression), rule.Action.SqlExpression.Value); } - if (rule.Action.Value.CompatibilityLevel.Kind != BicepValueKind.Unset) + if (rule.Action.CompatibilityLevel.IsSet()) { - writer.WriteNumber(nameof(ServiceBusFilterAction.CompatibilityLevel), rule.Action.Value.CompatibilityLevel.Value); + writer.WriteNumber(nameof(ServiceBusFilterAction.CompatibilityLevel), rule.Action.CompatibilityLevel.Value); } - if (rule.Action.Value.RequiresPreprocessing.Kind != BicepValueKind.Unset) + if (rule.Action.RequiresPreprocessing.IsSet()) { - writer.WriteBoolean(nameof(ServiceBusFilterAction.RequiresPreprocessing), rule.Action.Value.RequiresPreprocessing.Value); + writer.WriteBoolean(nameof(ServiceBusFilterAction.RequiresPreprocessing), rule.Action.RequiresPreprocessing.Value); } writer.WriteEndObject(); } - if (rule.CorrelationFilter.Kind != BicepValueKind.Unset && rule.CorrelationFilter.Value != null) + if (rule.CorrelationFilter.IsSet() && rule.CorrelationFilter != null) { writer.WriteStartObject(nameof(ServiceBusRule.CorrelationFilter)); - if (rule.CorrelationFilter.Value.ApplicationProperties.Kind != BicepValueKind.Unset && rule.CorrelationFilter.Value.ApplicationProperties != null) + if (rule.CorrelationFilter.ApplicationProperties.IsSet() && rule.CorrelationFilter.ApplicationProperties != null) { var dic = new Dictionary(); - foreach (var applicationProperty in rule.CorrelationFilter.Value.ApplicationProperties) + foreach (var applicationProperty in rule.CorrelationFilter.ApplicationProperties) { dic.Add(applicationProperty.Key, applicationProperty.Value); } JsonSerializer.Serialize(writer, dic); } - if (rule.CorrelationFilter.Value.CorrelationId.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.CorrelationId.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.CorrelationId), rule.CorrelationFilter.Value.CorrelationId.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.CorrelationId), rule.CorrelationFilter.CorrelationId.Value); } - if (rule.CorrelationFilter.Value.MessageId.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.MessageId.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.MessageId), rule.CorrelationFilter.Value.MessageId.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.MessageId), rule.CorrelationFilter.MessageId.Value); } - if (rule.CorrelationFilter.Value.SendTo.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.SendTo.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.SendTo), rule.CorrelationFilter.Value.SendTo.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.SendTo), rule.CorrelationFilter.SendTo.Value); } - if (rule.CorrelationFilter.Value.ReplyTo.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.ReplyTo.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyTo), rule.CorrelationFilter.Value.ReplyTo.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyTo), rule.CorrelationFilter.ReplyTo.Value); } - if (rule.CorrelationFilter.Value.Subject.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.Subject.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.Subject), rule.CorrelationFilter.Value.Subject.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.Subject), rule.CorrelationFilter.Subject.Value); } - if (rule.CorrelationFilter.Value.SessionId.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.SessionId.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.SessionId), rule.CorrelationFilter.Value.SessionId.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.SessionId), rule.CorrelationFilter.SessionId.Value); } - if (rule.CorrelationFilter.Value.ReplyToSessionId.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.ReplyToSessionId.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyToSessionId), rule.CorrelationFilter.Value.ReplyToSessionId.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyToSessionId), rule.CorrelationFilter.ReplyToSessionId.Value); } - if (rule.CorrelationFilter.Value.ContentType.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.ContentType.IsSet()) { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ContentType), rule.CorrelationFilter.Value.ContentType.Value); + writer.WriteString(nameof(ServiceBusCorrelationFilter.ContentType), rule.CorrelationFilter.ContentType.Value); } - if (rule.CorrelationFilter.Value.RequiresPreprocessing.Kind != BicepValueKind.Unset) + if (rule.CorrelationFilter.RequiresPreprocessing.IsSet()) { - writer.WriteBoolean(nameof(ServiceBusCorrelationFilter.RequiresPreprocessing), rule.CorrelationFilter.Value.RequiresPreprocessing.Value); + writer.WriteBoolean(nameof(ServiceBusCorrelationFilter.RequiresPreprocessing), rule.CorrelationFilter.RequiresPreprocessing.Value); } writer.WriteEndObject(); } - if (rule.FilterType.Kind != BicepValueKind.Unset) + if (rule.FilterType.IsSet()) { writer.WriteString(nameof(ServiceBusRule.FilterType), rule.FilterType.Value.ToString()); } - if (rule.SqlFilter.Kind != BicepValueKind.Unset && rule.SqlFilter.Value != null) + if (rule.SqlFilter.IsSet() && rule.SqlFilter != null) { writer.WriteStartObject(nameof(ServiceBusRule.SqlFilter)); - if (rule.SqlFilter.Value.SqlExpression.Kind != BicepValueKind.Unset) + if (rule.SqlFilter.SqlExpression.IsSet()) { - writer.WriteString(nameof(ServiceBusSqlFilter.SqlExpression), rule.SqlFilter.Value.SqlExpression.Value); + writer.WriteString(nameof(ServiceBusSqlFilter.SqlExpression), rule.SqlFilter.SqlExpression.Value); } - if (rule.SqlFilter.Value.CompatibilityLevel.Kind != BicepValueKind.Unset) + if (rule.SqlFilter.CompatibilityLevel.IsSet()) { - writer.WriteNumber(nameof(ServiceBusSqlFilter.CompatibilityLevel), rule.SqlFilter.Value.CompatibilityLevel.Value); + writer.WriteNumber(nameof(ServiceBusSqlFilter.CompatibilityLevel), rule.SqlFilter.CompatibilityLevel.Value); } - if (rule.SqlFilter.Value.RequiresPreprocessing.Kind != BicepValueKind.Unset) + if (rule.SqlFilter.RequiresPreprocessing.IsSet()) { - writer.WriteBoolean(nameof(ServiceBusSqlFilter.RequiresPreprocessing), rule.SqlFilter.Value.RequiresPreprocessing.Value); + writer.WriteBoolean(nameof(ServiceBusSqlFilter.RequiresPreprocessing), rule.SqlFilter.RequiresPreprocessing.Value); } writer.WriteEndObject(); } @@ -719,7 +719,7 @@ public static IResourceBuilder WithDataBindMoun /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. /// A builder for the . public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null) - => builder.WithVolume(name ?? VolumeNameGenerator.CreateVolumeName(builder, "data"), "/data", isReadOnly: false); + => builder.WithVolume(name ?? VolumeNameGenerator.Generate(builder, "data"), "/data", isReadOnly: false); /// /// Adds a bind mount for the configuration file of an Azure Service Bus emulator resource. @@ -743,4 +743,6 @@ public static IResourceBuilder WithGatewayPort( endpoint.Port = port; }); } + + private static bool IsSet(this IBicepValue value) => value.Kind != BicepValueKind.Unset; } From 698faae166b5654c759970618d6d013359bdbdde Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 18 Nov 2024 18:03:50 -0800 Subject: [PATCH 05/17] Create common model for emulator and cdk --- .../ServiceBus.AppHost/Program.cs | 55 ++- .../ApplicationModel/OptionalValue.cs | 70 ++++ .../ServiceBusClientAffineProperties.cs | 51 +++ .../ServiceBusCorrelationFilter.cs | 118 ++++++ .../ServiceBusFilterAction.cs | 50 +++ .../ApplicationModel/ServiceBusFilterType.cs | 20 + .../ServiceBusMessagingEntityStatus.cs | 55 +++ .../ApplicationModel/ServiceBusQueue.cs | 369 ++++++++++++++++++ .../ApplicationModel/ServiceBusRule.cs | 302 ++++++++++++++ .../ApplicationModel/ServiceBusSqlFilter.cs | 50 +++ .../ServiceBusSubscription.cs | 359 +++++++++++++++++ .../ApplicationModel/ServiceBusTopic.cs | 322 +++++++++++++++ .../AzureServiceBusExtensions.cs | 369 ++---------------- .../AzureServiceBusResource.cs | 2 +- .../PublicAPI.Unshipped.txt | 206 +++++++++- .../ServiceBusEmulatorContainerImageTags.cs | 10 +- 16 files changed, 2049 insertions(+), 359 deletions(-) create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs index c8fc200811..46dcb76336 100644 --- a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs +++ b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs @@ -1,7 +1,9 @@ +//using Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + var builder = DistributedApplication.CreateBuilder(args); var serviceBus = builder.AddAzureServiceBus("sbemulator") - //.RunAsEmulator() + .RunAsEmulator() // Comment to deploy and use the Azure cloud ; serviceBus @@ -17,23 +19,40 @@ queue.RequiresDuplicateDetection = false; queue.RequiresSession = false; }) - .AddTopic("myTopic", topic => - { - topic.Name = "topic.1"; - topic.DefaultMessageTimeToLive = TimeSpan.FromHours(1); - topic.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); - topic.RequiresDuplicateDetection = false; - }) - .AddSubscription("myTopic", "mySubscription", sub => - { - sub.Name = "subscription.1"; - sub.DeadLetteringOnMessageExpiration = false; - sub.DefaultMessageTimeToLive = TimeSpan.FromHours(1); - sub.LockDuration = TimeSpan.FromMinutes(1); - sub.MaxDeliveryCount = 10; - sub.ForwardDeadLetteredMessagesTo = ""; - sub.RequiresSession = false; - }); + //.AddTopic("myTopic", topic => + //{ + // topic.Name = "topic.1"; + // topic.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + // topic.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + // topic.RequiresDuplicateDetection = false; + //}) + //.AddSubscription("myTopic", "mySubscription", sub => + //{ + // sub.Name = "subscription.1"; + // sub.DeadLetteringOnMessageExpiration = false; + // sub.DefaultMessageTimeToLive = TimeSpan.FromHours(1); + // sub.LockDuration = TimeSpan.FromMinutes(1); + // sub.MaxDeliveryCount = 10; + // sub.ForwardDeadLetteredMessagesTo = ""; + // sub.RequiresSession = false; + //}) + //.AddRule("myTopic", "mySubscription", "myRule", rule => + //{ + // rule.Name = "app-prop-filter-1"; + // rule.FilterType = ServiceBusFilterType.CorrelationFilter; + // rule.CorrelationFilter = new ServiceBusCorrelationFilter + // { + // ContentType = "application/text", + // CorrelationId = "id1", + // Subject = "subject1", + // MessageId = "msgid1", + // ReplyTo = "someQueue", + // ReplyToSessionId = "sessionId", + // SessionId = "session1", + // SendTo = "xyz" + // }; + //}) + ; builder.AddProject("worker") .WithReference(serviceBus).WaitFor(serviceBus); diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs new file mode 100644 index 0000000000..81a05d6414 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents an optional value. +/// +/// The type of the value. +public sealed class OptionalValue +{ + + /// + /// Initializes a new instance of the class. + /// + public OptionalValue() + { + Value = default; + } + + /// + /// Initializes a new instance of the class with a specified value. + /// + /// The value to initialize with. + public OptionalValue(T value) + { + Value = value; + IsSet = true; + } + + /// + /// Gets or sets the literal value. + /// + public T? Value { get; private set; } + + /// + /// Gets a value indicating whether the value has been set. + /// + public bool IsSet { get; private set; } + + /// + /// Assigns a value. + /// + /// The value to assign. + internal void Assign(OptionalValue lazyValue) + { + Value = lazyValue.Value; + IsSet = true; + } + + /// + /// Implicitly converts a value to a LazyValue{T}. + /// + /// The value to convert. + /// A LazyValue{T} containing the value. + public static implicit operator OptionalValue(T value) + { + return new(value); + } + + /// + /// Implicitly converts a value to a LazyValue{T}. + /// + /// The value to convert. + /// A LazyValue{T} containing the value. + public static implicit operator T?(OptionalValue value) + { + return value.Value; + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs new file mode 100644 index 0000000000..a64743b070 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Properties specific to client affine subscriptions. +/// +public class ServiceBusClientAffineProperties +{ + private readonly OptionalValue _clientId = new(); + private readonly OptionalValue _isDurable = new(); + private readonly OptionalValue _isShared = new(); + + /// + /// Creates a new ServiceBusClientAffineProperties. + /// + public ServiceBusClientAffineProperties() + { + } + + /// + /// Indicates the Client ID of the application that created the + /// client-affine subscription. + /// + public OptionalValue ClientId + { + get { return _clientId!; } + set { _clientId!.Assign(value); } + } + + /// + /// For client-affine subscriptions, this value indicates whether the + /// subscription is durable or not. + /// + public OptionalValue IsDurable + { + get { return _isDurable!; } + set { _isDurable!.Assign(value); } + } + + /// + /// For client-affine subscriptions, this value indicates whether the + /// subscription is shared or not. + /// + public OptionalValue IsShared + { + get { return _isShared!; } + set { _isShared!.Assign(value); } + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs new file mode 100644 index 0000000000..4049548696 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs @@ -0,0 +1,118 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents the correlation filter expression. +/// +public class ServiceBusCorrelationFilter +{ + private readonly OptionalValue> _applicationProperties = new(); + private readonly OptionalValue _correlationId = new(); + private readonly OptionalValue _messageId = new(); + private readonly OptionalValue _sendTo = new(); + private readonly OptionalValue _replyTo = new(); + private readonly OptionalValue _subject = new(); + private readonly OptionalValue _sessionId = new(); + private readonly OptionalValue _replyToSessionId = new(); + private readonly OptionalValue _contentType = new(); + private readonly OptionalValue _requiresPreprocessing = new(); + + /// + /// Represents the correlation filter expression. + /// + public ServiceBusCorrelationFilter() + { + } + + /// + /// Dictionary object for custom filters. + /// + public OptionalValue> ApplicationProperties + { + get { return _applicationProperties; } + set { _applicationProperties.Assign(value); } + } + + /// + /// Identifier of the correlation. + /// + public OptionalValue CorrelationId + { + get { return _correlationId; } + set { _correlationId.Assign(value); } + } + + /// + /// Identifier of the message. + /// + public OptionalValue MessageId + { + get { return _messageId; } + set { _messageId.Assign(value); } + } + + /// + /// Address to send to. + /// + public OptionalValue SendTo + { + get { return _sendTo; } + set { _sendTo.Assign(value); } + } + + /// + /// Address of the queue to reply to. + /// + public OptionalValue ReplyTo + { + get { return _replyTo; } + set { _replyTo.Assign(value); } + } + + /// + /// Application specific label. + /// + public OptionalValue Subject + { + get { return _subject; } + set { _subject.Assign(value); } + } + + /// + /// Session identifier. + /// + public OptionalValue SessionId + { + get { return _sessionId; } + set { _sessionId.Assign(value); } + } + + /// + /// Session identifier to reply to. + /// + public OptionalValue ReplyToSessionId + { + get { return _replyToSessionId; } + set { _replyToSessionId.Assign(value); } + } + + /// + /// Content type of the message. + /// + public OptionalValue ContentType + { + get { return _contentType; } + set { _contentType.Assign(value); } + } + + /// + /// Value that indicates whether the rule action requires preprocessing. + /// + public OptionalValue RequiresPreprocessing + { + get { return _requiresPreprocessing; } + set { _requiresPreprocessing.Assign(value); } + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs new file mode 100644 index 0000000000..87befa51f9 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents the filter actions which are allowed for the transformation of a +/// message that have been matched by a filter expression. +/// +public class ServiceBusFilterAction +{ + private readonly OptionalValue _sqlExpression = new(); + private readonly OptionalValue _compatibilityLevel = new(); + private readonly OptionalValue _requiresPreprocessing = new(); + + /// + /// Creates a new ServiceBusFilterAction. + /// + public ServiceBusFilterAction() + { + } + + /// + /// SQL expression. e.g. MyProperty='ABC'. + /// + public OptionalValue SqlExpression + { + get { return _sqlExpression; } + set { _sqlExpression.Assign(value); } + } + + /// + /// This property is reserved for future use. An integer value showing the + /// compatibility level, currently hard-coded to 20. + /// + public OptionalValue CompatibilityLevel + { + get { return _compatibilityLevel; } + set { _compatibilityLevel.Assign(value); } + } + + /// + /// Value that indicates whether the rule action requires preprocessing. + /// + public OptionalValue RequiresPreprocessing + { + get { return _requiresPreprocessing; } + set { _requiresPreprocessing.Assign(value); } + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs new file mode 100644 index 0000000000..b040ec7f59 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Rule filter types. +/// +public enum ServiceBusFilterType +{ + /// + /// SqlFilter. + /// + SqlFilter, + + /// + /// CorrelationFilter. + /// + CorrelationFilter, +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs new file mode 100644 index 0000000000..bdcac195ff --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs @@ -0,0 +1,55 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Entity status. +/// +public enum ServiceBusMessagingEntityStatus +{ + /// + /// Unknown. + /// + Unknown, + + /// + /// Active. + /// + Active, + + /// + /// Disabled. + /// + Disabled, + + /// + /// Restoring. + /// + Restoring, + + /// + /// SendDisabled. + /// + SendDisabled, + + /// + /// ReceiveDisabled. + /// + ReceiveDisabled, + + /// + /// Creating. + /// + Creating, + + /// + /// Deleting. + /// + Deleting, + + /// + /// Renaming. + /// + Renaming, +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs new file mode 100644 index 0000000000..f733e0f071 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs @@ -0,0 +1,369 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using System.Xml; + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents a Service Bus Queue. +/// +public class ServiceBusQueue +{ + private readonly OptionalValue _name = new(); + private readonly OptionalValue _autoDeleteOnIdle = new(); + private readonly OptionalValue _deadLetteringOnMessageExpiration = new(); + private readonly OptionalValue _defaultMessageTimeToLive = new(); + private readonly OptionalValue _duplicateDetectionHistoryTimeWindow = new(); + private readonly OptionalValue _enableBatchedOperations = new(); + private readonly OptionalValue _enableExpress = new(); + private readonly OptionalValue _enablePartitioning = new(); + private readonly OptionalValue _forwardDeadLetteredMessagesTo = new(); + private readonly OptionalValue _forwardTo = new(); + private readonly OptionalValue _lockDuration = new(); + private readonly OptionalValue _maxDeliveryCount = new(); + private readonly OptionalValue _maxMessageSizeInKilobytes = new(); + private readonly OptionalValue _maxSizeInMegabytes = new(); + private readonly OptionalValue _requiresDuplicateDetection = new(); + private readonly OptionalValue _requiresSession = new(); + private readonly OptionalValue _status = new(); + + /// + /// Initializes a new instance of the class. + /// + public ServiceBusQueue(string id) + { + Id = id; + } + + /// + /// The queue id. + /// + public string Id { get; } + + /// + /// The queue name. + /// + public OptionalValue Name + { + get { return _name; } + set { _name.Assign(value); } + } + + /// + /// ISO 8061 timeSpan idle interval after which the queue is automatically + /// deleted. The minimum duration is 5 minutes. + /// + public OptionalValue AutoDeleteOnIdle + { + get { return _autoDeleteOnIdle; } + set { _autoDeleteOnIdle.Assign(value); } + } + + /// + /// A value that indicates whether this queue has dead letter support when + /// a message expires. + /// + public OptionalValue DeadLetteringOnMessageExpiration + { + get { return _deadLetteringOnMessageExpiration; } + set { _deadLetteringOnMessageExpiration.Assign(value); } + } + + /// + /// ISO 8601 default message timespan to live value. This is the duration + /// after which the message expires, starting from when the message is + /// sent to Service Bus. This is the default value used when TimeToLive is + /// not set on a message itself. + /// + public OptionalValue DefaultMessageTimeToLive + { + get { return _defaultMessageTimeToLive; } + set { _defaultMessageTimeToLive.Assign(value); } + } + + /// + /// ISO 8601 timeSpan structure that defines the duration of the duplicate + /// detection history. The default value is 10 minutes. + /// + public OptionalValue DuplicateDetectionHistoryTimeWindow + { + get { return _duplicateDetectionHistoryTimeWindow; } + set { _duplicateDetectionHistoryTimeWindow.Assign(value); } + } + + /// + /// Value that indicates whether server-side batched operations are enabled. + /// + public OptionalValue EnableBatchedOperations + { + get { return _enableBatchedOperations; } + set { _enableBatchedOperations.Assign(value); } + } + + /// + /// A value that indicates whether Express Entities are enabled. An express + /// queue holds a message in memory temporarily before writing it to + /// persistent storage. + /// + public OptionalValue EnableExpress + { + get { return _enableExpress; } + set { _enableExpress.Assign(value); } + } + + /// + /// A value that indicates whether the queue is to be partitioned across + /// multiple message brokers. + /// + public OptionalValue EnablePartitioning + { + get { return _enablePartitioning; } + set { _enablePartitioning.Assign(value); } + } + + /// + /// Queue/Topic name to forward the Dead Letter message. + /// + public OptionalValue ForwardDeadLetteredMessagesTo + { + get { return _forwardDeadLetteredMessagesTo; } + set { _forwardDeadLetteredMessagesTo.Assign(value); } + } + + /// + /// Queue/Topic name to forward the messages. + /// + public OptionalValue ForwardTo + { + get { return _forwardTo; } + set { _forwardTo.Assign(value); } + } + + /// + /// ISO 8601 timespan duration of a peek-lock; that is, the amount of time + /// that the message is locked for other receivers. The maximum value for + /// LockDuration is 5 minutes; the default value is 1 minute. + /// + public OptionalValue LockDuration + { + get { return _lockDuration; } + set { _lockDuration.Assign(value); } + } + + /// + /// The maximum delivery count. A message is automatically deadlettered + /// after this number of deliveries. default value is 10. + /// + public OptionalValue MaxDeliveryCount + { + get { return _maxDeliveryCount; } + set { _maxDeliveryCount.Assign(value); } + } + + /// + /// Maximum size (in KB) of the message payload that can be accepted by the + /// queue. This property is only used in Premium today and default is 1024. + /// + public OptionalValue MaxMessageSizeInKilobytes + { + get { return _maxMessageSizeInKilobytes; } + set { _maxMessageSizeInKilobytes.Assign(value); } + } + + /// + /// The maximum size of the queue in megabytes, which is the size of memory + /// allocated for the queue. Default is 1024. + /// + public OptionalValue MaxSizeInMegabytes + { + get { return _maxSizeInMegabytes; } + set { _maxSizeInMegabytes.Assign(value); } + } + + /// + /// A value indicating if this queue requires duplicate detection. + /// + public OptionalValue RequiresDuplicateDetection + { + get { return _requiresDuplicateDetection; } + set { _requiresDuplicateDetection.Assign(value); } + } + + /// + /// A value that indicates whether the queue supports the concept of + /// sessions. + /// + public OptionalValue RequiresSession + { + get { return _requiresSession; } + set { _requiresSession.Assign(value); } + } + + /// + /// Enumerates the possible values for the status of a messaging entity. + /// + public OptionalValue Status + { + get { return _status; } + set { _status.Assign(value); } + } + + /// + /// Converts the current instance to a provisioning entity. + /// + /// A instance. + public global::Azure.Provisioning.ServiceBus.ServiceBusQueue ToProvisioningEntity() + { + var queue = new global::Azure.Provisioning.ServiceBus.ServiceBusQueue(Id); + + if (Name.IsSet && Name.Value != null) + { + queue.Name = Name.Value; + } + + if (AutoDeleteOnIdle.IsSet) + { + queue.AutoDeleteOnIdle = AutoDeleteOnIdle.Value; + } + if (DeadLetteringOnMessageExpiration.IsSet) + { + queue.DeadLetteringOnMessageExpiration = DeadLetteringOnMessageExpiration.Value; + } + if (DefaultMessageTimeToLive.IsSet) + { + queue.DefaultMessageTimeToLive = DefaultMessageTimeToLive.Value; + } + if (DuplicateDetectionHistoryTimeWindow.IsSet) + { + queue.DuplicateDetectionHistoryTimeWindow = DuplicateDetectionHistoryTimeWindow.Value; + } + if (EnableBatchedOperations.IsSet) + { + queue.EnableBatchedOperations = EnableBatchedOperations.Value; + } + if (EnableExpress.IsSet) + { + queue.EnableExpress = EnableExpress.Value; + } + if (EnablePartitioning.IsSet) + { + queue.EnablePartitioning = EnablePartitioning.Value; + } + if (ForwardDeadLetteredMessagesTo.IsSet && ForwardDeadLetteredMessagesTo.Value != null) + { + queue.ForwardDeadLetteredMessagesTo = ForwardDeadLetteredMessagesTo.Value; + } + if (ForwardTo.IsSet && ForwardTo.Value != null) + { + queue.ForwardTo = ForwardTo.Value; + } + if (LockDuration.IsSet) + { + queue.LockDuration = LockDuration.Value; + } + if (MaxDeliveryCount.IsSet) + { + queue.MaxDeliveryCount = MaxDeliveryCount.Value; + } + if (MaxMessageSizeInKilobytes.IsSet) + { + queue.MaxSizeInMegabytes = MaxSizeInMegabytes.Value; + } + if (RequiresDuplicateDetection.IsSet) + { + queue.RequiresDuplicateDetection = RequiresDuplicateDetection.Value; + } + if (RequiresSession.IsSet) + { + queue.RequiresSession = RequiresSession.Value; + } + if (Status.IsSet) + { + queue.Status = Enum.Parse(Status.Value.ToString()); + } + return queue; + } + + /// + /// Converts the current instance to a JSON object. + /// + /// The Utf8JsonWriter to write the JSON object to. + public void WriteJsonObjectProperties(Utf8JsonWriter writer) + { + var queue = this; + + if (queue.Name.IsSet) + { + writer.WriteString(nameof(Name), queue.Name.Value); + } + writer.WriteStartObject("Properties"); + + if (queue.AutoDeleteOnIdle.IsSet) + { + writer.WriteString(nameof(AutoDeleteOnIdle), XmlConvert.ToString(queue.AutoDeleteOnIdle.Value)); + } + if (queue.DeadLetteringOnMessageExpiration.IsSet) + { + writer.WriteBoolean(nameof(DeadLetteringOnMessageExpiration), queue.DeadLetteringOnMessageExpiration.Value); + } + if (queue.DefaultMessageTimeToLive.IsSet) + { + writer.WriteString(nameof(DefaultMessageTimeToLive), XmlConvert.ToString(queue.DefaultMessageTimeToLive.Value)); + } + if (queue.DuplicateDetectionHistoryTimeWindow.IsSet) + { + writer.WriteString(nameof(DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(queue.DuplicateDetectionHistoryTimeWindow.Value)); + } + if (queue.EnableBatchedOperations.IsSet) + { + writer.WriteBoolean(nameof(EnableBatchedOperations), queue.EnableBatchedOperations.Value); + } + if (queue.EnableExpress.IsSet) + { + writer.WriteBoolean(nameof(EnableExpress), queue.EnableExpress.Value); + } + if (queue.EnablePartitioning.IsSet) + { + writer.WriteBoolean(nameof(EnablePartitioning), queue.EnablePartitioning.Value); + } + if (queue.ForwardDeadLetteredMessagesTo.IsSet) + { + writer.WriteString(nameof(ForwardDeadLetteredMessagesTo), queue.ForwardDeadLetteredMessagesTo.Value); + } + if (queue.ForwardTo.IsSet) + { + writer.WriteString(nameof(ForwardTo), queue.ForwardTo.Value); + } + if (queue.LockDuration.IsSet) + { + writer.WriteString(nameof(LockDuration), XmlConvert.ToString(queue.LockDuration.Value)); + } + if (queue.MaxDeliveryCount.IsSet) + { + writer.WriteNumber(nameof(MaxDeliveryCount), queue.MaxDeliveryCount.Value); + } + if (queue.MaxMessageSizeInKilobytes.IsSet) + { + writer.WriteNumber(nameof(MaxMessageSizeInKilobytes), queue.MaxMessageSizeInKilobytes.Value); + } + if (queue.MaxSizeInMegabytes.IsSet) + { + writer.WriteNumber(nameof(MaxSizeInMegabytes), queue.MaxSizeInMegabytes.Value); + } + if (queue.RequiresDuplicateDetection.IsSet) + { + writer.WriteBoolean(nameof(RequiresDuplicateDetection), queue.RequiresDuplicateDetection.Value); + } + if (queue.RequiresSession.IsSet) + { + writer.WriteBoolean(nameof(RequiresSession), queue.RequiresSession.Value); + } + if (queue.Status.IsSet) + { + writer.WriteString(nameof(Status), queue.Status.Value.ToString()); + } + writer.WriteEndObject(); + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs new file mode 100644 index 0000000000..41c9976d79 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs @@ -0,0 +1,302 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents a Service Bus Rule. +/// +public class ServiceBusRule +{ + private readonly OptionalValue _name = new(); + private readonly OptionalValue _action = new(); + private readonly OptionalValue _correlationFilter = new(); + private readonly OptionalValue _filterType = new(); + private readonly OptionalValue _sqlFilter = new(); + + /// + /// Initializes a new instance of the class. + /// + public ServiceBusRule(string id) + { + Id = id; + } + + /// + /// The rule id. + /// + public string Id { get; } + + /// + /// The rule name. + /// + public OptionalValue Name + { + get { return _name; } + set { _name.Assign(value); } + } + + /// + /// Represents the filter actions which are allowed for the transformation + /// of a message that have been matched by a filter expression. + /// + public OptionalValue Action + { + get { return _action; } + set { _action.Assign(value); } + } + + /// + /// Properties of correlationFilter. + /// + public OptionalValue CorrelationFilter + { + get { return _correlationFilter; } + set { _correlationFilter.Assign(value); } + } + + /// + /// Filter type that is evaluated against a BrokeredMessage. + /// + public OptionalValue FilterType + { + get { return _filterType; } + set { _filterType.Assign(value); } + } + + /// + /// Properties of sqlFilter. + /// + public OptionalValue SqlFilter + { + get { return _sqlFilter; } + set { _sqlFilter.Assign(value); } + } + + /// + /// Converts the current instance to a provisioning entity. + /// + /// A instance. + public global::Azure.Provisioning.ServiceBus.ServiceBusRule ToProvisioningEntity() + { + var rule = new global::Azure.Provisioning.ServiceBus.ServiceBusRule(Id); + + if (Name.IsSet && Name.Value != null) + { + rule.Name = Name.Value; + } + + if (Action.IsSet && Action.Value != null) + { + rule.Action = new(); + + if (Action.Value.SqlExpression.IsSet && Action.Value.SqlExpression.Value != null) + { + rule.Action.SqlExpression = Action.Value.SqlExpression.Value; + } + if (Action.Value.CompatibilityLevel.IsSet) + { + rule.Action.CompatibilityLevel = Action.Value.CompatibilityLevel.Value; + } + if (Action.Value.RequiresPreprocessing.IsSet) + { + rule.Action.RequiresPreprocessing = Action.Value.RequiresPreprocessing.Value; + } + } + + if (CorrelationFilter.IsSet && CorrelationFilter.Value != null) + { + rule.CorrelationFilter = new(); + + if (CorrelationFilter.Value.ApplicationProperties.IsSet && CorrelationFilter.Value.ApplicationProperties.Value != null) + { + foreach (var property in CorrelationFilter.Value.ApplicationProperties.Value) + { + rule.CorrelationFilter.ApplicationProperties[property.Key] = property.Value; + } + } + if (CorrelationFilter.Value.CorrelationId.IsSet && CorrelationFilter.Value.CorrelationId.Value != null) + { + rule.CorrelationFilter.CorrelationId = CorrelationFilter.Value.CorrelationId.Value; + } + if (CorrelationFilter.Value.MessageId.IsSet && CorrelationFilter.Value.MessageId.Value != null) + { + rule.CorrelationFilter.MessageId = CorrelationFilter.Value.MessageId.Value; + } + if (CorrelationFilter.Value.SendTo.IsSet && CorrelationFilter.Value.SendTo.Value != null) + { + rule.CorrelationFilter.SendTo = CorrelationFilter.Value.SendTo.Value; + } + if (CorrelationFilter.Value.ReplyTo.IsSet && CorrelationFilter.Value.ReplyTo.Value != null) + { + rule.CorrelationFilter.ReplyTo = CorrelationFilter.Value.ReplyTo.Value; + } + if (CorrelationFilter.Value.Subject.IsSet && CorrelationFilter.Value.Subject.Value != null) + { + rule.CorrelationFilter.Subject = CorrelationFilter.Value.Subject.Value; + } + if (CorrelationFilter.Value.SessionId.IsSet && CorrelationFilter.Value.SessionId.Value != null) + { + rule.CorrelationFilter.SessionId = CorrelationFilter.Value.SessionId.Value; + } + if (CorrelationFilter.Value.ReplyToSessionId.IsSet && CorrelationFilter.Value.ReplyToSessionId.Value != null) + { + rule.CorrelationFilter.ReplyToSessionId = CorrelationFilter.Value.ReplyToSessionId.Value; + } + if (CorrelationFilter.Value.ContentType.IsSet && CorrelationFilter.Value.ContentType.Value != null) + { + rule.CorrelationFilter.ContentType = CorrelationFilter.Value.ContentType.Value; + } + if (CorrelationFilter.Value.RequiresPreprocessing.IsSet) + { + rule.CorrelationFilter.RequiresPreprocessing = CorrelationFilter.Value.RequiresPreprocessing.Value; + } + } + + if (FilterType.IsSet) + { + rule.FilterType = FilterType.Value switch + { + ServiceBusFilterType.SqlFilter => global::Azure.Provisioning.ServiceBus.ServiceBusFilterType.SqlFilter, + ServiceBusFilterType.CorrelationFilter => global::Azure.Provisioning.ServiceBus.ServiceBusFilterType.CorrelationFilter, + _ => throw new NotImplementedException() + }; + } + + if (SqlFilter.IsSet && SqlFilter.Value != null) + { + rule.SqlFilter = new(); + + if (SqlFilter.Value.SqlExpression.IsSet && SqlFilter.Value.SqlExpression.Value != null) + { + rule.SqlFilter.SqlExpression = SqlFilter.Value.SqlExpression.Value; + } + if (SqlFilter.Value.CompatibilityLevel.IsSet) + { + rule.SqlFilter.CompatibilityLevel = SqlFilter.Value.CompatibilityLevel.Value; + } + if (SqlFilter.Value.RequiresPreprocessing.IsSet) + { + rule.SqlFilter.RequiresPreprocessing = SqlFilter.Value.RequiresPreprocessing.Value; + } + } + + return rule; + } + + /// + /// Converts the current instance to a JSON object. + /// + /// The Utf8JsonWriter to write the JSON object to. + public void WriteJsonObjectProperties(Utf8JsonWriter writer) + { + var rule = this; + + if (rule.Name.IsSet) + { + writer.WriteString(nameof(ServiceBusQueue.Name), rule.Name.Value); + } + + writer.WriteStartObject("Properties"); + + if (rule.Action.IsSet && rule.Action.Value != null) + { + writer.WriteStartObject(nameof(Action)); + + if (rule.Action.Value.SqlExpression.IsSet) + { + writer.WriteString(nameof(ServiceBusFilterAction.SqlExpression), rule.Action.Value.SqlExpression.Value); + } + if (rule.Action.Value.CompatibilityLevel.IsSet) + { + writer.WriteNumber(nameof(ServiceBusFilterAction.CompatibilityLevel), rule.Action.Value.CompatibilityLevel.Value); + } + if (rule.Action.Value.RequiresPreprocessing.IsSet) + { + writer.WriteBoolean(nameof(ServiceBusFilterAction.RequiresPreprocessing), rule.Action.Value.RequiresPreprocessing.Value); + } + writer.WriteEndObject(); + } + + if (rule.CorrelationFilter.IsSet && rule.CorrelationFilter.Value != null) + { + writer.WriteStartObject(nameof(CorrelationFilter)); + + if (rule.CorrelationFilter.Value.ApplicationProperties.IsSet && rule.CorrelationFilter.Value.ApplicationProperties != null) + { + JsonSerializer.Serialize(writer, rule.CorrelationFilter.Value.ApplicationProperties.Value); + } + if (rule.CorrelationFilter.Value.CorrelationId.IsSet) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.CorrelationId), rule.CorrelationFilter.Value.CorrelationId.Value); + } + if (rule.CorrelationFilter.Value.MessageId.IsSet) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.MessageId), rule.CorrelationFilter.Value.MessageId.Value); + } + if (rule.CorrelationFilter.Value.SendTo.IsSet) + { + writer.WriteString("To", rule.CorrelationFilter.Value.SendTo.Value); + } + if (rule.CorrelationFilter.Value.ReplyTo.IsSet) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyTo), rule.CorrelationFilter.Value.ReplyTo.Value); + } + if (rule.CorrelationFilter.Value.Subject.IsSet) + { + writer.WriteString("Label", rule.CorrelationFilter.Value.Subject.Value); + } + if (rule.CorrelationFilter.Value.SessionId.IsSet) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.SessionId), rule.CorrelationFilter.Value.SessionId.Value); + } + if (rule.CorrelationFilter.Value.ReplyToSessionId.IsSet) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyToSessionId), rule.CorrelationFilter.Value.ReplyToSessionId.Value); + } + if (rule.CorrelationFilter.Value.ContentType.IsSet) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ContentType), rule.CorrelationFilter.Value.ContentType.Value); + } + if (rule.CorrelationFilter.Value.RequiresPreprocessing.IsSet) + { + writer.WriteBoolean(nameof(ServiceBusCorrelationFilter.RequiresPreprocessing), rule.CorrelationFilter.Value.RequiresPreprocessing.Value); + } + + writer.WriteEndObject(); + } + + if (rule.FilterType.IsSet) + { + writer.WriteString(nameof(FilterType), rule.FilterType.Value switch + { + ServiceBusFilterType.SqlFilter => "Sql", + ServiceBusFilterType.CorrelationFilter => "Correlation", + _ => throw new NotImplementedException() + }); + } + + if (rule.SqlFilter.IsSet && rule.SqlFilter.Value != null) + { + writer.WriteStartObject(nameof(SqlFilter)); + + if (rule.SqlFilter.Value.SqlExpression.IsSet) + { + writer.WriteString(nameof(ServiceBusSqlFilter.SqlExpression), rule.SqlFilter.Value.SqlExpression.Value); + } + if (rule.SqlFilter.Value.CompatibilityLevel.IsSet) + { + writer.WriteNumber(nameof(ServiceBusSqlFilter.CompatibilityLevel), rule.SqlFilter.Value.CompatibilityLevel.Value); + } + if (rule.SqlFilter.Value.RequiresPreprocessing.IsSet) + { + writer.WriteBoolean(nameof(ServiceBusSqlFilter.RequiresPreprocessing), rule.SqlFilter.Value.RequiresPreprocessing.Value); + } + writer.WriteEndObject(); + } + + writer.WriteEndObject(); + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs new file mode 100644 index 0000000000..a27f500911 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs @@ -0,0 +1,50 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents a filter which is a composition of an expression and an action +/// that is executed in the pub/sub pipeline. +/// +public class ServiceBusSqlFilter +{ + private readonly OptionalValue _sqlExpression = new(); + private readonly OptionalValue _compatibilityLevel = new(); + private readonly OptionalValue _requiresPreprocessing = new(); + + /// + /// Creates a new ServiceBusSqlFilter. + /// + public ServiceBusSqlFilter() + { + } + + /// + /// The SQL expression. e.g. MyProperty='ABC'. + /// + public OptionalValue SqlExpression + { + get { return _sqlExpression; } + set { _sqlExpression.Assign(value); } + } + + /// + /// This property is reserved for future use. An integer value showing the + /// compatibility level, currently hard-coded to 20. + /// + public OptionalValue CompatibilityLevel + { + get { return _compatibilityLevel; } + set { _compatibilityLevel.Assign(value); } + } + + /// + /// Value that indicates whether the rule action requires preprocessing. + /// + public OptionalValue RequiresPreprocessing + { + get { return _requiresPreprocessing; } + set { _requiresPreprocessing.Assign(value); } + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs new file mode 100644 index 0000000000..e6fc5a324b --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs @@ -0,0 +1,359 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using System.Xml; + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents a Service Bus Subscription. +/// +public class ServiceBusSubscription +{ + private readonly OptionalValue _name = new(); + private readonly OptionalValue _autoDeleteOnIdle = new(); + private readonly OptionalValue _deadLetteringOnFilterEvaluationExceptions = new(); + private readonly OptionalValue _deadLetteringOnMessageExpiration = new(); + private readonly OptionalValue _defaultMessageTimeToLive = new(); + private readonly OptionalValue _duplicateDetectionHistoryTimeWindow = new(); + private readonly OptionalValue _enableBatchedOperations = new(); + private readonly OptionalValue _forwardDeadLetteredMessagesTo = new(); + private readonly OptionalValue _forwardTo = new(); + private readonly OptionalValue _isClientAffine = new(); + private readonly OptionalValue _lockDuration = new(); + private readonly OptionalValue _maxDeliveryCount = new(); + private readonly OptionalValue _maxMessageSizeInKilobytes = new(); + private readonly OptionalValue _requiresSession = new(); + private readonly OptionalValue _status = new(); + private readonly OptionalValue _clientAffineProperties = new(); + + /// + /// Initializes a new instance of the class. + /// + public ServiceBusSubscription(string id) + { + Id = id; + } + + /// + /// The subscription id. + /// + public string Id { get; } + + /// + /// The subscription name. + /// + public OptionalValue Name + { + get { return _name; } + set { _name.Assign(value); } + } + + /// + /// ISO 8061 timeSpan idle interval after which the queue is automatically + /// deleted. The minimum duration is 5 minutes. + /// + public OptionalValue AutoDeleteOnIdle + { + get { return _autoDeleteOnIdle; } + set { _autoDeleteOnIdle.Assign(value); } + } + + /// + /// Properties specific to client affine subscriptions. + /// + public OptionalValue ClientAffineProperties + { + get { return _clientAffineProperties; } + set { _clientAffineProperties.Assign(value); } + } + + /// + /// Value that indicates whether a subscription has dead letter support on + /// filter evaluation exceptions. + /// + public OptionalValue DeadLetteringOnFilterEvaluationExceptions + { + get { return _deadLetteringOnFilterEvaluationExceptions!; } + set { _deadLetteringOnFilterEvaluationExceptions.Assign(value); } + } + + /// + /// A value that indicates whether this queue has dead letter support when + /// a message expires. + /// + public OptionalValue DeadLetteringOnMessageExpiration + { + get { return _deadLetteringOnMessageExpiration; } + set { _deadLetteringOnMessageExpiration.Assign(value); } + } + + /// + /// ISO 8601 default message timespan to live value. This is the duration + /// after which the message expires, starting from when the message is + /// sent to Service Bus. This is the default value used when TimeToLive is + /// not set on a message itself. + /// + public OptionalValue DefaultMessageTimeToLive + { + get { return _defaultMessageTimeToLive; } + set { _defaultMessageTimeToLive.Assign(value); } + } + + /// + /// ISO 8601 timeSpan structure that defines the duration of the duplicate + /// detection history. The default value is 10 minutes. + /// + public OptionalValue DuplicateDetectionHistoryTimeWindow + { + get { return _duplicateDetectionHistoryTimeWindow; } + set { _duplicateDetectionHistoryTimeWindow.Assign(value); } + } + + /// + /// Value that indicates whether server-side batched operations are enabled. + /// + public OptionalValue EnableBatchedOperations + { + get { return _enableBatchedOperations; } + set { _enableBatchedOperations.Assign(value); } + } + + /// + /// Queue/Topic name to forward the Dead Letter message. + /// + public OptionalValue ForwardDeadLetteredMessagesTo + { + get { return _forwardDeadLetteredMessagesTo; } + set { _forwardDeadLetteredMessagesTo.Assign(value); } + } + + /// + /// Queue/Topic name to forward the messages. + /// + public OptionalValue ForwardTo + { + get { return _forwardTo; } + set { _forwardTo.Assign(value); } + } + + /// + /// Value that indicates whether the subscription has an affinity to the + /// client id. + /// + public OptionalValue IsClientAffine + { + get { return _isClientAffine; } + set { _isClientAffine.Assign(value); } + } + + /// + /// ISO 8601 timespan duration of a peek-lock; that is, the amount of time + /// that the message is locked for other receivers. The maximum value for + /// LockDuration is 5 minutes; the default value is 1 minute. + /// + public OptionalValue LockDuration + { + get { return _lockDuration; } + set { _lockDuration.Assign(value); } + } + + /// + /// The maximum delivery count. A message is automatically deadlettered + /// after this number of deliveries. default value is 10. + /// + public OptionalValue MaxDeliveryCount + { + get { return _maxDeliveryCount; } + set { _maxDeliveryCount.Assign(value); } + } + + /// + /// Maximum size (in KB) of the message payload that can be accepted by the + /// queue. This property is only used in Premium today and default is 1024. + /// + public OptionalValue MaxMessageSizeInKilobytes + { + get { return _maxMessageSizeInKilobytes; } + set { _maxMessageSizeInKilobytes.Assign(value); } + } + + /// + /// A value that indicates whether the queue supports the concept of + /// sessions. + /// + public OptionalValue RequiresSession + { + get { return _requiresSession; } + set { _requiresSession.Assign(value); } + } + + /// + /// Enumerates the possible values for the status of a messaging entity. + /// + public OptionalValue Status + { + get { return _status; } + set { _status.Assign(value); } + } + + /// + /// Converts the current instance to a provisioning entity. + /// + /// A instance. + public global::Azure.Provisioning.ServiceBus.ServiceBusSubscription ToProvisioningEntity() + { + var subscription = new global::Azure.Provisioning.ServiceBus.ServiceBusSubscription(Id); + + if (Name.IsSet && Name.Value != null) + { + subscription.Name = Name.Value; + } + + if (AutoDeleteOnIdle.IsSet) + { + subscription.AutoDeleteOnIdle = AutoDeleteOnIdle.Value; + } + if (DeadLetteringOnFilterEvaluationExceptions.IsSet) + { + subscription.DeadLetteringOnFilterEvaluationExceptions = DeadLetteringOnFilterEvaluationExceptions.Value; + } + if (DeadLetteringOnMessageExpiration.IsSet) + { + subscription.DeadLetteringOnMessageExpiration = DeadLetteringOnMessageExpiration.Value; + } + if (DefaultMessageTimeToLive.IsSet) + { + subscription.DefaultMessageTimeToLive = DefaultMessageTimeToLive.Value; + } + if (DuplicateDetectionHistoryTimeWindow.IsSet) + { + subscription.DuplicateDetectionHistoryTimeWindow = DuplicateDetectionHistoryTimeWindow.Value; + } + if (EnableBatchedOperations.IsSet) + { + subscription.EnableBatchedOperations = EnableBatchedOperations.Value; + } + if (ForwardDeadLetteredMessagesTo.IsSet && ForwardDeadLetteredMessagesTo.Value != null) + { + subscription.ForwardDeadLetteredMessagesTo = ForwardDeadLetteredMessagesTo.Value; + } + if (ForwardTo.IsSet && ForwardTo.Value != null) + { + subscription.ForwardTo = ForwardTo.Value; + } + if (IsClientAffine.IsSet) + { + subscription.IsClientAffine = IsClientAffine.Value; + } + if (LockDuration.IsSet) + { + subscription.LockDuration = LockDuration.Value; + } + if (MaxDeliveryCount.IsSet) + { + subscription.MaxDeliveryCount = MaxDeliveryCount.Value; + } + if (RequiresSession.IsSet) + { + subscription.RequiresSession = RequiresSession.Value; + } + if (Status.IsSet) + { + subscription.Status = Enum.Parse(Status.Value.ToString()); + } + return subscription; + } + + /// + /// Converts the current instance to a JSON object. + /// + /// The Utf8JsonWriter to write the JSON object to. + public void WriteJsonObjectProperties(Utf8JsonWriter writer) + { + var subscription = this; + + if (subscription.Name.IsSet) + { + writer.WriteString(nameof(ServiceBusQueue.Name), subscription.Name.Value); + } + + writer.WriteStartObject("Properties"); + + if (subscription.AutoDeleteOnIdle.IsSet) + { + writer.WriteString(nameof(ServiceBusSubscription.AutoDeleteOnIdle), XmlConvert.ToString(subscription.AutoDeleteOnIdle.Value)); + } + if (subscription.ClientAffineProperties.IsSet && subscription.ClientAffineProperties.Value != null) + { + writer.WriteStartObject(nameof(subscription.ClientAffineProperties)); + + if (subscription.ClientAffineProperties.Value.ClientId.IsSet) + { + writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), subscription.ClientAffineProperties.Value.ClientId.Value); + } + if (subscription.ClientAffineProperties.Value.IsDurable.IsSet) + { + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), subscription.ClientAffineProperties.Value.IsDurable.Value); + } + if (subscription.ClientAffineProperties.Value.IsShared.IsSet) + { + writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), subscription.ClientAffineProperties.Value.IsShared.Value); + } + + writer.WriteEndObject(); + } + + if (subscription.DeadLetteringOnFilterEvaluationExceptions.IsSet) + { + writer.WriteBoolean(nameof(DeadLetteringOnFilterEvaluationExceptions), subscription.DeadLetteringOnFilterEvaluationExceptions.Value); + } + if (subscription.DeadLetteringOnMessageExpiration.IsSet) + { + writer.WriteBoolean(nameof(DeadLetteringOnMessageExpiration), subscription.DeadLetteringOnMessageExpiration.Value); + } + if (subscription.DefaultMessageTimeToLive.IsSet) + { + writer.WriteString(nameof(DefaultMessageTimeToLive), XmlConvert.ToString(subscription.DefaultMessageTimeToLive.Value)); + } + if (subscription.DuplicateDetectionHistoryTimeWindow.IsSet) + { + writer.WriteString(nameof(DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(subscription.DuplicateDetectionHistoryTimeWindow.Value)); + } + if (subscription.EnableBatchedOperations.IsSet) + { + writer.WriteBoolean(nameof(EnableBatchedOperations), subscription.EnableBatchedOperations.Value); + } + if (subscription.ForwardDeadLetteredMessagesTo.IsSet) + { + writer.WriteString(nameof(ForwardDeadLetteredMessagesTo), subscription.ForwardDeadLetteredMessagesTo.Value); + } + if (subscription.ForwardTo.IsSet) + { + writer.WriteString(nameof(ForwardTo), subscription.ForwardTo.Value); + } + if (subscription.IsClientAffine.IsSet) + { + writer.WriteBoolean(nameof(IsClientAffine), subscription.IsClientAffine.Value); + } + if (subscription.LockDuration.IsSet) + { + writer.WriteString(nameof(LockDuration), XmlConvert.ToString(subscription.LockDuration.Value)); + } + if (subscription.MaxDeliveryCount.IsSet) + { + writer.WriteNumber(nameof(MaxDeliveryCount), subscription.MaxDeliveryCount.Value); + } + if (subscription.RequiresSession.IsSet) + { + writer.WriteBoolean(nameof(RequiresSession), subscription.RequiresSession.Value); + } + if (subscription.Status.IsSet) + { + writer.WriteString(nameof(Status), subscription.Status.Value.ToString()); + } + + writer.WriteEndObject(); + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs new file mode 100644 index 0000000000..eca3017170 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs @@ -0,0 +1,322 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json; +using System.Xml; + +namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; + +/// +/// Represents a Service Bus Topic. +/// +public class ServiceBusTopic +{ + private readonly OptionalValue _name = new(); + private readonly OptionalValue _autoDeleteOnIdle = new(); + private readonly OptionalValue _deadLetteringOnMessageExpiration = new(); + private readonly OptionalValue _defaultMessageTimeToLive = new(); + private readonly OptionalValue _duplicateDetectionHistoryTimeWindow = new(); + private readonly OptionalValue _enableBatchedOperations = new(); + private readonly OptionalValue _enableExpress = new(); + private readonly OptionalValue _enablePartitioning = new(); + private readonly OptionalValue _forwardDeadLetteredMessagesTo = new(); + private readonly OptionalValue _forwardTo = new(); + private readonly OptionalValue _lockDuration = new(); + private readonly OptionalValue _maxDeliveryCount = new(); + private readonly OptionalValue _maxMessageSizeInKilobytes = new(); + private readonly OptionalValue _maxSizeInMegabytes = new(); + private readonly OptionalValue _requiresDuplicateDetection = new(); + private readonly OptionalValue _requiresSession = new(); + private readonly OptionalValue _status = new(); + + /// + /// Initializes a new instance of the class. + /// + public ServiceBusTopic(string id) + { + Id = id; + } + + /// + /// The topic id. + /// + public string Id { get; } + + /// + /// The topic name. + /// + public OptionalValue Name + { + get { return _name; } + set { _name.Assign(value); } + } + + /// + /// ISO 8061 timeSpan idle interval after which the queue is automatically + /// deleted. The minimum duration is 5 minutes. + /// + public OptionalValue AutoDeleteOnIdle + { + get { return _autoDeleteOnIdle; } + set { _autoDeleteOnIdle.Assign(value); } + } + + /// + /// A value that indicates whether this queue has dead letter support when + /// a message expires. + /// + public OptionalValue DeadLetteringOnMessageExpiration + { + get { return _deadLetteringOnMessageExpiration; } + set { _deadLetteringOnMessageExpiration.Assign(value); } + } + + /// + /// ISO 8601 default message timespan to live value. This is the duration + /// after which the message expires, starting from when the message is + /// sent to Service Bus. This is the default value used when TimeToLive is + /// not set on a message itself. + /// + public OptionalValue DefaultMessageTimeToLive + { + get { return _defaultMessageTimeToLive; } + set { _defaultMessageTimeToLive.Assign(value); } + } + + /// + /// ISO 8601 timeSpan structure that defines the duration of the duplicate + /// detection history. The default value is 10 minutes. + /// + public OptionalValue DuplicateDetectionHistoryTimeWindow + { + get { return _duplicateDetectionHistoryTimeWindow; } + set { _duplicateDetectionHistoryTimeWindow.Assign(value); } + } + + /// + /// Value that indicates whether server-side batched operations are enabled. + /// + public OptionalValue EnableBatchedOperations + { + get { return _enableBatchedOperations; } + set { _enableBatchedOperations.Assign(value); } + } + + /// + /// A value that indicates whether Express Entities are enabled. An express + /// queue holds a message in memory temporarily before writing it to + /// persistent storage. + /// + public OptionalValue EnableExpress + { + get { return _enableExpress; } + set { _enableExpress.Assign(value); } + } + + /// + /// A value that indicates whether the queue is to be partitioned across + /// multiple message brokers. + /// + public OptionalValue EnablePartitioning + { + get { return _enablePartitioning; } + set { _enablePartitioning.Assign(value); } + } + + /// + /// Queue/Topic name to forward the Dead Letter message. + /// + public OptionalValue ForwardDeadLetteredMessagesTo + { + get { return _forwardDeadLetteredMessagesTo; } + set { _forwardDeadLetteredMessagesTo.Assign(value); } + } + + /// + /// Queue/Topic name to forward the messages. + /// + public OptionalValue ForwardTo + { + get { return _forwardTo; } + set { _forwardTo.Assign(value); } + } + + /// + /// ISO 8601 timespan duration of a peek-lock; that is, the amount of time + /// that the message is locked for other receivers. The maximum value for + /// LockDuration is 5 minutes; the default value is 1 minute. + /// + public OptionalValue LockDuration + { + get { return _lockDuration; } + set { _lockDuration.Assign(value); } + } + + /// + /// The maximum delivery count. A message is automatically deadlettered + /// after this number of deliveries. default value is 10. + /// + public OptionalValue MaxDeliveryCount + { + get { return _maxDeliveryCount; } + set { _maxDeliveryCount.Assign(value); } + } + + /// + /// Maximum size (in KB) of the message payload that can be accepted by the + /// queue. This property is only used in Premium today and default is 1024. + /// + public OptionalValue MaxMessageSizeInKilobytes + { + get { return _maxMessageSizeInKilobytes; } + set { _maxMessageSizeInKilobytes.Assign(value); } + } + + /// + /// The maximum size of the queue in megabytes, which is the size of memory + /// allocated for the queue. Default is 1024. + /// + public OptionalValue MaxSizeInMegabytes + { + get { return _maxSizeInMegabytes; } + set { _maxSizeInMegabytes.Assign(value); } + } + + /// + /// A value indicating if this queue requires duplicate detection. + /// + public OptionalValue RequiresDuplicateDetection + { + get { return _requiresDuplicateDetection; } + set { _requiresDuplicateDetection.Assign(value); } + } + + /// + /// A value that indicates whether the queue supports the concept of + /// sessions. + /// + public OptionalValue RequiresSession + { + get { return _requiresSession; } + set { _requiresSession.Assign(value); } + } + + /// + /// Enumerates the possible values for the status of a messaging entity. + /// + public OptionalValue Status + { + get { return _status!; } + set { _status!.Assign(value); } + } + + /// + /// Converts the current instance to a provisioning entity. + /// + /// A instance. + public global::Azure.Provisioning.ServiceBus.ServiceBusTopic ToProvisioningEntity() + { + var topic = new global::Azure.Provisioning.ServiceBus.ServiceBusTopic(Id); + + if (Name.IsSet && Name.Value != null) + { + topic.Name = Name.Value; + } + + if (AutoDeleteOnIdle.IsSet) + { + topic.AutoDeleteOnIdle = AutoDeleteOnIdle.Value; + } + if (DefaultMessageTimeToLive.IsSet) + { + topic.DefaultMessageTimeToLive = DefaultMessageTimeToLive.Value; + } + if (DuplicateDetectionHistoryTimeWindow.IsSet) + { + topic.DuplicateDetectionHistoryTimeWindow = DuplicateDetectionHistoryTimeWindow.Value; + } + if (EnableBatchedOperations.IsSet) + { + topic.EnableBatchedOperations = EnableBatchedOperations.Value; + } + if (EnableExpress.IsSet) + { + topic.EnableExpress = EnableExpress.Value; + } + if (EnablePartitioning.IsSet) + { + topic.EnablePartitioning = EnablePartitioning.Value; + } + if (MaxMessageSizeInKilobytes.IsSet) + { + topic.MaxSizeInMegabytes = MaxSizeInMegabytes.Value; + } + if (RequiresDuplicateDetection.IsSet) + { + topic.RequiresDuplicateDetection = RequiresDuplicateDetection.Value; + } + if (Status.IsSet) + { + topic.Status = Enum.Parse(Status.Value.ToString()); + } + return topic; + } + + /// + /// Converts the current instance to a JSON object. + /// + /// The Utf8JsonWriter to write the JSON object to. + public void WriteJsonObjectProperties(Utf8JsonWriter writer) + { + var topic = this; + + if (topic.Name.IsSet) + { + writer.WriteString(nameof(Name), topic.Name.Value); + } + writer.WriteStartObject("Properties"); + + if (topic.AutoDeleteOnIdle.IsSet) + { + writer.WriteString(nameof(AutoDeleteOnIdle), XmlConvert.ToString(topic.AutoDeleteOnIdle.Value)); + } + if (topic.DefaultMessageTimeToLive.IsSet) + { + writer.WriteString(nameof(DefaultMessageTimeToLive), XmlConvert.ToString(topic.DefaultMessageTimeToLive.Value)); + } + if (topic.DuplicateDetectionHistoryTimeWindow.IsSet) + { + writer.WriteString(nameof(DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(topic.DuplicateDetectionHistoryTimeWindow.Value)); + } + if (topic.EnableBatchedOperations.IsSet) + { + writer.WriteBoolean(nameof(EnableBatchedOperations), topic.EnableBatchedOperations.Value); + } + if (topic.EnableExpress.IsSet) + { + writer.WriteBoolean(nameof(EnableExpress), topic.EnableExpress.Value); + } + if (topic.EnablePartitioning.IsSet) + { + writer.WriteBoolean(nameof(EnablePartitioning), topic.EnablePartitioning.Value); + } + if (topic.MaxMessageSizeInKilobytes.IsSet) + { + writer.WriteNumber(nameof(MaxMessageSizeInKilobytes), topic.MaxMessageSizeInKilobytes.Value); + } + if (topic.MaxSizeInMegabytes.IsSet) + { + writer.WriteNumber(nameof(MaxSizeInMegabytes), topic.MaxSizeInMegabytes.Value); + } + if (topic.RequiresDuplicateDetection.IsSet) + { + writer.WriteBoolean(nameof(RequiresDuplicateDetection), topic.RequiresDuplicateDetection.Value); + } + if (topic.Status.IsSet) + { + writer.WriteString(nameof(Status), topic.Status.Value.ToString()); + } + + writer.WriteEndObject(); + } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index 12aa48792d..b510630d2c 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -2,15 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; -using System.Xml; +using Aspire.Hosting.Azure.ServiceBus.ApplicationModel; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Azure; using Aspire.Hosting.Azure.ServiceBus; using Aspire.Hosting.Utils; using Azure.Messaging.ServiceBus; using Azure.Provisioning; -using Azure.Provisioning.ServiceBus; using Microsoft.Extensions.DependencyInjection; +using AzureProvisioning = Azure.Provisioning.ServiceBus; namespace Aspire.Hosting; @@ -37,9 +37,9 @@ public static IResourceBuilder AddAzureServiceBus(this }; infrastructure.Add(skuParameter); - var serviceBusNamespace = new ServiceBusNamespace(infrastructure.AspireResource.GetBicepIdentifier()) + var serviceBusNamespace = new AzureProvisioning.ServiceBusNamespace(infrastructure.AspireResource.GetBicepIdentifier()) { - Sku = new ServiceBusSku() + Sku = new AzureProvisioning.ServiceBusSku() { Name = skuParameter }, @@ -50,7 +50,7 @@ public static IResourceBuilder AddAzureServiceBus(this var principalTypeParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalType, typeof(string)); var principalIdParameter = new ProvisioningParameter(AzureBicepResource.KnownParameters.PrincipalId, typeof(string)); - infrastructure.Add(serviceBusNamespace.CreateRoleAssignment(ServiceBusBuiltInRole.AzureServiceBusDataOwner, principalTypeParameter, principalIdParameter)); + infrastructure.Add(serviceBusNamespace.CreateRoleAssignment(AzureProvisioning.ServiceBusBuiltInRole.AzureServiceBusDataOwner, principalTypeParameter, principalIdParameter)); infrastructure.Add(new ProvisioningOutput("serviceBusEndpoint", typeof(string)) { Value = serviceBusNamespace.ServiceBusEndpoint }); @@ -58,33 +58,37 @@ public static IResourceBuilder AddAzureServiceBus(this foreach (var queue in azureResource.Queues) { - queue.Parent = serviceBusNamespace; - infrastructure.Add(queue); + var cdkQueue = queue.ToProvisioningEntity(); + cdkQueue.Parent = serviceBusNamespace; + infrastructure.Add(cdkQueue); } - var topicDictionary = new Dictionary(); + var topicDictionary = new Dictionary(); foreach (var topic in azureResource.Topics) { - topic.Parent = serviceBusNamespace; - infrastructure.Add(topic); + var cdkTopic = topic.ToProvisioningEntity(); + cdkTopic.Parent = serviceBusNamespace; + infrastructure.Add(cdkTopic); // Topics are added in the dictionary with their normalized names. - topicDictionary.Add(topic.BicepIdentifier, topic); + topicDictionary.Add(topic.Id, cdkTopic); } - var subscriptionDictionary = new Dictionary<(string, string), ServiceBusSubscription>(); + var subscriptionDictionary = new Dictionary<(string, string), AzureProvisioning.ServiceBusSubscription>(); foreach (var (topicName, subscription) in azureResource.Subscriptions) { + var cdkSubscription = subscription.ToProvisioningEntity(); var topic = topicDictionary[topicName]; - subscription.Parent = topic; - infrastructure.Add(subscription); + cdkSubscription.Parent = topic; + infrastructure.Add(cdkSubscription); // Subscriptions are added in the dictionary with their normalized names. - subscriptionDictionary.Add((topicName, subscription.BicepIdentifier), subscription); + subscriptionDictionary.Add((topicName, subscription.Id), cdkSubscription); } foreach (var (topicName, subscriptionName, rule) in azureResource.Rules) { + var cdkRule = rule.ToProvisioningEntity(); var subscription = subscriptionDictionary[(topicName, subscriptionName)]; - rule.Parent = subscription; - infrastructure.Add(rule); + cdkRule.Parent = subscription; + infrastructure.Add(cdkRule); } }; @@ -343,343 +347,50 @@ public static IResourceBuilder RunAsEmulator(this IReso foreach (var queue in emulatorResource.Queues) { - writer.WriteStartObject(); // { - if (((IBicepValue)queue.Name).IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.Name), queue.Name.Value); - } - writer.WriteStartObject("Properties"); // "Properties": { - if (queue.AutoDeleteOnIdle.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.AutoDeleteOnIdle), XmlConvert.ToString(queue.AutoDeleteOnIdle.Value)); - } - if (queue.DeadLetteringOnMessageExpiration.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusQueue.DeadLetteringOnMessageExpiration), queue.DeadLetteringOnMessageExpiration.Value); - } - if (queue.DefaultMessageTimeToLive.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.DefaultMessageTimeToLive), XmlConvert.ToString(queue.DefaultMessageTimeToLive.Value)); - } - if (queue.DuplicateDetectionHistoryTimeWindow.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(queue.DuplicateDetectionHistoryTimeWindow.Value)); - } - if (queue.EnableBatchedOperations.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusQueue.EnableBatchedOperations), queue.EnableBatchedOperations.Value); - } - if (queue.EnableExpress.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusQueue.EnableExpress), queue.EnableExpress.Value); - } - if (queue.EnablePartitioning.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusQueue.EnablePartitioning), queue.EnablePartitioning.Value); - } - if (queue.ForwardDeadLetteredMessagesTo.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.ForwardDeadLetteredMessagesTo), queue.ForwardDeadLetteredMessagesTo.Value); - } - if (queue.ForwardTo.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.ForwardTo), queue.ForwardTo.Value); - } - if (queue.LockDuration.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.LockDuration), XmlConvert.ToString(queue.LockDuration.Value)); - } - if (queue.MaxDeliveryCount.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusQueue.MaxDeliveryCount), queue.MaxDeliveryCount.Value); - } - if (queue.MaxMessageSizeInKilobytes.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusQueue.MaxMessageSizeInKilobytes), queue.MaxMessageSizeInKilobytes.Value); - } - if (queue.MaxSizeInMegabytes.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusQueue.MaxSizeInMegabytes), queue.MaxSizeInMegabytes.Value); - } - if (queue.RequiresDuplicateDetection.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusQueue.RequiresDuplicateDetection), queue.RequiresDuplicateDetection.Value); - } - if (queue.RequiresSession.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusQueue.RequiresSession), queue.RequiresSession.Value); - } - if (queue.Status.IsSet()) - { - writer.WriteString(nameof(ServiceBusTopic.Status), queue.Status.Value.ToString()); - } - writer.WriteEndObject(); // } (/Properties) - - writer.WriteEndObject(); // } (/Queue) + writer.WriteStartObject(); + queue.WriteJsonObjectProperties(writer); + writer.WriteEndObject(); } + writer.WriteEndArray(); // ] (/Queues) writer.WriteStartArray("Topics"); // "Topics": [ foreach (var topic in emulatorResource.Topics) { - writer.WriteStartObject(); // { - if (topic.Name.IsSet()) - { - writer.WriteString(nameof(ServiceBusTopic.Name), topic.Name.Value); - } - writer.WriteStartObject("Properties"); // "Properties": { - if (topic.AutoDeleteOnIdle.IsSet()) - { - writer.WriteString(nameof(ServiceBusTopic.AutoDeleteOnIdle), XmlConvert.ToString(topic.AutoDeleteOnIdle.Value)); - } - if (topic.DefaultMessageTimeToLive.IsSet()) - { - writer.WriteString(nameof(ServiceBusTopic.DefaultMessageTimeToLive), XmlConvert.ToString(topic.DefaultMessageTimeToLive.Value)); - } - if (topic.DuplicateDetectionHistoryTimeWindow.IsSet()) - { - writer.WriteString(nameof(ServiceBusTopic.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(topic.DuplicateDetectionHistoryTimeWindow.Value)); - } - if (topic.EnableBatchedOperations.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusTopic.EnableBatchedOperations), topic.EnableBatchedOperations.Value); - } - if (topic.EnableExpress.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusTopic.EnableExpress), topic.EnableExpress.Value); - } - if (topic.EnablePartitioning.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusTopic.EnablePartitioning), topic.EnablePartitioning.Value); - } - if (topic.MaxMessageSizeInKilobytes.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusTopic.MaxMessageSizeInKilobytes), topic.MaxMessageSizeInKilobytes.Value); - } - if (topic.MaxSizeInMegabytes.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusTopic.MaxSizeInMegabytes), topic.MaxSizeInMegabytes.Value); - } - if (topic.RequiresDuplicateDetection.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusTopic.RequiresDuplicateDetection), topic.RequiresDuplicateDetection.Value); - } - if (topic.Status.IsSet()) - { - writer.WriteString(nameof(ServiceBusTopic.Status), topic.Status.Value.ToString()); - } - writer.WriteEndObject(); // } (/Properties) + writer.WriteStartObject(); // "{ (Topic)" + topic.WriteJsonObjectProperties(writer); - writer.WriteStartArray("Subscriptions"); // "Subscriptions": [ + writer.WriteStartArray("Subscriptions"); // "Subscriptions": [ foreach (var (topicName, subscription) in emulatorResource.Subscriptions) { - if (topicName != topic.BicepIdentifier) + if (topicName != topic.Id) { continue; } - - writer.WriteStartObject(); // { - if (topic.Name.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.Name), subscription.Name.Value); - } - - writer.WriteStartObject("Properties"); // "Properties": { - if (subscription.Status.IsSet()) - { - writer.WriteString(nameof(ServiceBusSubscription.AutoDeleteOnIdle), XmlConvert.ToString(subscription.AutoDeleteOnIdle.Value)); - } - if (subscription.ClientAffineProperties.IsSet() && subscription.ClientAffineProperties != null) - { - writer.WriteStartObject("ClientAffineProperties"); // "ClientAffineProperties": { - - if (subscription.ClientAffineProperties.ClientId.IsSet()) - { - writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), subscription.ClientAffineProperties.ClientId.Value); - } - if (subscription.ClientAffineProperties.IsDurable.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), subscription.ClientAffineProperties.IsDurable.Value); - } - if (subscription.ClientAffineProperties.IsShared.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), subscription.ClientAffineProperties.IsShared.Value); - } - - writer.WriteEndObject(); // } (/ClientAffineProperties) - } - if (subscription.DeadLetteringOnFilterEvaluationExceptions.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions), subscription.DeadLetteringOnFilterEvaluationExceptions.Value); - } - if (subscription.DeadLetteringOnMessageExpiration.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusSubscription.DeadLetteringOnMessageExpiration), subscription.DeadLetteringOnMessageExpiration.Value); - } - if (subscription.DefaultMessageTimeToLive.IsSet()) - { - writer.WriteString(nameof(ServiceBusSubscription.DefaultMessageTimeToLive), XmlConvert.ToString(subscription.DefaultMessageTimeToLive.Value)); - } - if (subscription.DuplicateDetectionHistoryTimeWindow.IsSet()) - { - writer.WriteString(nameof(ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(subscription.DuplicateDetectionHistoryTimeWindow.Value)); - } - if (subscription.EnableBatchedOperations.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusSubscription.EnableBatchedOperations), subscription.EnableBatchedOperations.Value); - } - if (subscription.ForwardDeadLetteredMessagesTo.IsSet()) - { - writer.WriteString(nameof(ServiceBusSubscription.ForwardDeadLetteredMessagesTo), subscription.ForwardDeadLetteredMessagesTo.Value); - } - if (subscription.ForwardTo.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.ForwardTo), subscription.ForwardTo.Value); - } - if (subscription.IsClientAffine.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusSubscription.IsClientAffine), subscription.IsClientAffine.Value); - } - if (subscription.LockDuration.IsSet()) - { - writer.WriteString(nameof(ServiceBusSubscription.LockDuration), XmlConvert.ToString(subscription.LockDuration.Value)); - } - if (subscription.MaxDeliveryCount.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusSubscription.MaxDeliveryCount), subscription.MaxDeliveryCount.Value); - } - if (subscription.RequiresSession.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusSubscription.RequiresSession), subscription.RequiresSession.Value); - } - if (subscription.Status.IsSet()) - { - writer.WriteString(nameof(ServiceBusSubscription.Status), subscription.Status.Value.ToString()); - } - writer.WriteEndObject(); // } (/Properties) + writer.WriteStartObject(); // "{ (Subscription)" + subscription.WriteJsonObjectProperties(writer); #region Rules - writer.WriteStartArray("Rules"); // "Rules": [ + writer.WriteStartArray("Rules"); // "Rules": [ foreach (var (ruleTopicName, ruleSubscriptionName, rule) in emulatorResource.Rules) { - if (ruleTopicName != topic.BicepIdentifier && ruleSubscriptionName != subscription.BicepIdentifier) + if (ruleTopicName != topic.Id && ruleSubscriptionName != subscription.Id) { continue; } - writer.WriteStartObject(); // { - if (rule.Name.IsSet()) - { - writer.WriteString(nameof(ServiceBusQueue.Name), rule.Name.Value); - } - writer.WriteStartObject("Properties"); // "Properties": { - - if (rule.Action.IsSet() && rule.Action != null) - { - writer.WriteStartObject(nameof(ServiceBusRule.Action)); - if (rule.Action.SqlExpression.IsSet()) - { - writer.WriteString(nameof(ServiceBusFilterAction.SqlExpression), rule.Action.SqlExpression.Value); - } - if (rule.Action.CompatibilityLevel.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusFilterAction.CompatibilityLevel), rule.Action.CompatibilityLevel.Value); - } - if (rule.Action.RequiresPreprocessing.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusFilterAction.RequiresPreprocessing), rule.Action.RequiresPreprocessing.Value); - } - writer.WriteEndObject(); - } - - if (rule.CorrelationFilter.IsSet() && rule.CorrelationFilter != null) - { - writer.WriteStartObject(nameof(ServiceBusRule.CorrelationFilter)); - - if (rule.CorrelationFilter.ApplicationProperties.IsSet() && rule.CorrelationFilter.ApplicationProperties != null) - { - var dic = new Dictionary(); - - foreach (var applicationProperty in rule.CorrelationFilter.ApplicationProperties) - { - dic.Add(applicationProperty.Key, applicationProperty.Value); - } - - JsonSerializer.Serialize(writer, dic); - } - if (rule.CorrelationFilter.CorrelationId.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.CorrelationId), rule.CorrelationFilter.CorrelationId.Value); - } - if (rule.CorrelationFilter.MessageId.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.MessageId), rule.CorrelationFilter.MessageId.Value); - } - if (rule.CorrelationFilter.SendTo.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.SendTo), rule.CorrelationFilter.SendTo.Value); - } - if (rule.CorrelationFilter.ReplyTo.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyTo), rule.CorrelationFilter.ReplyTo.Value); - } - if (rule.CorrelationFilter.Subject.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.Subject), rule.CorrelationFilter.Subject.Value); - } - if (rule.CorrelationFilter.SessionId.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.SessionId), rule.CorrelationFilter.SessionId.Value); - } - if (rule.CorrelationFilter.ReplyToSessionId.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyToSessionId), rule.CorrelationFilter.ReplyToSessionId.Value); - } - if (rule.CorrelationFilter.ContentType.IsSet()) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ContentType), rule.CorrelationFilter.ContentType.Value); - } - if (rule.CorrelationFilter.RequiresPreprocessing.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusCorrelationFilter.RequiresPreprocessing), rule.CorrelationFilter.RequiresPreprocessing.Value); - } - - writer.WriteEndObject(); - } - - if (rule.FilterType.IsSet()) - { - writer.WriteString(nameof(ServiceBusRule.FilterType), rule.FilterType.Value.ToString()); - } - - if (rule.SqlFilter.IsSet() && rule.SqlFilter != null) - { - writer.WriteStartObject(nameof(ServiceBusRule.SqlFilter)); - if (rule.SqlFilter.SqlExpression.IsSet()) - { - writer.WriteString(nameof(ServiceBusSqlFilter.SqlExpression), rule.SqlFilter.SqlExpression.Value); - } - if (rule.SqlFilter.CompatibilityLevel.IsSet()) - { - writer.WriteNumber(nameof(ServiceBusSqlFilter.CompatibilityLevel), rule.SqlFilter.CompatibilityLevel.Value); - } - if (rule.SqlFilter.RequiresPreprocessing.IsSet()) - { - writer.WriteBoolean(nameof(ServiceBusSqlFilter.RequiresPreprocessing), rule.SqlFilter.RequiresPreprocessing.Value); - } - writer.WriteEndObject(); - } - - writer.WriteEndObject(); // } (/Rule) + writer.WriteStartObject(); + rule.WriteJsonObjectProperties(writer); + writer.WriteEndObject(); } - writer.WriteEndArray(); + writer.WriteEndArray(); // ] (/Rules) #endregion Rules - writer.WriteEndObject(); // } (/Subscription) + writer.WriteEndObject(); // } (/Subscription) } - writer.WriteEndArray(); // ] (/Subscriptions) + writer.WriteEndArray(); // ] (/Subscriptions) writer.WriteEndObject(); // } (/Topic) } @@ -743,6 +454,4 @@ public static IResourceBuilder WithGatewayPort( endpoint.Port = port; }); } - - private static bool IsSet(this IBicepValue value) => value.Kind != BicepValueKind.Unset; } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs index fc4cca046b..a1541aec18 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; -using Azure.Provisioning.ServiceBus; +using Aspire.Hosting.Azure.ServiceBus.ApplicationModel; namespace Aspire.Hosting.Azure; diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index c2018cbd8b..1de8924c19 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -8,13 +8,209 @@ Aspire.Hosting.Azure.AzureServiceBusEmulatorResource Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.AzureServiceBusEmulatorResource(Aspire.Hosting.Azure.AzureServiceBusResource! innerResource) -> void Aspire.Hosting.Azure.AzureServiceBusResource.AzureServiceBusResource(string! name, System.Action! configureInfrastructure) -> void Aspire.Hosting.Azure.AzureServiceBusResource.IsEmulator.get -> bool +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.IsSet.get -> bool +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.OptionalValue() -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.OptionalValue(T value) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.Value.get -> T? +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.ClientId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.ClientId.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsDurable.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsDurable.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsShared.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsShared.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.ServiceBusClientAffineProperties() -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ApplicationProperties.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue!>! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ApplicationProperties.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ContentType.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ContentType.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.CorrelationId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.CorrelationId.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.MessageId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.MessageId.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyToSessionId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyToSessionId.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.RequiresPreprocessing.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.RequiresPreprocessing.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SendTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SendTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ServiceBusCorrelationFilter() -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SessionId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SessionId.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.Subject.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.Subject.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.CompatibilityLevel.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.CompatibilityLevel.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.RequiresPreprocessing.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.RequiresPreprocessing.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.ServiceBusFilterAction() -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.SqlExpression.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.SqlExpression.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType.CorrelationFilter = 1 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType.SqlFilter = 0 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Active = 1 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Creating = 6 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Deleting = 7 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Disabled = 2 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.ReceiveDisabled = 5 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Renaming = 8 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Restoring = 3 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.SendDisabled = 4 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Unknown = 0 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.AutoDeleteOnIdle.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.AutoDeleteOnIdle.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DeadLetteringOnMessageExpiration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DeadLetteringOnMessageExpiration.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DefaultMessageTimeToLive.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DefaultMessageTimeToLive.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DuplicateDetectionHistoryTimeWindow.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DuplicateDetectionHistoryTimeWindow.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableBatchedOperations.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableBatchedOperations.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableExpress.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableExpress.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnablePartitioning.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnablePartitioning.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardDeadLetteredMessagesTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardDeadLetteredMessagesTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.LockDuration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.LockDuration.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxDeliveryCount.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxDeliveryCount.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxMessageSizeInKilobytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxMessageSizeInKilobytes.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxSizeInMegabytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxSizeInMegabytes.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresDuplicateDetection.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresDuplicateDetection.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresSession.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresSession.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ServiceBusQueue(string! id) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Status.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Status.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusQueue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Action.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Action.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.CorrelationFilter.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.CorrelationFilter.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.FilterType.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.FilterType.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.ServiceBusRule(string! id) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.SqlFilter.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.SqlFilter.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusRule! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.CompatibilityLevel.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.CompatibilityLevel.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.RequiresPreprocessing.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.RequiresPreprocessing.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.ServiceBusSqlFilter() -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.SqlExpression.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.SqlExpression.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.AutoDeleteOnIdle.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.AutoDeleteOnIdle.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ClientAffineProperties.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ClientAffineProperties.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnMessageExpiration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnMessageExpiration.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DefaultMessageTimeToLive.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DefaultMessageTimeToLive.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.EnableBatchedOperations.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.EnableBatchedOperations.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardDeadLetteredMessagesTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardDeadLetteredMessagesTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.IsClientAffine.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.IsClientAffine.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.LockDuration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.LockDuration.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxDeliveryCount.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxDeliveryCount.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxMessageSizeInKilobytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxMessageSizeInKilobytes.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.RequiresSession.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.RequiresSession.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ServiceBusSubscription(string! id) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Status.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Status.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusSubscription! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.AutoDeleteOnIdle.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.AutoDeleteOnIdle.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DeadLetteringOnMessageExpiration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DeadLetteringOnMessageExpiration.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DefaultMessageTimeToLive.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DefaultMessageTimeToLive.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DuplicateDetectionHistoryTimeWindow.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DuplicateDetectionHistoryTimeWindow.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableBatchedOperations.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableBatchedOperations.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableExpress.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableExpress.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnablePartitioning.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnablePartitioning.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardDeadLetteredMessagesTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardDeadLetteredMessagesTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.LockDuration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.LockDuration.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxDeliveryCount.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxDeliveryCount.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxMessageSizeInKilobytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxMessageSizeInKilobytes.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxSizeInMegabytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxSizeInMegabytes.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresDuplicateDetection.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresDuplicateDetection.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresSession.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresSession.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ServiceBusTopic(string! id) -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Status.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Status.set -> void +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusTopic! +Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Annotations.get -> Aspire.Hosting.ApplicationModel.ResourceAnnotationCollection! override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Name.get -> string! -static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.implicit operator Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue!(T value) -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! +static Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.implicit operator T?(Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! value) -> T? +static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.RunAsEmulator(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, System.Action!>? configureContainer = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithConfigJson(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! path) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string? path = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs index a2120577d5..c4297c9c16 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusEmulatorContainerImageTags.cs @@ -6,13 +6,13 @@ namespace Aspire.Hosting.Azure.ServiceBus; internal static class ServiceBusEmulatorContainerImageTags { /// mcr.microsoft.com - public const string Registry = "messagingemulators.azurecr.io"; + public const string Registry = "mcr.microsoft.com"; - /// internal/azure-messaging/servicebus-emulator - public const string Image = "internal/azure-messaging/servicebus-emulator"; + /// azure-messaging/servicebus-emulator + public const string Image = "azure-messaging/servicebus-emulator"; - /// 1.0.1-alpha - public const string Tag = "1.0.1-alpha"; + /// 1.0.1 + public const string Tag = "1.0.1"; /// mcr.microsoft.com public const string AzureSqlEdgeRegistry = "mcr.microsoft.com"; From 63dae9e04cb0085b8ad72cfcf6af6b1b37c03f70 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Wed, 20 Nov 2024 09:04:52 -0800 Subject: [PATCH 06/17] Remove unnecessary ! --- .../ServiceBusClientAffineProperties.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs index a64743b070..491052d3fd 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs @@ -25,8 +25,8 @@ public ServiceBusClientAffineProperties() /// public OptionalValue ClientId { - get { return _clientId!; } - set { _clientId!.Assign(value); } + get { return _clientId; } + set { _clientId.Assign(value); } } /// @@ -35,8 +35,8 @@ public OptionalValue ClientId /// public OptionalValue IsDurable { - get { return _isDurable!; } - set { _isDurable!.Assign(value); } + get { return _isDurable; } + set { _isDurable.Assign(value); } } /// @@ -45,7 +45,7 @@ public OptionalValue IsDurable /// public OptionalValue IsShared { - get { return _isShared!; } - set { _isShared!.Assign(value); } + get { return _isShared; } + set { _isShared.Assign(value); } } } From 9e3ae513cb3d2dcb92ca9715cd8fc2c2a0c591a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Ros?= Date: Wed, 20 Nov 2024 09:13:02 -0800 Subject: [PATCH 07/17] Update src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs Co-authored-by: David Pine --- .../ApplicationModel/OptionalValue.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs index 81a05d6414..485368e424 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs @@ -9,7 +9,6 @@ namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; /// The type of the value. public sealed class OptionalValue { - /// /// Initializes a new instance of the class. /// From 0a971eb0ee2bb6fac6bebb06bfb92a3a18d413a6 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Wed, 20 Nov 2024 14:42:43 -0800 Subject: [PATCH 08/17] Remove OptionalValue --- .../ServiceBus.AppHost/Program.cs | 5 +- .../ApplicationModel/OptionalValue.cs | 69 ---- .../ServiceBusClientAffineProperties.cs | 51 --- .../ServiceBusCorrelationFilter.cs | 73 +---- .../ServiceBusFilterAction.cs | 50 --- .../ApplicationModel/ServiceBusFilterType.cs | 2 +- .../ServiceBusMessagingEntityStatus.cs | 55 ---- .../ApplicationModel/ServiceBusQueue.cs | 275 +++------------- .../ApplicationModel/ServiceBusRule.cs | 289 +++++------------ .../ApplicationModel/ServiceBusSqlFilter.cs | 50 --- .../ServiceBusSubscription.cs | 272 +++------------- .../ApplicationModel/ServiceBusTopic.cs | 265 ++------------- .../AzureServiceBusExtensions.cs | 17 +- .../AzureServiceBusResource.cs | 2 +- .../PublicAPI.Unshipped.txt | 301 ++++++------------ 15 files changed, 343 insertions(+), 1433 deletions(-) delete mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs delete mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs delete mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs delete mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs delete mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs index 46dcb76336..3aced78406 100644 --- a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs +++ b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs @@ -1,5 +1,3 @@ -//using Aspire.Hosting.Azure.ServiceBus.ApplicationModel; - var builder = DistributedApplication.CreateBuilder(args); var serviceBus = builder.AddAzureServiceBus("sbemulator") @@ -39,8 +37,7 @@ //.AddRule("myTopic", "mySubscription", "myRule", rule => //{ // rule.Name = "app-prop-filter-1"; - // rule.FilterType = ServiceBusFilterType.CorrelationFilter; - // rule.CorrelationFilter = new ServiceBusCorrelationFilter + // rule.CorrelationFilter = new() // { // ContentType = "application/text", // CorrelationId = "id1", diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs deleted file mode 100644 index 485368e424..0000000000 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/OptionalValue.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; - -/// -/// Represents an optional value. -/// -/// The type of the value. -public sealed class OptionalValue -{ - /// - /// Initializes a new instance of the class. - /// - public OptionalValue() - { - Value = default; - } - - /// - /// Initializes a new instance of the class with a specified value. - /// - /// The value to initialize with. - public OptionalValue(T value) - { - Value = value; - IsSet = true; - } - - /// - /// Gets or sets the literal value. - /// - public T? Value { get; private set; } - - /// - /// Gets a value indicating whether the value has been set. - /// - public bool IsSet { get; private set; } - - /// - /// Assigns a value. - /// - /// The value to assign. - internal void Assign(OptionalValue lazyValue) - { - Value = lazyValue.Value; - IsSet = true; - } - - /// - /// Implicitly converts a value to a LazyValue{T}. - /// - /// The value to convert. - /// A LazyValue{T} containing the value. - public static implicit operator OptionalValue(T value) - { - return new(value); - } - - /// - /// Implicitly converts a value to a LazyValue{T}. - /// - /// The value to convert. - /// A LazyValue{T} containing the value. - public static implicit operator T?(OptionalValue value) - { - return value.Value; - } -} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs deleted file mode 100644 index 491052d3fd..0000000000 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusClientAffineProperties.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; - -/// -/// Properties specific to client affine subscriptions. -/// -public class ServiceBusClientAffineProperties -{ - private readonly OptionalValue _clientId = new(); - private readonly OptionalValue _isDurable = new(); - private readonly OptionalValue _isShared = new(); - - /// - /// Creates a new ServiceBusClientAffineProperties. - /// - public ServiceBusClientAffineProperties() - { - } - - /// - /// Indicates the Client ID of the application that created the - /// client-affine subscription. - /// - public OptionalValue ClientId - { - get { return _clientId; } - set { _clientId.Assign(value); } - } - - /// - /// For client-affine subscriptions, this value indicates whether the - /// subscription is durable or not. - /// - public OptionalValue IsDurable - { - get { return _isDurable; } - set { _isDurable.Assign(value); } - } - - /// - /// For client-affine subscriptions, this value indicates whether the - /// subscription is shared or not. - /// - public OptionalValue IsShared - { - get { return _isShared; } - set { _isShared.Assign(value); } - } -} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs index 4049548696..669a4cd830 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusCorrelationFilter.cs @@ -1,24 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; +namespace Aspire.Hosting.Azure.ServiceBus; /// /// Represents the correlation filter expression. /// public class ServiceBusCorrelationFilter { - private readonly OptionalValue> _applicationProperties = new(); - private readonly OptionalValue _correlationId = new(); - private readonly OptionalValue _messageId = new(); - private readonly OptionalValue _sendTo = new(); - private readonly OptionalValue _replyTo = new(); - private readonly OptionalValue _subject = new(); - private readonly OptionalValue _sessionId = new(); - private readonly OptionalValue _replyToSessionId = new(); - private readonly OptionalValue _contentType = new(); - private readonly OptionalValue _requiresPreprocessing = new(); - /// /// Represents the correlation filter expression. /// @@ -29,90 +18,50 @@ public ServiceBusCorrelationFilter() /// /// Dictionary object for custom filters. /// - public OptionalValue> ApplicationProperties - { - get { return _applicationProperties; } - set { _applicationProperties.Assign(value); } - } + public Dictionary Properties { get; set; } = []; /// /// Identifier of the correlation. /// - public OptionalValue CorrelationId - { - get { return _correlationId; } - set { _correlationId.Assign(value); } - } + public string? CorrelationId { get; set; } /// /// Identifier of the message. /// - public OptionalValue MessageId - { - get { return _messageId; } - set { _messageId.Assign(value); } - } + public string? MessageId { get; set; } /// /// Address to send to. /// - public OptionalValue SendTo - { - get { return _sendTo; } - set { _sendTo.Assign(value); } - } + public string? SendTo { get; set; } /// /// Address of the queue to reply to. /// - public OptionalValue ReplyTo - { - get { return _replyTo; } - set { _replyTo.Assign(value); } - } + public string? ReplyTo { get; set; } /// /// Application specific label. /// - public OptionalValue Subject - { - get { return _subject; } - set { _subject.Assign(value); } - } + public string? Subject { get; set; } /// /// Session identifier. /// - public OptionalValue SessionId - { - get { return _sessionId; } - set { _sessionId.Assign(value); } - } + public string? SessionId { get; set; } /// /// Session identifier to reply to. /// - public OptionalValue ReplyToSessionId - { - get { return _replyToSessionId; } - set { _replyToSessionId.Assign(value); } - } + public string? ReplyToSessionId { get; set; } /// /// Content type of the message. /// - public OptionalValue ContentType - { - get { return _contentType; } - set { _contentType.Assign(value); } - } + public string? ContentType { get; set; } /// /// Value that indicates whether the rule action requires preprocessing. /// - public OptionalValue RequiresPreprocessing - { - get { return _requiresPreprocessing; } - set { _requiresPreprocessing.Assign(value); } - } + public bool? RequiresPreprocessing { get; set; } } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs deleted file mode 100644 index 87befa51f9..0000000000 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterAction.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; - -/// -/// Represents the filter actions which are allowed for the transformation of a -/// message that have been matched by a filter expression. -/// -public class ServiceBusFilterAction -{ - private readonly OptionalValue _sqlExpression = new(); - private readonly OptionalValue _compatibilityLevel = new(); - private readonly OptionalValue _requiresPreprocessing = new(); - - /// - /// Creates a new ServiceBusFilterAction. - /// - public ServiceBusFilterAction() - { - } - - /// - /// SQL expression. e.g. MyProperty='ABC'. - /// - public OptionalValue SqlExpression - { - get { return _sqlExpression; } - set { _sqlExpression.Assign(value); } - } - - /// - /// This property is reserved for future use. An integer value showing the - /// compatibility level, currently hard-coded to 20. - /// - public OptionalValue CompatibilityLevel - { - get { return _compatibilityLevel; } - set { _compatibilityLevel.Assign(value); } - } - - /// - /// Value that indicates whether the rule action requires preprocessing. - /// - public OptionalValue RequiresPreprocessing - { - get { return _requiresPreprocessing; } - set { _requiresPreprocessing.Assign(value); } - } -} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs index b040ec7f59..6696bc715e 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusFilterType.cs @@ -1,7 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; +namespace Aspire.Hosting.Azure.ServiceBus; /// /// Rule filter types. diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs deleted file mode 100644 index bdcac195ff..0000000000 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusMessagingEntityStatus.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; - -/// -/// Entity status. -/// -public enum ServiceBusMessagingEntityStatus -{ - /// - /// Unknown. - /// - Unknown, - - /// - /// Active. - /// - Active, - - /// - /// Disabled. - /// - Disabled, - - /// - /// Restoring. - /// - Restoring, - - /// - /// SendDisabled. - /// - SendDisabled, - - /// - /// ReceiveDisabled. - /// - ReceiveDisabled, - - /// - /// Creating. - /// - Creating, - - /// - /// Deleting. - /// - Deleting, - - /// - /// Renaming. - /// - Renaming, -} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs index f733e0f071..406df9b081 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusQueue.cs @@ -4,37 +4,32 @@ using System.Text.Json; using System.Xml; -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; +namespace Aspire.Hosting.Azure.ServiceBus; /// /// Represents a Service Bus Queue. /// +/// +/// List of properties from the CDK that are not exposed here: +/// - AutoDeleteOnIdle +/// - EnableBatchedOperations +/// - EnableExpress +/// - EnablePartitioning +/// - MaxMessageSizeInKilobytes +/// - MaxSizeInMegabytes +/// - Status +/// +/// Use to configure these specific properties. +/// public class ServiceBusQueue { - private readonly OptionalValue _name = new(); - private readonly OptionalValue _autoDeleteOnIdle = new(); - private readonly OptionalValue _deadLetteringOnMessageExpiration = new(); - private readonly OptionalValue _defaultMessageTimeToLive = new(); - private readonly OptionalValue _duplicateDetectionHistoryTimeWindow = new(); - private readonly OptionalValue _enableBatchedOperations = new(); - private readonly OptionalValue _enableExpress = new(); - private readonly OptionalValue _enablePartitioning = new(); - private readonly OptionalValue _forwardDeadLetteredMessagesTo = new(); - private readonly OptionalValue _forwardTo = new(); - private readonly OptionalValue _lockDuration = new(); - private readonly OptionalValue _maxDeliveryCount = new(); - private readonly OptionalValue _maxMessageSizeInKilobytes = new(); - private readonly OptionalValue _maxSizeInMegabytes = new(); - private readonly OptionalValue _requiresDuplicateDetection = new(); - private readonly OptionalValue _requiresSession = new(); - private readonly OptionalValue _status = new(); - /// /// Initializes a new instance of the class. /// - public ServiceBusQueue(string id) + public ServiceBusQueue(string id, string name) { Id = id; + Name = name; } /// @@ -45,31 +40,13 @@ public ServiceBusQueue(string id) /// /// The queue name. /// - public OptionalValue Name - { - get { return _name; } - set { _name.Assign(value); } - } - - /// - /// ISO 8061 timeSpan idle interval after which the queue is automatically - /// deleted. The minimum duration is 5 minutes. - /// - public OptionalValue AutoDeleteOnIdle - { - get { return _autoDeleteOnIdle; } - set { _autoDeleteOnIdle.Assign(value); } - } + public string Name { get; set; } /// /// A value that indicates whether this queue has dead letter support when /// a message expires. /// - public OptionalValue DeadLetteringOnMessageExpiration - { - get { return _deadLetteringOnMessageExpiration; } - set { _deadLetteringOnMessageExpiration.Assign(value); } - } + public bool? DeadLetteringOnMessageExpiration { get; set; } /// /// ISO 8601 default message timespan to live value. This is the duration @@ -77,138 +54,47 @@ public OptionalValue DeadLetteringOnMessageExpiration /// sent to Service Bus. This is the default value used when TimeToLive is /// not set on a message itself. /// - public OptionalValue DefaultMessageTimeToLive - { - get { return _defaultMessageTimeToLive; } - set { _defaultMessageTimeToLive.Assign(value); } - } + public TimeSpan? DefaultMessageTimeToLive { get; set; } /// /// ISO 8601 timeSpan structure that defines the duration of the duplicate /// detection history. The default value is 10 minutes. /// - public OptionalValue DuplicateDetectionHistoryTimeWindow - { - get { return _duplicateDetectionHistoryTimeWindow; } - set { _duplicateDetectionHistoryTimeWindow.Assign(value); } - } - - /// - /// Value that indicates whether server-side batched operations are enabled. - /// - public OptionalValue EnableBatchedOperations - { - get { return _enableBatchedOperations; } - set { _enableBatchedOperations.Assign(value); } - } - - /// - /// A value that indicates whether Express Entities are enabled. An express - /// queue holds a message in memory temporarily before writing it to - /// persistent storage. - /// - public OptionalValue EnableExpress - { - get { return _enableExpress; } - set { _enableExpress.Assign(value); } - } - - /// - /// A value that indicates whether the queue is to be partitioned across - /// multiple message brokers. - /// - public OptionalValue EnablePartitioning - { - get { return _enablePartitioning; } - set { _enablePartitioning.Assign(value); } - } + public TimeSpan? DuplicateDetectionHistoryTimeWindow { get; set; } /// /// Queue/Topic name to forward the Dead Letter message. /// - public OptionalValue ForwardDeadLetteredMessagesTo - { - get { return _forwardDeadLetteredMessagesTo; } - set { _forwardDeadLetteredMessagesTo.Assign(value); } - } + public string? ForwardDeadLetteredMessagesTo { get; set; } /// /// Queue/Topic name to forward the messages. /// - public OptionalValue ForwardTo - { - get { return _forwardTo; } - set { _forwardTo.Assign(value); } - } + public string? ForwardTo { get; set; } /// /// ISO 8601 timespan duration of a peek-lock; that is, the amount of time /// that the message is locked for other receivers. The maximum value for /// LockDuration is 5 minutes; the default value is 1 minute. /// - public OptionalValue LockDuration - { - get { return _lockDuration; } - set { _lockDuration.Assign(value); } - } + public TimeSpan? LockDuration { get; set; } /// - /// The maximum delivery count. A message is automatically deadlettered - /// after this number of deliveries. default value is 10. + /// The maximum delivery count. A message is automatically dead-lettered + /// after this number of deliveries. /// - public OptionalValue MaxDeliveryCount - { - get { return _maxDeliveryCount; } - set { _maxDeliveryCount.Assign(value); } - } - - /// - /// Maximum size (in KB) of the message payload that can be accepted by the - /// queue. This property is only used in Premium today and default is 1024. - /// - public OptionalValue MaxMessageSizeInKilobytes - { - get { return _maxMessageSizeInKilobytes; } - set { _maxMessageSizeInKilobytes.Assign(value); } - } - - /// - /// The maximum size of the queue in megabytes, which is the size of memory - /// allocated for the queue. Default is 1024. - /// - public OptionalValue MaxSizeInMegabytes - { - get { return _maxSizeInMegabytes; } - set { _maxSizeInMegabytes.Assign(value); } - } + public int? MaxDeliveryCount { get; set; } /// /// A value indicating if this queue requires duplicate detection. /// - public OptionalValue RequiresDuplicateDetection - { - get { return _requiresDuplicateDetection; } - set { _requiresDuplicateDetection.Assign(value); } - } + public bool? RequiresDuplicateDetection { get; set; } /// /// A value that indicates whether the queue supports the concept of /// sessions. /// - public OptionalValue RequiresSession - { - get { return _requiresSession; } - set { _requiresSession.Assign(value); } - } - - /// - /// Enumerates the possible values for the status of a messaging entity. - /// - public OptionalValue Status - { - get { return _status; } - set { _status.Assign(value); } - } + public bool? RequiresSession { get; set; } /// /// Converts the current instance to a provisioning entity. @@ -218,71 +104,44 @@ public OptionalValue Status { var queue = new global::Azure.Provisioning.ServiceBus.ServiceBusQueue(Id); - if (Name.IsSet && Name.Value != null) - { - queue.Name = Name.Value; - } + queue.Name = Name; - if (AutoDeleteOnIdle.IsSet) - { - queue.AutoDeleteOnIdle = AutoDeleteOnIdle.Value; - } - if (DeadLetteringOnMessageExpiration.IsSet) + if (DeadLetteringOnMessageExpiration.HasValue) { queue.DeadLetteringOnMessageExpiration = DeadLetteringOnMessageExpiration.Value; } - if (DefaultMessageTimeToLive.IsSet) + if (DefaultMessageTimeToLive.HasValue) { queue.DefaultMessageTimeToLive = DefaultMessageTimeToLive.Value; } - if (DuplicateDetectionHistoryTimeWindow.IsSet) + if (DuplicateDetectionHistoryTimeWindow.HasValue) { queue.DuplicateDetectionHistoryTimeWindow = DuplicateDetectionHistoryTimeWindow.Value; } - if (EnableBatchedOperations.IsSet) - { - queue.EnableBatchedOperations = EnableBatchedOperations.Value; - } - if (EnableExpress.IsSet) - { - queue.EnableExpress = EnableExpress.Value; - } - if (EnablePartitioning.IsSet) - { - queue.EnablePartitioning = EnablePartitioning.Value; - } - if (ForwardDeadLetteredMessagesTo.IsSet && ForwardDeadLetteredMessagesTo.Value != null) + if (ForwardDeadLetteredMessagesTo != null) { - queue.ForwardDeadLetteredMessagesTo = ForwardDeadLetteredMessagesTo.Value; + queue.ForwardDeadLetteredMessagesTo = ForwardDeadLetteredMessagesTo; } - if (ForwardTo.IsSet && ForwardTo.Value != null) + if (ForwardTo != null) { - queue.ForwardTo = ForwardTo.Value; + queue.ForwardTo = ForwardTo; } - if (LockDuration.IsSet) + if (LockDuration.HasValue) { queue.LockDuration = LockDuration.Value; } - if (MaxDeliveryCount.IsSet) + if (MaxDeliveryCount.HasValue) { queue.MaxDeliveryCount = MaxDeliveryCount.Value; } - if (MaxMessageSizeInKilobytes.IsSet) - { - queue.MaxSizeInMegabytes = MaxSizeInMegabytes.Value; - } - if (RequiresDuplicateDetection.IsSet) + if (RequiresDuplicateDetection.HasValue) { queue.RequiresDuplicateDetection = RequiresDuplicateDetection.Value; } - if (RequiresSession.IsSet) + if (RequiresSession.HasValue) { queue.RequiresSession = RequiresSession.Value; } - if (Status.IsSet) - { - queue.Status = Enum.Parse(Status.Value.ToString()); - } return queue; } @@ -294,76 +153,46 @@ public void WriteJsonObjectProperties(Utf8JsonWriter writer) { var queue = this; - if (queue.Name.IsSet) - { - writer.WriteString(nameof(Name), queue.Name.Value); - } + writer.WriteString(nameof(Name), queue.Name); + writer.WriteStartObject("Properties"); - if (queue.AutoDeleteOnIdle.IsSet) - { - writer.WriteString(nameof(AutoDeleteOnIdle), XmlConvert.ToString(queue.AutoDeleteOnIdle.Value)); - } - if (queue.DeadLetteringOnMessageExpiration.IsSet) + if (queue.DeadLetteringOnMessageExpiration.HasValue) { writer.WriteBoolean(nameof(DeadLetteringOnMessageExpiration), queue.DeadLetteringOnMessageExpiration.Value); } - if (queue.DefaultMessageTimeToLive.IsSet) + if (queue.DefaultMessageTimeToLive.HasValue) { writer.WriteString(nameof(DefaultMessageTimeToLive), XmlConvert.ToString(queue.DefaultMessageTimeToLive.Value)); } - if (queue.DuplicateDetectionHistoryTimeWindow.IsSet) + if (queue.DuplicateDetectionHistoryTimeWindow.HasValue) { writer.WriteString(nameof(DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(queue.DuplicateDetectionHistoryTimeWindow.Value)); } - if (queue.EnableBatchedOperations.IsSet) - { - writer.WriteBoolean(nameof(EnableBatchedOperations), queue.EnableBatchedOperations.Value); - } - if (queue.EnableExpress.IsSet) + if (queue.ForwardDeadLetteredMessagesTo != null) { - writer.WriteBoolean(nameof(EnableExpress), queue.EnableExpress.Value); + writer.WriteString(nameof(ForwardDeadLetteredMessagesTo), queue.ForwardDeadLetteredMessagesTo); } - if (queue.EnablePartitioning.IsSet) + if (queue.ForwardTo != null) { - writer.WriteBoolean(nameof(EnablePartitioning), queue.EnablePartitioning.Value); + writer.WriteString(nameof(ForwardTo), queue.ForwardTo); } - if (queue.ForwardDeadLetteredMessagesTo.IsSet) - { - writer.WriteString(nameof(ForwardDeadLetteredMessagesTo), queue.ForwardDeadLetteredMessagesTo.Value); - } - if (queue.ForwardTo.IsSet) - { - writer.WriteString(nameof(ForwardTo), queue.ForwardTo.Value); - } - if (queue.LockDuration.IsSet) + if (queue.LockDuration.HasValue) { writer.WriteString(nameof(LockDuration), XmlConvert.ToString(queue.LockDuration.Value)); } - if (queue.MaxDeliveryCount.IsSet) + if (queue.MaxDeliveryCount.HasValue) { writer.WriteNumber(nameof(MaxDeliveryCount), queue.MaxDeliveryCount.Value); } - if (queue.MaxMessageSizeInKilobytes.IsSet) - { - writer.WriteNumber(nameof(MaxMessageSizeInKilobytes), queue.MaxMessageSizeInKilobytes.Value); - } - if (queue.MaxSizeInMegabytes.IsSet) - { - writer.WriteNumber(nameof(MaxSizeInMegabytes), queue.MaxSizeInMegabytes.Value); - } - if (queue.RequiresDuplicateDetection.IsSet) + if (queue.RequiresDuplicateDetection.HasValue) { writer.WriteBoolean(nameof(RequiresDuplicateDetection), queue.RequiresDuplicateDetection.Value); } - if (queue.RequiresSession.IsSet) + if (queue.RequiresSession.HasValue) { writer.WriteBoolean(nameof(RequiresSession), queue.RequiresSession.Value); } - if (queue.Status.IsSet) - { - writer.WriteString(nameof(Status), queue.Status.Value.ToString()); - } writer.WriteEndObject(); } } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs index 41c9976d79..929ba2dbed 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs @@ -3,25 +3,27 @@ using System.Text.Json; -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; +namespace Aspire.Hosting.Azure.ServiceBus; /// /// Represents a Service Bus Rule. /// +/// +/// List of properties from the CDK that are not exposed here: +/// - Action +/// - SqlFilter +/// +/// Use to configure these specific properties. +/// public class ServiceBusRule { - private readonly OptionalValue _name = new(); - private readonly OptionalValue _action = new(); - private readonly OptionalValue _correlationFilter = new(); - private readonly OptionalValue _filterType = new(); - private readonly OptionalValue _sqlFilter = new(); - /// /// Initializes a new instance of the class. /// - public ServiceBusRule(string id) + public ServiceBusRule(string id, string name) { Id = id; + Name = name; } /// @@ -32,48 +34,17 @@ public ServiceBusRule(string id) /// /// The rule name. /// - public OptionalValue Name - { - get { return _name; } - set { _name.Assign(value); } - } - - /// - /// Represents the filter actions which are allowed for the transformation - /// of a message that have been matched by a filter expression. - /// - public OptionalValue Action - { - get { return _action; } - set { _action.Assign(value); } - } + public string Name { get; set; } /// - /// Properties of correlationFilter. + /// Properties of correlation filter. /// - public OptionalValue CorrelationFilter - { - get { return _correlationFilter; } - set { _correlationFilter.Assign(value); } - } + public ServiceBusCorrelationFilter CorrelationFilter { get; set; } = new(); /// /// Filter type that is evaluated against a BrokeredMessage. /// - public OptionalValue FilterType - { - get { return _filterType; } - set { _filterType.Assign(value); } - } - - /// - /// Properties of sqlFilter. - /// - public OptionalValue SqlFilter - { - get { return _sqlFilter; } - set { _sqlFilter.Assign(value); } - } + public ServiceBusFilterType FilterType { get; set; } = ServiceBusFilterType.CorrelationFilter; /// /// Converts the current instance to a provisioning entity. @@ -83,105 +54,63 @@ public OptionalValue SqlFilter { var rule = new global::Azure.Provisioning.ServiceBus.ServiceBusRule(Id); - if (Name.IsSet && Name.Value != null) + if (Name != null) { - rule.Name = Name.Value; - } - - if (Action.IsSet && Action.Value != null) - { - rule.Action = new(); - - if (Action.Value.SqlExpression.IsSet && Action.Value.SqlExpression.Value != null) - { - rule.Action.SqlExpression = Action.Value.SqlExpression.Value; - } - if (Action.Value.CompatibilityLevel.IsSet) - { - rule.Action.CompatibilityLevel = Action.Value.CompatibilityLevel.Value; - } - if (Action.Value.RequiresPreprocessing.IsSet) - { - rule.Action.RequiresPreprocessing = Action.Value.RequiresPreprocessing.Value; - } + rule.Name = Name; } - if (CorrelationFilter.IsSet && CorrelationFilter.Value != null) + if (CorrelationFilter != null) { rule.CorrelationFilter = new(); - if (CorrelationFilter.Value.ApplicationProperties.IsSet && CorrelationFilter.Value.ApplicationProperties.Value != null) + foreach (var property in CorrelationFilter.Properties) { - foreach (var property in CorrelationFilter.Value.ApplicationProperties.Value) - { - rule.CorrelationFilter.ApplicationProperties[property.Key] = property.Value; - } + rule.CorrelationFilter.ApplicationProperties[property.Key] = property.Value; } - if (CorrelationFilter.Value.CorrelationId.IsSet && CorrelationFilter.Value.CorrelationId.Value != null) + if (CorrelationFilter.CorrelationId != null) { - rule.CorrelationFilter.CorrelationId = CorrelationFilter.Value.CorrelationId.Value; + rule.CorrelationFilter.CorrelationId = CorrelationFilter.CorrelationId; } - if (CorrelationFilter.Value.MessageId.IsSet && CorrelationFilter.Value.MessageId.Value != null) + if (CorrelationFilter.MessageId != null) { - rule.CorrelationFilter.MessageId = CorrelationFilter.Value.MessageId.Value; + rule.CorrelationFilter.MessageId = CorrelationFilter.MessageId; } - if (CorrelationFilter.Value.SendTo.IsSet && CorrelationFilter.Value.SendTo.Value != null) + if (CorrelationFilter.SendTo != null) { - rule.CorrelationFilter.SendTo = CorrelationFilter.Value.SendTo.Value; + rule.CorrelationFilter.SendTo = CorrelationFilter.SendTo; } - if (CorrelationFilter.Value.ReplyTo.IsSet && CorrelationFilter.Value.ReplyTo.Value != null) + if (CorrelationFilter.ReplyTo != null) { - rule.CorrelationFilter.ReplyTo = CorrelationFilter.Value.ReplyTo.Value; + rule.CorrelationFilter.ReplyTo = CorrelationFilter.ReplyTo; } - if (CorrelationFilter.Value.Subject.IsSet && CorrelationFilter.Value.Subject.Value != null) + if (CorrelationFilter.Subject != null) { - rule.CorrelationFilter.Subject = CorrelationFilter.Value.Subject.Value; + rule.CorrelationFilter.Subject = CorrelationFilter.Subject; } - if (CorrelationFilter.Value.SessionId.IsSet && CorrelationFilter.Value.SessionId.Value != null) + if (CorrelationFilter.SessionId != null) { - rule.CorrelationFilter.SessionId = CorrelationFilter.Value.SessionId.Value; + rule.CorrelationFilter.SessionId = CorrelationFilter.SessionId; } - if (CorrelationFilter.Value.ReplyToSessionId.IsSet && CorrelationFilter.Value.ReplyToSessionId.Value != null) + if (CorrelationFilter.ReplyToSessionId != null) { - rule.CorrelationFilter.ReplyToSessionId = CorrelationFilter.Value.ReplyToSessionId.Value; + rule.CorrelationFilter.ReplyToSessionId = CorrelationFilter.ReplyToSessionId; } - if (CorrelationFilter.Value.ContentType.IsSet && CorrelationFilter.Value.ContentType.Value != null) + if (CorrelationFilter.ContentType != null) { - rule.CorrelationFilter.ContentType = CorrelationFilter.Value.ContentType.Value; + rule.CorrelationFilter.ContentType = CorrelationFilter.ContentType; } - if (CorrelationFilter.Value.RequiresPreprocessing.IsSet) + if (CorrelationFilter.RequiresPreprocessing.HasValue) { - rule.CorrelationFilter.RequiresPreprocessing = CorrelationFilter.Value.RequiresPreprocessing.Value; + rule.CorrelationFilter.RequiresPreprocessing = CorrelationFilter.RequiresPreprocessing.Value; } } - if (FilterType.IsSet) - { - rule.FilterType = FilterType.Value switch - { - ServiceBusFilterType.SqlFilter => global::Azure.Provisioning.ServiceBus.ServiceBusFilterType.SqlFilter, - ServiceBusFilterType.CorrelationFilter => global::Azure.Provisioning.ServiceBus.ServiceBusFilterType.CorrelationFilter, - _ => throw new NotImplementedException() - }; - } - - if (SqlFilter.IsSet && SqlFilter.Value != null) + rule.FilterType = FilterType switch { - rule.SqlFilter = new(); - - if (SqlFilter.Value.SqlExpression.IsSet && SqlFilter.Value.SqlExpression.Value != null) - { - rule.SqlFilter.SqlExpression = SqlFilter.Value.SqlExpression.Value; - } - if (SqlFilter.Value.CompatibilityLevel.IsSet) - { - rule.SqlFilter.CompatibilityLevel = SqlFilter.Value.CompatibilityLevel.Value; - } - if (SqlFilter.Value.RequiresPreprocessing.IsSet) - { - rule.SqlFilter.RequiresPreprocessing = SqlFilter.Value.RequiresPreprocessing.Value; - } - } + ServiceBusFilterType.SqlFilter => global::Azure.Provisioning.ServiceBus.ServiceBusFilterType.SqlFilter, + ServiceBusFilterType.CorrelationFilter => global::Azure.Provisioning.ServiceBus.ServiceBusFilterType.CorrelationFilter, + _ => throw new NotImplementedException() + }; return rule; } @@ -194,109 +123,67 @@ public void WriteJsonObjectProperties(Utf8JsonWriter writer) { var rule = this; - if (rule.Name.IsSet) + if (rule.Name != null) { - writer.WriteString(nameof(ServiceBusQueue.Name), rule.Name.Value); + writer.WriteString(nameof(ServiceBusQueue.Name), rule.Name); } writer.WriteStartObject("Properties"); - if (rule.Action.IsSet && rule.Action.Value != null) + writer.WriteString(nameof(FilterType), rule.FilterType switch { - writer.WriteStartObject(nameof(Action)); + ServiceBusFilterType.SqlFilter => "Sql", + ServiceBusFilterType.CorrelationFilter => "Correlation", + _ => throw new NotImplementedException() + }); - if (rule.Action.Value.SqlExpression.IsSet) - { - writer.WriteString(nameof(ServiceBusFilterAction.SqlExpression), rule.Action.Value.SqlExpression.Value); - } - if (rule.Action.Value.CompatibilityLevel.IsSet) - { - writer.WriteNumber(nameof(ServiceBusFilterAction.CompatibilityLevel), rule.Action.Value.CompatibilityLevel.Value); - } - if (rule.Action.Value.RequiresPreprocessing.IsSet) - { - writer.WriteBoolean(nameof(ServiceBusFilterAction.RequiresPreprocessing), rule.Action.Value.RequiresPreprocessing.Value); - } - writer.WriteEndObject(); - } + writer.WriteStartObject(nameof(CorrelationFilter)); - if (rule.CorrelationFilter.IsSet && rule.CorrelationFilter.Value != null) + if (rule.CorrelationFilter.Properties.Count != 0) { - writer.WriteStartObject(nameof(CorrelationFilter)); + writer.WritePropertyName("Properties"); - if (rule.CorrelationFilter.Value.ApplicationProperties.IsSet && rule.CorrelationFilter.Value.ApplicationProperties != null) - { - JsonSerializer.Serialize(writer, rule.CorrelationFilter.Value.ApplicationProperties.Value); - } - if (rule.CorrelationFilter.Value.CorrelationId.IsSet) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.CorrelationId), rule.CorrelationFilter.Value.CorrelationId.Value); - } - if (rule.CorrelationFilter.Value.MessageId.IsSet) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.MessageId), rule.CorrelationFilter.Value.MessageId.Value); - } - if (rule.CorrelationFilter.Value.SendTo.IsSet) - { - writer.WriteString("To", rule.CorrelationFilter.Value.SendTo.Value); - } - if (rule.CorrelationFilter.Value.ReplyTo.IsSet) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyTo), rule.CorrelationFilter.Value.ReplyTo.Value); - } - if (rule.CorrelationFilter.Value.Subject.IsSet) - { - writer.WriteString("Label", rule.CorrelationFilter.Value.Subject.Value); - } - if (rule.CorrelationFilter.Value.SessionId.IsSet) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.SessionId), rule.CorrelationFilter.Value.SessionId.Value); - } - if (rule.CorrelationFilter.Value.ReplyToSessionId.IsSet) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyToSessionId), rule.CorrelationFilter.Value.ReplyToSessionId.Value); - } - if (rule.CorrelationFilter.Value.ContentType.IsSet) - { - writer.WriteString(nameof(ServiceBusCorrelationFilter.ContentType), rule.CorrelationFilter.Value.ContentType.Value); - } - if (rule.CorrelationFilter.Value.RequiresPreprocessing.IsSet) - { - writer.WriteBoolean(nameof(ServiceBusCorrelationFilter.RequiresPreprocessing), rule.CorrelationFilter.Value.RequiresPreprocessing.Value); - } - - writer.WriteEndObject(); + JsonSerializer.Serialize(writer, rule.CorrelationFilter.Properties); } - - if (rule.FilterType.IsSet) + if (rule.CorrelationFilter.CorrelationId != null) { - writer.WriteString(nameof(FilterType), rule.FilterType.Value switch - { - ServiceBusFilterType.SqlFilter => "Sql", - ServiceBusFilterType.CorrelationFilter => "Correlation", - _ => throw new NotImplementedException() - }); + writer.WriteString(nameof(ServiceBusCorrelationFilter.CorrelationId), rule.CorrelationFilter.CorrelationId); } - - if (rule.SqlFilter.IsSet && rule.SqlFilter.Value != null) + if (rule.CorrelationFilter.MessageId != null) { - writer.WriteStartObject(nameof(SqlFilter)); - - if (rule.SqlFilter.Value.SqlExpression.IsSet) - { - writer.WriteString(nameof(ServiceBusSqlFilter.SqlExpression), rule.SqlFilter.Value.SqlExpression.Value); - } - if (rule.SqlFilter.Value.CompatibilityLevel.IsSet) - { - writer.WriteNumber(nameof(ServiceBusSqlFilter.CompatibilityLevel), rule.SqlFilter.Value.CompatibilityLevel.Value); - } - if (rule.SqlFilter.Value.RequiresPreprocessing.IsSet) - { - writer.WriteBoolean(nameof(ServiceBusSqlFilter.RequiresPreprocessing), rule.SqlFilter.Value.RequiresPreprocessing.Value); - } - writer.WriteEndObject(); + writer.WriteString(nameof(ServiceBusCorrelationFilter.MessageId), rule.CorrelationFilter.MessageId); + } + if (rule.CorrelationFilter.SendTo != null) + { + writer.WriteString("To", rule.CorrelationFilter.SendTo); + } + if (rule.CorrelationFilter.ReplyTo != null) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyTo), rule.CorrelationFilter.ReplyTo); } + if (rule.CorrelationFilter.Subject != null) + { + writer.WriteString("Label", rule.CorrelationFilter.Subject); + } + if (rule.CorrelationFilter.SessionId != null) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.SessionId), rule.CorrelationFilter.SessionId); + } + if (rule.CorrelationFilter.ReplyToSessionId != null) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ReplyToSessionId), rule.CorrelationFilter.ReplyToSessionId); + } + if (rule.CorrelationFilter.ContentType != null) + { + writer.WriteString(nameof(ServiceBusCorrelationFilter.ContentType), rule.CorrelationFilter.ContentType); + } + if (rule.CorrelationFilter.RequiresPreprocessing.HasValue) + { + writer.WriteBoolean(nameof(ServiceBusCorrelationFilter.RequiresPreprocessing), rule.CorrelationFilter.RequiresPreprocessing.Value); + } + + writer.WriteEndObject(); // CorrelationFilter - writer.WriteEndObject(); + writer.WriteEndObject(); // Properties } } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs deleted file mode 100644 index a27f500911..0000000000 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSqlFilter.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; - -/// -/// Represents a filter which is a composition of an expression and an action -/// that is executed in the pub/sub pipeline. -/// -public class ServiceBusSqlFilter -{ - private readonly OptionalValue _sqlExpression = new(); - private readonly OptionalValue _compatibilityLevel = new(); - private readonly OptionalValue _requiresPreprocessing = new(); - - /// - /// Creates a new ServiceBusSqlFilter. - /// - public ServiceBusSqlFilter() - { - } - - /// - /// The SQL expression. e.g. MyProperty='ABC'. - /// - public OptionalValue SqlExpression - { - get { return _sqlExpression; } - set { _sqlExpression.Assign(value); } - } - - /// - /// This property is reserved for future use. An integer value showing the - /// compatibility level, currently hard-coded to 20. - /// - public OptionalValue CompatibilityLevel - { - get { return _compatibilityLevel; } - set { _compatibilityLevel.Assign(value); } - } - - /// - /// Value that indicates whether the rule action requires preprocessing. - /// - public OptionalValue RequiresPreprocessing - { - get { return _requiresPreprocessing; } - set { _requiresPreprocessing.Assign(value); } - } -} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs index e6fc5a324b..b31b786a24 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusSubscription.cs @@ -4,36 +4,33 @@ using System.Text.Json; using System.Xml; -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; +namespace Aspire.Hosting.Azure.ServiceBus; /// /// Represents a Service Bus Subscription. /// +/// +/// List of properties from the CDK that are not exposed here: +/// - AutoDeleteOnIdle +/// - ClientAffineProperties +/// - DeadLetteringOnFilterEvaluationExceptions +/// - DuplicateDetectionHistoryTimeWindow +/// - EnableBatchedOperations +/// - IsClientAffine +/// - MaxMessageSizeInKilobytes +/// - Status +/// +/// Use to configure these specific properties. +/// public class ServiceBusSubscription { - private readonly OptionalValue _name = new(); - private readonly OptionalValue _autoDeleteOnIdle = new(); - private readonly OptionalValue _deadLetteringOnFilterEvaluationExceptions = new(); - private readonly OptionalValue _deadLetteringOnMessageExpiration = new(); - private readonly OptionalValue _defaultMessageTimeToLive = new(); - private readonly OptionalValue _duplicateDetectionHistoryTimeWindow = new(); - private readonly OptionalValue _enableBatchedOperations = new(); - private readonly OptionalValue _forwardDeadLetteredMessagesTo = new(); - private readonly OptionalValue _forwardTo = new(); - private readonly OptionalValue _isClientAffine = new(); - private readonly OptionalValue _lockDuration = new(); - private readonly OptionalValue _maxDeliveryCount = new(); - private readonly OptionalValue _maxMessageSizeInKilobytes = new(); - private readonly OptionalValue _requiresSession = new(); - private readonly OptionalValue _status = new(); - private readonly OptionalValue _clientAffineProperties = new(); - /// /// Initializes a new instance of the class. /// - public ServiceBusSubscription(string id) + public ServiceBusSubscription(string id, string name) { Id = id; + Name = name; } /// @@ -44,50 +41,13 @@ public ServiceBusSubscription(string id) /// /// The subscription name. /// - public OptionalValue Name - { - get { return _name; } - set { _name.Assign(value); } - } - - /// - /// ISO 8061 timeSpan idle interval after which the queue is automatically - /// deleted. The minimum duration is 5 minutes. - /// - public OptionalValue AutoDeleteOnIdle - { - get { return _autoDeleteOnIdle; } - set { _autoDeleteOnIdle.Assign(value); } - } - - /// - /// Properties specific to client affine subscriptions. - /// - public OptionalValue ClientAffineProperties - { - get { return _clientAffineProperties; } - set { _clientAffineProperties.Assign(value); } - } - - /// - /// Value that indicates whether a subscription has dead letter support on - /// filter evaluation exceptions. - /// - public OptionalValue DeadLetteringOnFilterEvaluationExceptions - { - get { return _deadLetteringOnFilterEvaluationExceptions!; } - set { _deadLetteringOnFilterEvaluationExceptions.Assign(value); } - } + public string Name { get; set; } /// /// A value that indicates whether this queue has dead letter support when /// a message expires. /// - public OptionalValue DeadLetteringOnMessageExpiration - { - get { return _deadLetteringOnMessageExpiration; } - set { _deadLetteringOnMessageExpiration.Assign(value); } - } + public bool? DeadLetteringOnMessageExpiration { get; set; } /// /// ISO 8601 default message timespan to live value. This is the duration @@ -95,108 +55,36 @@ public OptionalValue DeadLetteringOnMessageExpiration /// sent to Service Bus. This is the default value used when TimeToLive is /// not set on a message itself. /// - public OptionalValue DefaultMessageTimeToLive - { - get { return _defaultMessageTimeToLive; } - set { _defaultMessageTimeToLive.Assign(value); } - } - - /// - /// ISO 8601 timeSpan structure that defines the duration of the duplicate - /// detection history. The default value is 10 minutes. - /// - public OptionalValue DuplicateDetectionHistoryTimeWindow - { - get { return _duplicateDetectionHistoryTimeWindow; } - set { _duplicateDetectionHistoryTimeWindow.Assign(value); } - } - - /// - /// Value that indicates whether server-side batched operations are enabled. - /// - public OptionalValue EnableBatchedOperations - { - get { return _enableBatchedOperations; } - set { _enableBatchedOperations.Assign(value); } - } + public TimeSpan? DefaultMessageTimeToLive { get; set; } /// /// Queue/Topic name to forward the Dead Letter message. /// - public OptionalValue ForwardDeadLetteredMessagesTo - { - get { return _forwardDeadLetteredMessagesTo; } - set { _forwardDeadLetteredMessagesTo.Assign(value); } - } + public string? ForwardDeadLetteredMessagesTo { get; set; } /// /// Queue/Topic name to forward the messages. /// - public OptionalValue ForwardTo - { - get { return _forwardTo; } - set { _forwardTo.Assign(value); } - } - - /// - /// Value that indicates whether the subscription has an affinity to the - /// client id. - /// - public OptionalValue IsClientAffine - { - get { return _isClientAffine; } - set { _isClientAffine.Assign(value); } - } + public string? ForwardTo { get; set; } /// /// ISO 8601 timespan duration of a peek-lock; that is, the amount of time /// that the message is locked for other receivers. The maximum value for /// LockDuration is 5 minutes; the default value is 1 minute. /// - public OptionalValue LockDuration - { - get { return _lockDuration; } - set { _lockDuration.Assign(value); } - } + public TimeSpan? LockDuration { get; set; } /// /// The maximum delivery count. A message is automatically deadlettered /// after this number of deliveries. default value is 10. /// - public OptionalValue MaxDeliveryCount - { - get { return _maxDeliveryCount; } - set { _maxDeliveryCount.Assign(value); } - } - - /// - /// Maximum size (in KB) of the message payload that can be accepted by the - /// queue. This property is only used in Premium today and default is 1024. - /// - public OptionalValue MaxMessageSizeInKilobytes - { - get { return _maxMessageSizeInKilobytes; } - set { _maxMessageSizeInKilobytes.Assign(value); } - } + public int? MaxDeliveryCount { get; set; } /// /// A value that indicates whether the queue supports the concept of /// sessions. /// - public OptionalValue RequiresSession - { - get { return _requiresSession; } - set { _requiresSession.Assign(value); } - } - - /// - /// Enumerates the possible values for the status of a messaging entity. - /// - public OptionalValue Status - { - get { return _status; } - set { _status.Assign(value); } - } + public bool? RequiresSession { get; set; } /// /// Converts the current instance to a provisioning entity. @@ -206,63 +94,39 @@ public OptionalValue Status { var subscription = new global::Azure.Provisioning.ServiceBus.ServiceBusSubscription(Id); - if (Name.IsSet && Name.Value != null) + if (Name != null) { - subscription.Name = Name.Value; + subscription.Name = Name; } - if (AutoDeleteOnIdle.IsSet) - { - subscription.AutoDeleteOnIdle = AutoDeleteOnIdle.Value; - } - if (DeadLetteringOnFilterEvaluationExceptions.IsSet) - { - subscription.DeadLetteringOnFilterEvaluationExceptions = DeadLetteringOnFilterEvaluationExceptions.Value; - } - if (DeadLetteringOnMessageExpiration.IsSet) + if (DeadLetteringOnMessageExpiration.HasValue) { subscription.DeadLetteringOnMessageExpiration = DeadLetteringOnMessageExpiration.Value; } - if (DefaultMessageTimeToLive.IsSet) + if (DefaultMessageTimeToLive.HasValue) { subscription.DefaultMessageTimeToLive = DefaultMessageTimeToLive.Value; } - if (DuplicateDetectionHistoryTimeWindow.IsSet) - { - subscription.DuplicateDetectionHistoryTimeWindow = DuplicateDetectionHistoryTimeWindow.Value; - } - if (EnableBatchedOperations.IsSet) - { - subscription.EnableBatchedOperations = EnableBatchedOperations.Value; - } - if (ForwardDeadLetteredMessagesTo.IsSet && ForwardDeadLetteredMessagesTo.Value != null) + if (ForwardDeadLetteredMessagesTo != null) { - subscription.ForwardDeadLetteredMessagesTo = ForwardDeadLetteredMessagesTo.Value; + subscription.ForwardDeadLetteredMessagesTo = ForwardDeadLetteredMessagesTo; } - if (ForwardTo.IsSet && ForwardTo.Value != null) + if (ForwardTo != null) { - subscription.ForwardTo = ForwardTo.Value; + subscription.ForwardTo = ForwardTo; } - if (IsClientAffine.IsSet) - { - subscription.IsClientAffine = IsClientAffine.Value; - } - if (LockDuration.IsSet) + if (LockDuration.HasValue) { subscription.LockDuration = LockDuration.Value; } - if (MaxDeliveryCount.IsSet) + if (MaxDeliveryCount.HasValue) { subscription.MaxDeliveryCount = MaxDeliveryCount.Value; } - if (RequiresSession.IsSet) + if (RequiresSession.HasValue) { subscription.RequiresSession = RequiresSession.Value; } - if (Status.IsSet) - { - subscription.Status = Enum.Parse(Status.Value.ToString()); - } return subscription; } @@ -274,85 +138,41 @@ public void WriteJsonObjectProperties(Utf8JsonWriter writer) { var subscription = this; - if (subscription.Name.IsSet) + if (subscription.Name != null) { - writer.WriteString(nameof(ServiceBusQueue.Name), subscription.Name.Value); + writer.WriteString(nameof(ServiceBusQueue.Name), subscription.Name); } writer.WriteStartObject("Properties"); - if (subscription.AutoDeleteOnIdle.IsSet) - { - writer.WriteString(nameof(ServiceBusSubscription.AutoDeleteOnIdle), XmlConvert.ToString(subscription.AutoDeleteOnIdle.Value)); - } - if (subscription.ClientAffineProperties.IsSet && subscription.ClientAffineProperties.Value != null) - { - writer.WriteStartObject(nameof(subscription.ClientAffineProperties)); - - if (subscription.ClientAffineProperties.Value.ClientId.IsSet) - { - writer.WriteString(nameof(ServiceBusClientAffineProperties.ClientId), subscription.ClientAffineProperties.Value.ClientId.Value); - } - if (subscription.ClientAffineProperties.Value.IsDurable.IsSet) - { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsDurable), subscription.ClientAffineProperties.Value.IsDurable.Value); - } - if (subscription.ClientAffineProperties.Value.IsShared.IsSet) - { - writer.WriteBoolean(nameof(ServiceBusClientAffineProperties.IsShared), subscription.ClientAffineProperties.Value.IsShared.Value); - } - - writer.WriteEndObject(); - } - - if (subscription.DeadLetteringOnFilterEvaluationExceptions.IsSet) - { - writer.WriteBoolean(nameof(DeadLetteringOnFilterEvaluationExceptions), subscription.DeadLetteringOnFilterEvaluationExceptions.Value); - } - if (subscription.DeadLetteringOnMessageExpiration.IsSet) + if (subscription.DeadLetteringOnMessageExpiration.HasValue) { writer.WriteBoolean(nameof(DeadLetteringOnMessageExpiration), subscription.DeadLetteringOnMessageExpiration.Value); } - if (subscription.DefaultMessageTimeToLive.IsSet) + if (subscription.DefaultMessageTimeToLive.HasValue) { writer.WriteString(nameof(DefaultMessageTimeToLive), XmlConvert.ToString(subscription.DefaultMessageTimeToLive.Value)); } - if (subscription.DuplicateDetectionHistoryTimeWindow.IsSet) - { - writer.WriteString(nameof(DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(subscription.DuplicateDetectionHistoryTimeWindow.Value)); - } - if (subscription.EnableBatchedOperations.IsSet) - { - writer.WriteBoolean(nameof(EnableBatchedOperations), subscription.EnableBatchedOperations.Value); - } - if (subscription.ForwardDeadLetteredMessagesTo.IsSet) - { - writer.WriteString(nameof(ForwardDeadLetteredMessagesTo), subscription.ForwardDeadLetteredMessagesTo.Value); - } - if (subscription.ForwardTo.IsSet) + if (subscription.ForwardDeadLetteredMessagesTo != null) { - writer.WriteString(nameof(ForwardTo), subscription.ForwardTo.Value); + writer.WriteString(nameof(ForwardDeadLetteredMessagesTo), subscription.ForwardDeadLetteredMessagesTo); } - if (subscription.IsClientAffine.IsSet) + if (subscription.ForwardTo != null) { - writer.WriteBoolean(nameof(IsClientAffine), subscription.IsClientAffine.Value); + writer.WriteString(nameof(ForwardTo), subscription.ForwardTo); } - if (subscription.LockDuration.IsSet) + if (subscription.LockDuration.HasValue) { writer.WriteString(nameof(LockDuration), XmlConvert.ToString(subscription.LockDuration.Value)); } - if (subscription.MaxDeliveryCount.IsSet) + if (subscription.MaxDeliveryCount.HasValue) { writer.WriteNumber(nameof(MaxDeliveryCount), subscription.MaxDeliveryCount.Value); } - if (subscription.RequiresSession.IsSet) + if (subscription.RequiresSession.HasValue) { writer.WriteBoolean(nameof(RequiresSession), subscription.RequiresSession.Value); } - if (subscription.Status.IsSet) - { - writer.WriteString(nameof(Status), subscription.Status.Value.ToString()); - } writer.WriteEndObject(); } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs index eca3017170..b01869b6c4 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusTopic.cs @@ -4,37 +4,38 @@ using System.Text.Json; using System.Xml; -namespace Aspire.Hosting.Azure.ServiceBus.ApplicationModel; +namespace Aspire.Hosting.Azure.ServiceBus; /// /// Represents a Service Bus Topic. /// +/// +/// List of properties from the CDK that are not exposed here: +/// - AutoDeleteOnIdle +/// - DeadLetteringOnMessageExpiration +/// - EnableBatchedOperations +/// - EnableExpress +/// - EnablePartitioning +/// - ForwardDeadLetteredMessagesTo +/// - ForwardTo +/// - LockDuration +/// - MaxDeliveryCount +/// - MaxMessageSizeInKilobytes +/// - MaxSizeInMegabytes +/// - RequiresSession +/// - Status +/// +/// Use to configure these specific properties. +/// public class ServiceBusTopic { - private readonly OptionalValue _name = new(); - private readonly OptionalValue _autoDeleteOnIdle = new(); - private readonly OptionalValue _deadLetteringOnMessageExpiration = new(); - private readonly OptionalValue _defaultMessageTimeToLive = new(); - private readonly OptionalValue _duplicateDetectionHistoryTimeWindow = new(); - private readonly OptionalValue _enableBatchedOperations = new(); - private readonly OptionalValue _enableExpress = new(); - private readonly OptionalValue _enablePartitioning = new(); - private readonly OptionalValue _forwardDeadLetteredMessagesTo = new(); - private readonly OptionalValue _forwardTo = new(); - private readonly OptionalValue _lockDuration = new(); - private readonly OptionalValue _maxDeliveryCount = new(); - private readonly OptionalValue _maxMessageSizeInKilobytes = new(); - private readonly OptionalValue _maxSizeInMegabytes = new(); - private readonly OptionalValue _requiresDuplicateDetection = new(); - private readonly OptionalValue _requiresSession = new(); - private readonly OptionalValue _status = new(); - /// /// Initializes a new instance of the class. /// - public ServiceBusTopic(string id) + public ServiceBusTopic(string id, string name) { Id = id; + Name = name; } /// @@ -45,31 +46,7 @@ public ServiceBusTopic(string id) /// /// The topic name. /// - public OptionalValue Name - { - get { return _name; } - set { _name.Assign(value); } - } - - /// - /// ISO 8061 timeSpan idle interval after which the queue is automatically - /// deleted. The minimum duration is 5 minutes. - /// - public OptionalValue AutoDeleteOnIdle - { - get { return _autoDeleteOnIdle; } - set { _autoDeleteOnIdle.Assign(value); } - } - - /// - /// A value that indicates whether this queue has dead letter support when - /// a message expires. - /// - public OptionalValue DeadLetteringOnMessageExpiration - { - get { return _deadLetteringOnMessageExpiration; } - set { _deadLetteringOnMessageExpiration.Assign(value); } - } + public string Name { get; set; } /// /// ISO 8601 default message timespan to live value. This is the duration @@ -77,138 +54,18 @@ public OptionalValue DeadLetteringOnMessageExpiration /// sent to Service Bus. This is the default value used when TimeToLive is /// not set on a message itself. /// - public OptionalValue DefaultMessageTimeToLive - { - get { return _defaultMessageTimeToLive; } - set { _defaultMessageTimeToLive.Assign(value); } - } + public TimeSpan? DefaultMessageTimeToLive { get; set; } /// /// ISO 8601 timeSpan structure that defines the duration of the duplicate /// detection history. The default value is 10 minutes. /// - public OptionalValue DuplicateDetectionHistoryTimeWindow - { - get { return _duplicateDetectionHistoryTimeWindow; } - set { _duplicateDetectionHistoryTimeWindow.Assign(value); } - } - - /// - /// Value that indicates whether server-side batched operations are enabled. - /// - public OptionalValue EnableBatchedOperations - { - get { return _enableBatchedOperations; } - set { _enableBatchedOperations.Assign(value); } - } - - /// - /// A value that indicates whether Express Entities are enabled. An express - /// queue holds a message in memory temporarily before writing it to - /// persistent storage. - /// - public OptionalValue EnableExpress - { - get { return _enableExpress; } - set { _enableExpress.Assign(value); } - } - - /// - /// A value that indicates whether the queue is to be partitioned across - /// multiple message brokers. - /// - public OptionalValue EnablePartitioning - { - get { return _enablePartitioning; } - set { _enablePartitioning.Assign(value); } - } - - /// - /// Queue/Topic name to forward the Dead Letter message. - /// - public OptionalValue ForwardDeadLetteredMessagesTo - { - get { return _forwardDeadLetteredMessagesTo; } - set { _forwardDeadLetteredMessagesTo.Assign(value); } - } - - /// - /// Queue/Topic name to forward the messages. - /// - public OptionalValue ForwardTo - { - get { return _forwardTo; } - set { _forwardTo.Assign(value); } - } - - /// - /// ISO 8601 timespan duration of a peek-lock; that is, the amount of time - /// that the message is locked for other receivers. The maximum value for - /// LockDuration is 5 minutes; the default value is 1 minute. - /// - public OptionalValue LockDuration - { - get { return _lockDuration; } - set { _lockDuration.Assign(value); } - } - - /// - /// The maximum delivery count. A message is automatically deadlettered - /// after this number of deliveries. default value is 10. - /// - public OptionalValue MaxDeliveryCount - { - get { return _maxDeliveryCount; } - set { _maxDeliveryCount.Assign(value); } - } - - /// - /// Maximum size (in KB) of the message payload that can be accepted by the - /// queue. This property is only used in Premium today and default is 1024. - /// - public OptionalValue MaxMessageSizeInKilobytes - { - get { return _maxMessageSizeInKilobytes; } - set { _maxMessageSizeInKilobytes.Assign(value); } - } - - /// - /// The maximum size of the queue in megabytes, which is the size of memory - /// allocated for the queue. Default is 1024. - /// - public OptionalValue MaxSizeInMegabytes - { - get { return _maxSizeInMegabytes; } - set { _maxSizeInMegabytes.Assign(value); } - } + public TimeSpan? DuplicateDetectionHistoryTimeWindow { get; set; } /// /// A value indicating if this queue requires duplicate detection. /// - public OptionalValue RequiresDuplicateDetection - { - get { return _requiresDuplicateDetection; } - set { _requiresDuplicateDetection.Assign(value); } - } - - /// - /// A value that indicates whether the queue supports the concept of - /// sessions. - /// - public OptionalValue RequiresSession - { - get { return _requiresSession; } - set { _requiresSession.Assign(value); } - } - - /// - /// Enumerates the possible values for the status of a messaging entity. - /// - public OptionalValue Status - { - get { return _status!; } - set { _status!.Assign(value); } - } + public bool? RequiresDuplicateDetection { get; set; } /// /// Converts the current instance to a provisioning entity. @@ -218,47 +75,23 @@ public OptionalValue Status { var topic = new global::Azure.Provisioning.ServiceBus.ServiceBusTopic(Id); - if (Name.IsSet && Name.Value != null) + if (Name != null) { - topic.Name = Name.Value; + topic.Name = Name; } - if (AutoDeleteOnIdle.IsSet) - { - topic.AutoDeleteOnIdle = AutoDeleteOnIdle.Value; - } - if (DefaultMessageTimeToLive.IsSet) + if (DefaultMessageTimeToLive.HasValue) { topic.DefaultMessageTimeToLive = DefaultMessageTimeToLive.Value; } - if (DuplicateDetectionHistoryTimeWindow.IsSet) + if (DuplicateDetectionHistoryTimeWindow.HasValue) { topic.DuplicateDetectionHistoryTimeWindow = DuplicateDetectionHistoryTimeWindow.Value; } - if (EnableBatchedOperations.IsSet) - { - topic.EnableBatchedOperations = EnableBatchedOperations.Value; - } - if (EnableExpress.IsSet) - { - topic.EnableExpress = EnableExpress.Value; - } - if (EnablePartitioning.IsSet) - { - topic.EnablePartitioning = EnablePartitioning.Value; - } - if (MaxMessageSizeInKilobytes.IsSet) - { - topic.MaxSizeInMegabytes = MaxSizeInMegabytes.Value; - } - if (RequiresDuplicateDetection.IsSet) + if (RequiresDuplicateDetection.HasValue) { topic.RequiresDuplicateDetection = RequiresDuplicateDetection.Value; } - if (Status.IsSet) - { - topic.Status = Enum.Parse(Status.Value.ToString()); - } return topic; } @@ -270,52 +103,24 @@ public void WriteJsonObjectProperties(Utf8JsonWriter writer) { var topic = this; - if (topic.Name.IsSet) + if (topic.Name != null) { - writer.WriteString(nameof(Name), topic.Name.Value); + writer.WriteString(nameof(Name), topic.Name); } writer.WriteStartObject("Properties"); - if (topic.AutoDeleteOnIdle.IsSet) - { - writer.WriteString(nameof(AutoDeleteOnIdle), XmlConvert.ToString(topic.AutoDeleteOnIdle.Value)); - } - if (topic.DefaultMessageTimeToLive.IsSet) + if (topic.DefaultMessageTimeToLive.HasValue) { writer.WriteString(nameof(DefaultMessageTimeToLive), XmlConvert.ToString(topic.DefaultMessageTimeToLive.Value)); } - if (topic.DuplicateDetectionHistoryTimeWindow.IsSet) + if (topic.DuplicateDetectionHistoryTimeWindow.HasValue) { writer.WriteString(nameof(DuplicateDetectionHistoryTimeWindow), XmlConvert.ToString(topic.DuplicateDetectionHistoryTimeWindow.Value)); } - if (topic.EnableBatchedOperations.IsSet) - { - writer.WriteBoolean(nameof(EnableBatchedOperations), topic.EnableBatchedOperations.Value); - } - if (topic.EnableExpress.IsSet) - { - writer.WriteBoolean(nameof(EnableExpress), topic.EnableExpress.Value); - } - if (topic.EnablePartitioning.IsSet) - { - writer.WriteBoolean(nameof(EnablePartitioning), topic.EnablePartitioning.Value); - } - if (topic.MaxMessageSizeInKilobytes.IsSet) - { - writer.WriteNumber(nameof(MaxMessageSizeInKilobytes), topic.MaxMessageSizeInKilobytes.Value); - } - if (topic.MaxSizeInMegabytes.IsSet) - { - writer.WriteNumber(nameof(MaxSizeInMegabytes), topic.MaxSizeInMegabytes.Value); - } - if (topic.RequiresDuplicateDetection.IsSet) + if (topic.RequiresDuplicateDetection.HasValue) { writer.WriteBoolean(nameof(RequiresDuplicateDetection), topic.RequiresDuplicateDetection.Value); } - if (topic.Status.IsSet) - { - writer.WriteString(nameof(Status), topic.Status.Value.ToString()); - } writer.WriteEndObject(); } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index 3acde8d01e..1cd8edc5db 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; -using Aspire.Hosting.Azure.ServiceBus.ApplicationModel; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Azure; using Aspire.Hosting.Azure.ServiceBus; @@ -110,14 +109,14 @@ public static IResourceBuilder AddAzureServiceBus(this public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, string[] subscriptions, Action? configure = null) { var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(name); - var topic = new ServiceBusTopic(normalizedTopicName) { Name = name }; + var topic = new ServiceBusTopic(normalizedTopicName, name); configure?.Invoke(topic); builder.Resource.Topics.Add(topic); foreach (var subscriptionName in subscriptions) { - var subscription = new ServiceBusSubscription(Infrastructure.NormalizeBicepIdentifier(subscriptionName)) { Name = subscriptionName }; + var subscription = new ServiceBusSubscription(Infrastructure.NormalizeBicepIdentifier(subscriptionName), subscriptionName); builder.Resource.Subscriptions.Add((normalizedTopicName, subscription)); } return builder; @@ -131,7 +130,7 @@ public static IResourceBuilder AddTopic(this IResourceB /// An optional method that can be used for customizing the . public static IResourceBuilder AddQueue(this IResourceBuilder builder, [ResourceName] string name, Action? configure = null) { - var queue = new ServiceBusQueue(Infrastructure.NormalizeBicepIdentifier(name)) { Name = name }; + var queue = new ServiceBusQueue(Infrastructure.NormalizeBicepIdentifier(name), name); configure?.Invoke(queue); @@ -146,7 +145,7 @@ public static IResourceBuilder AddQueue(this IResourceB /// The name of the topic. public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name) { - var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name)) { Name = name }; + var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name), name); builder.Resource.Topics.Add(topic); return builder; @@ -160,7 +159,7 @@ public static IResourceBuilder AddTopic(this IResourceB /// An optional method that can be used for customizing the . public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, Action configure) { - var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name)) { Name = name }; + var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name), name); configure?.Invoke(topic); builder.Resource.Topics.Add(topic); @@ -179,7 +178,7 @@ public static IResourceBuilder AddSubscription(this IRe var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(topicName); var normalizedSubscriptionName = Infrastructure.NormalizeBicepIdentifier(subscriptionName); - var subscription = new ServiceBusSubscription(normalizedSubscriptionName) { Name = subscriptionName }; + var subscription = new ServiceBusSubscription(normalizedSubscriptionName, subscriptionName); configure?.Invoke(subscription); builder.Resource.Subscriptions.Add((normalizedTopicName, subscription)); return builder; @@ -199,7 +198,7 @@ public static IResourceBuilder AddRule(this IResourceBu var normalizedSubscriptionName = Infrastructure.NormalizeBicepIdentifier(subscriptionName); var normalizedRuleName = Infrastructure.NormalizeBicepIdentifier(ruleName); - var rule = new ServiceBusRule(normalizedRuleName) { Name = ruleName }; + var rule = new ServiceBusRule(normalizedRuleName, ruleName); configure?.Invoke(rule); builder.Resource.Rules.Add((normalizedTopicName, normalizedSubscriptionName, rule)); @@ -306,7 +305,7 @@ public static IResourceBuilder RunAsEmulator(this IReso return connectionString ?? throw new InvalidOperationException("ServiceBusClient is not initialized."); }, queueNameFactory: sp => { - var queueName = builder.Resource.Queues[0].Name.Value?.ToString(); + var queueName = builder.Resource.Queues[0].Name; return queueName ?? throw new InvalidOperationException("Queue name is not initialized."); }, name: healthCheckKey); diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs index a1541aec18..4f914427ba 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusResource.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using Aspire.Hosting.ApplicationModel; -using Aspire.Hosting.Azure.ServiceBus.ApplicationModel; +using Aspire.Hosting.Azure.ServiceBus; namespace Aspire.Hosting.Azure; diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index 1de8924c19..49924a1668 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -8,209 +8,108 @@ Aspire.Hosting.Azure.AzureServiceBusEmulatorResource Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.AzureServiceBusEmulatorResource(Aspire.Hosting.Azure.AzureServiceBusResource! innerResource) -> void Aspire.Hosting.Azure.AzureServiceBusResource.AzureServiceBusResource(string! name, System.Action! configureInfrastructure) -> void Aspire.Hosting.Azure.AzureServiceBusResource.IsEmulator.get -> bool -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.IsSet.get -> bool -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.OptionalValue() -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.OptionalValue(T value) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.Value.get -> T? -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.ClientId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.ClientId.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsDurable.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsDurable.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsShared.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.IsShared.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusClientAffineProperties.ServiceBusClientAffineProperties() -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ApplicationProperties.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue!>! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ApplicationProperties.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ContentType.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ContentType.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.CorrelationId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.CorrelationId.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.MessageId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.MessageId.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyToSessionId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ReplyToSessionId.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.RequiresPreprocessing.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.RequiresPreprocessing.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SendTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SendTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.ServiceBusCorrelationFilter() -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SessionId.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.SessionId.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.Subject.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusCorrelationFilter.Subject.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.CompatibilityLevel.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.CompatibilityLevel.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.RequiresPreprocessing.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.RequiresPreprocessing.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.ServiceBusFilterAction() -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.SqlExpression.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterAction.SqlExpression.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType.CorrelationFilter = 1 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType.SqlFilter = 0 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusFilterType -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Active = 1 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Creating = 6 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Deleting = 7 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Disabled = 2 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.ReceiveDisabled = 5 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Renaming = 8 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Restoring = 3 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.SendDisabled = 4 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus.Unknown = 0 -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusMessagingEntityStatus -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.AutoDeleteOnIdle.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.AutoDeleteOnIdle.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DeadLetteringOnMessageExpiration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DeadLetteringOnMessageExpiration.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DefaultMessageTimeToLive.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DefaultMessageTimeToLive.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DuplicateDetectionHistoryTimeWindow.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.DuplicateDetectionHistoryTimeWindow.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableBatchedOperations.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableBatchedOperations.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableExpress.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnableExpress.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnablePartitioning.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.EnablePartitioning.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardDeadLetteredMessagesTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardDeadLetteredMessagesTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ForwardTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Id.get -> string! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.LockDuration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.LockDuration.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxDeliveryCount.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxDeliveryCount.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxMessageSizeInKilobytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxMessageSizeInKilobytes.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxSizeInMegabytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.MaxSizeInMegabytes.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Name.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresDuplicateDetection.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresDuplicateDetection.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresSession.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.RequiresSession.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ServiceBusQueue(string! id) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Status.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.Status.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusQueue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusQueue.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Action.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Action.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.CorrelationFilter.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.CorrelationFilter.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.FilterType.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.FilterType.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Id.get -> string! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.Name.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.ServiceBusRule(string! id) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.SqlFilter.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.SqlFilter.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusRule! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusRule.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.CompatibilityLevel.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.CompatibilityLevel.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.RequiresPreprocessing.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.RequiresPreprocessing.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.ServiceBusSqlFilter() -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.SqlExpression.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSqlFilter.SqlExpression.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.AutoDeleteOnIdle.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.AutoDeleteOnIdle.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ClientAffineProperties.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ClientAffineProperties.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnFilterEvaluationExceptions.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnMessageExpiration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DeadLetteringOnMessageExpiration.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DefaultMessageTimeToLive.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DefaultMessageTimeToLive.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.DuplicateDetectionHistoryTimeWindow.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.EnableBatchedOperations.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.EnableBatchedOperations.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardDeadLetteredMessagesTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardDeadLetteredMessagesTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ForwardTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Id.get -> string! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.IsClientAffine.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.IsClientAffine.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.LockDuration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.LockDuration.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxDeliveryCount.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxDeliveryCount.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxMessageSizeInKilobytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.MaxMessageSizeInKilobytes.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Name.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.RequiresSession.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.RequiresSession.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ServiceBusSubscription(string! id) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Status.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.Status.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusSubscription! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusSubscription.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.AutoDeleteOnIdle.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.AutoDeleteOnIdle.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DeadLetteringOnMessageExpiration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DeadLetteringOnMessageExpiration.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DefaultMessageTimeToLive.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DefaultMessageTimeToLive.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DuplicateDetectionHistoryTimeWindow.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.DuplicateDetectionHistoryTimeWindow.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableBatchedOperations.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableBatchedOperations.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableExpress.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnableExpress.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnablePartitioning.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.EnablePartitioning.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardDeadLetteredMessagesTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardDeadLetteredMessagesTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardTo.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ForwardTo.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Id.get -> string! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.LockDuration.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.LockDuration.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxDeliveryCount.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxDeliveryCount.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxMessageSizeInKilobytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxMessageSizeInKilobytes.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxSizeInMegabytes.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.MaxSizeInMegabytes.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Name.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Name.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresDuplicateDetection.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresDuplicateDetection.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresSession.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.RequiresSession.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ServiceBusTopic(string! id) -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Status.get -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.Status.set -> void -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusTopic! -Aspire.Hosting.Azure.ServiceBus.ApplicationModel.ServiceBusTopic.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.ContentType.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.ContentType.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.CorrelationId.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.CorrelationId.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.MessageId.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.MessageId.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.Properties.get -> System.Collections.Generic.Dictionary! +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.Properties.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.ReplyTo.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.ReplyTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.ReplyToSessionId.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.ReplyToSessionId.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.RequiresPreprocessing.get -> bool? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.RequiresPreprocessing.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.SendTo.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.SendTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.ServiceBusCorrelationFilter() -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.SessionId.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.SessionId.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.Subject.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter.Subject.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType +Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType.CorrelationFilter = 1 -> Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType +Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType.SqlFilter = 0 -> Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.DeadLetteringOnMessageExpiration.get -> bool? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.DeadLetteringOnMessageExpiration.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.DefaultMessageTimeToLive.get -> System.TimeSpan? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.DefaultMessageTimeToLive.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.DuplicateDetectionHistoryTimeWindow.get -> System.TimeSpan? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.DuplicateDetectionHistoryTimeWindow.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.ForwardDeadLetteredMessagesTo.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.ForwardDeadLetteredMessagesTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.ForwardTo.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.ForwardTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.LockDuration.get -> System.TimeSpan? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.LockDuration.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.MaxDeliveryCount.get -> int? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.MaxDeliveryCount.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.Name.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.RequiresDuplicateDetection.get -> bool? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.RequiresDuplicateDetection.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.RequiresSession.get -> bool? +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.RequiresSession.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.ServiceBusQueue(string! id, string! name) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusQueue! +Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.CorrelationFilter.get -> Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter! +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.CorrelationFilter.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.FilterType.get -> Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType? +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.FilterType.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.Name.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.ServiceBusRule(string! id, string! name) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusRule! +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.DeadLetteringOnMessageExpiration.get -> bool? +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.DeadLetteringOnMessageExpiration.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.DefaultMessageTimeToLive.get -> System.TimeSpan? +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.DefaultMessageTimeToLive.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.ForwardDeadLetteredMessagesTo.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.ForwardDeadLetteredMessagesTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.ForwardTo.get -> string? +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.ForwardTo.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.LockDuration.get -> System.TimeSpan? +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.LockDuration.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.MaxDeliveryCount.get -> int? +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.MaxDeliveryCount.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.Name.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.RequiresSession.get -> bool? +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.RequiresSession.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.ServiceBusSubscription(string! id, string! name) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusSubscription! +Aspire.Hosting.Azure.ServiceBus.ServiceBusSubscription.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.DefaultMessageTimeToLive.get -> System.TimeSpan? +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.DefaultMessageTimeToLive.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.DuplicateDetectionHistoryTimeWindow.get -> System.TimeSpan? +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.DuplicateDetectionHistoryTimeWindow.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.Id.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.Name.get -> string! +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.Name.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.RequiresDuplicateDetection.get -> bool? +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.RequiresDuplicateDetection.set -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ServiceBusTopic(string! id, string! name) -> void +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusTopic! +Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Annotations.get -> Aspire.Hosting.ApplicationModel.ResourceAnnotationCollection! override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Name.get -> string! -static Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.implicit operator Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue!(T value) -> Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! -static Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue.implicit operator T?(Aspire.Hosting.Azure.ServiceBus.ApplicationModel.OptionalValue! value) -> T? -static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.RunAsEmulator(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, System.Action!>? configureContainer = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithConfigJson(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! path) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string? path = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! From 8f8281dab18a2f0eb58750d89a01a91ad6986f27 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Wed, 20 Nov 2024 14:51:15 -0800 Subject: [PATCH 09/17] PR feedback --- .../ServiceBusWorker/ServiceBusWorker.csproj | 1 - .../AzureCosmosDBEmulatorResource.cs | 3 --- .../AzureEventHubsEmulatorResource.cs | 3 --- .../EventHubsEmulatorContainerImageTags.cs | 6 +++--- .../Aspire.Hosting.Azure.ServiceBus.csproj | 1 - .../AzureServiceBusEmulatorResource.cs | 3 --- src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt | 2 +- .../AzureStorageEmulatorResource.cs | 3 --- 8 files changed, 4 insertions(+), 18 deletions(-) diff --git a/playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj b/playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj index a551003f1a..0149f12d83 100644 --- a/playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj +++ b/playground/AzureServiceBus/ServiceBusWorker/ServiceBusWorker.csproj @@ -9,7 +9,6 @@ - diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs index 1eacd90e27..f6a6433e37 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs @@ -13,9 +13,6 @@ public class AzureCosmosDBEmulatorResource(AzureCosmosDBResource innerResource) { private readonly AzureCosmosDBResource _innerResource = innerResource; - /// - public override string Name => _innerResource.Name; - /// public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; } diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs index 910d7b55cd..bf150e3324 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs @@ -16,9 +16,6 @@ public class AzureEventHubsEmulatorResource(AzureEventHubsResource innerResource private readonly AzureEventHubsResource _innerResource = innerResource; - /// - public override string Name => _innerResource.Name; - /// public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; } diff --git a/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs b/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs index f32e098277..8a50e3ab20 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/EventHubsEmulatorContainerImageTags.cs @@ -5,12 +5,12 @@ namespace Aspire.Hosting.Azure.EventHubs; internal static class EventHubsEmulatorContainerImageTags { - /// mcr.microsoft.com + /// mcr.microsoft.com public const string Registry = "mcr.microsoft.com"; - /// azure-messaging/eventhubs-emulator + /// azure-messaging/eventhubs-emulator public const string Image = "azure-messaging/eventhubs-emulator"; - /// latest + /// latest public const string Tag = "latest"; // latest is the only arch-agnostic tag } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj index 46610ed3ec..022424d4a8 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj +++ b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj @@ -6,7 +6,6 @@ aspire integration hosting azure Azure Service Bus resource types for .NET Aspire. $(SharedDir)AzureServiceBus_256x.png - diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs index 260e39dc28..4c6c2720f6 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusEmulatorResource.cs @@ -16,9 +16,6 @@ public class AzureServiceBusEmulatorResource(AzureServiceBusResource innerResour private readonly AzureServiceBusResource _innerResource = innerResource; - /// - public override string Name => _innerResource.Name; - /// public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index 49924a1668..41060b55c6 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -61,7 +61,7 @@ Aspire.Hosting.Azure.ServiceBus.ServiceBusQueue.WriteJsonObjectProperties(System Aspire.Hosting.Azure.ServiceBus.ServiceBusRule Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.CorrelationFilter.get -> Aspire.Hosting.Azure.ServiceBus.ServiceBusCorrelationFilter! Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.CorrelationFilter.set -> void -Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.FilterType.get -> Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType? +Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.FilterType.get -> Aspire.Hosting.Azure.ServiceBus.ServiceBusFilterType Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.FilterType.set -> void Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.Id.get -> string! Aspire.Hosting.Azure.ServiceBus.ServiceBusRule.Name.get -> string! diff --git a/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs b/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs index 0cf55fce8c..23194042cf 100644 --- a/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs @@ -13,9 +13,6 @@ public class AzureStorageEmulatorResource(AzureStorageResource innerResource) : { private readonly AzureStorageResource _innerResource = innerResource; - /// - public override string Name => _innerResource.Name; - /// public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; } From fd1a4b21478a1ffef321d462e037a4b24bd487f6 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Wed, 20 Nov 2024 15:33:38 -0800 Subject: [PATCH 10/17] Revert API breaking changes --- .../AzureCosmosDBEmulatorResource.cs | 3 +++ .../AzureEventHubsEmulatorResource.cs | 3 +++ .../AzureServiceBusExtensions.cs | 15 ++++++++++----- .../AzureStorageEmulatorResource.cs | 3 +++ 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs index f6a6433e37..1eacd90e27 100644 --- a/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.CosmosDB/AzureCosmosDBEmulatorResource.cs @@ -13,6 +13,9 @@ public class AzureCosmosDBEmulatorResource(AzureCosmosDBResource innerResource) { private readonly AzureCosmosDBResource _innerResource = innerResource; + /// + public override string Name => _innerResource.Name; + /// public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; } diff --git a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs index bf150e3324..910d7b55cd 100644 --- a/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.EventHubs/AzureEventHubsEmulatorResource.cs @@ -16,6 +16,9 @@ public class AzureEventHubsEmulatorResource(AzureEventHubsResource innerResource private readonly AzureEventHubsResource _innerResource = innerResource; + /// + public override string Name => _innerResource.Name; + /// public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index 1cd8edc5db..b445dea199 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -23,7 +23,7 @@ public static class AzureServiceBusExtensions /// /// The builder for the distributed application. /// The name of the resource. - /// + /// A reference to the . public static IResourceBuilder AddAzureServiceBus(this IDistributedApplicationBuilder builder, [ResourceName] string name) { builder.AddAzureProvisioning(); @@ -106,6 +106,7 @@ public static IResourceBuilder AddAzureServiceBus(this /// The name of the topic. /// The name of the subscriptions. /// An optional method that can be used for customizing the . + /// A reference to the . public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, string[] subscriptions, Action? configure = null) { var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(name); @@ -128,6 +129,7 @@ public static IResourceBuilder AddTopic(this IResourceB /// The Azure Service Bus resource builder. /// The name of the queue. /// An optional method that can be used for customizing the . + /// A reference to the . public static IResourceBuilder AddQueue(this IResourceBuilder builder, [ResourceName] string name, Action? configure = null) { var queue = new ServiceBusQueue(Infrastructure.NormalizeBicepIdentifier(name), name); @@ -157,6 +159,7 @@ public static IResourceBuilder AddTopic(this IResourceB /// The Azure Service Bus resource builder. /// The name of the topic. /// An optional method that can be used for customizing the . + /// A reference to the . public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, Action configure) { var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name), name); @@ -173,6 +176,7 @@ public static IResourceBuilder AddTopic(this IResourceB /// The name of the topic. /// The name of the subscription. /// An optional method that can be used for customizing the . + /// A reference to the . public static IResourceBuilder AddSubscription(this IResourceBuilder builder, string topicName, string subscriptionName, Action? configure = null) { var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(topicName); @@ -192,6 +196,7 @@ public static IResourceBuilder AddSubscription(this IRe /// The name of the subscription. /// The name of the rule /// An optional method that can be used for customizing the . + /// A reference to the . public static IResourceBuilder AddRule(this IResourceBuilder builder, string topicName, string subscriptionName, string ruleName, Action? configure = null) { var normalizedTopicName = Infrastructure.NormalizeBicepIdentifier(topicName); @@ -418,7 +423,7 @@ public static IResourceBuilder RunAsEmulator(this IReso /// /// The builder for the . /// Relative path to the AppHost where emulator storage is persisted between runs. Defaults to the path '.servicebus/{builder.Resource.Name}' - /// A builder for the . + /// A reference to the . public static IResourceBuilder WithDataBindMount(this IResourceBuilder builder, string? path = null) => builder.WithBindMount(path ?? $".servicebus/{builder.Resource.Name}", "/data", isReadOnly: false); @@ -427,7 +432,7 @@ public static IResourceBuilder WithDataBindMoun /// /// The builder for the . /// The name of the volume. Defaults to an auto-generated name based on the application and resource names. - /// A builder for the . + /// A reference to the . public static IResourceBuilder WithDataVolume(this IResourceBuilder builder, string? name = null) => builder.WithVolume(name ?? VolumeNameGenerator.Generate(builder, "data"), "/data", isReadOnly: false); @@ -436,7 +441,7 @@ public static IResourceBuilder WithDataVolume(t /// /// The builder for the . /// Path to the file on the AppHost where the emulator configuration is located. - /// A builder for the . + /// A reference to the . public static IResourceBuilder WithConfigJson(this IResourceBuilder builder, string path) => builder.WithBindMount(path, AzureServiceBusEmulatorResource.EmulatorConfigJsonPath, isReadOnly: true); @@ -445,7 +450,7 @@ public static IResourceBuilder WithConfigJson(t /// /// Builder for the Azure Service Bus emulator container /// Host port to bind to the emulator gateway port. - /// Azure Service Bus emulator resource builder. + /// A reference to the . public static IResourceBuilder WithGatewayPort(this IResourceBuilder builder, int? port) { return builder.WithEndpoint("emulator", endpoint => diff --git a/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs b/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs index 23194042cf..0cf55fce8c 100644 --- a/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs +++ b/src/Aspire.Hosting.Azure.Storage/AzureStorageEmulatorResource.cs @@ -13,6 +13,9 @@ public class AzureStorageEmulatorResource(AzureStorageResource innerResource) : { private readonly AzureStorageResource _innerResource = innerResource; + /// + public override string Name => _innerResource.Name; + /// public override ResourceAnnotationCollection Annotations => _innerResource.Annotations; } From 12c62144266f88ad66eae50edfb339f8b3f35c25 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Thu, 21 Nov 2024 17:24:02 -0800 Subject: [PATCH 11/17] Ad callback to update json configuration --- .../ServiceBus.AppHost/Program.cs | 11 ++- .../AzureServiceBusExtensions.cs | 71 ++++++++++++++++--- .../ConfigJsonAnnotation.cs | 20 ++++++ .../PublicAPI.Unshipped.txt | 2 +- 4 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ConfigJsonAnnotation.cs diff --git a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs index 3aced78406..e8816617a9 100644 --- a/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs +++ b/playground/AzureServiceBus/ServiceBus.AppHost/Program.cs @@ -1,8 +1,8 @@ +using System.Text.Json.Nodes; + var builder = DistributedApplication.CreateBuilder(args); -var serviceBus = builder.AddAzureServiceBus("sbemulator") - .RunAsEmulator() // Comment to deploy and use the Azure cloud - ; +var serviceBus = builder.AddAzureServiceBus("sbemulator"); serviceBus .AddQueue("myQueue", queue => @@ -51,6 +51,11 @@ //}) ; +serviceBus.RunAsEmulator(configure => configure.ConfigureJson(document => +{ + document["UserConfig"]!["Logging"] = new JsonObject { ["Type"] = "Console" }; +})); + builder.AddProject("worker") .WithReference(serviceBus).WaitFor(serviceBus); diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index b445dea199..d353a2aa97 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Text.Json; +using System.Text.Json.Nodes; using Aspire.Hosting.ApplicationModel; using Aspire.Hosting.Azure; using Aspire.Hosting.Azure.ServiceBus; @@ -257,6 +258,12 @@ public static IResourceBuilder RunAsEmulator(this IReso var password = PasswordGenerator.Generate(16, true, true, true, true, 0, 0, 0, 0); + var customMountAnnotation = new ContainerMountAnnotation( + configHostFile, + AzureServiceBusEmulatorResource.EmulatorConfigJsonPath, + ContainerMountType.BindMount, + isReadOnly: false); + builder .WithEndpoint(name: "emulator", targetPort: 5672) .WithAnnotation(new ContainerImageAnnotation @@ -265,11 +272,7 @@ public static IResourceBuilder RunAsEmulator(this IReso Image = ServiceBusEmulatorContainerImageTags.Image, Tag = ServiceBusEmulatorContainerImageTags.Tag }) - .WithAnnotation(new ContainerMountAnnotation( - configHostFile, - AzureServiceBusEmulatorResource.EmulatorConfigJsonPath, - ContainerMountType.BindMount, - isReadOnly: false)); + .WithAnnotation(customMountAnnotation); var sqlEdgeResource = builder.ApplicationBuilder .AddContainer($"{builder.Resource.Name}-sqledge", @@ -336,8 +339,13 @@ public static IResourceBuilder RunAsEmulator(this IReso foreach (var emulatorResource in serviceBusEmulatorResources) { // A custom file mount with read-only access is used to mount the emulator configuration file. If it's not found, the read-write mount we defined on the container is used. - var configFileMount = emulatorResource.Annotations.OfType().FirstOrDefault(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath && v.IsReadOnly) - ?? emulatorResource.Annotations.OfType().Single(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath); + var configFileMount = emulatorResource.Annotations.OfType().LastOrDefault(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath); + + // If the latest mount for EmulatorConfigJsonPath is our custom one then we can generate it. + if (configFileMount != customMountAnnotation) + { + continue; + } using var stream = new FileStream(configFileMount.Source!, FileMode.Create); using var writer = new Utf8JsonWriter(stream); @@ -411,6 +419,37 @@ public static IResourceBuilder RunAsEmulator(this IReso } + // Apply ConfigJsonAnnotation modifications + foreach (var emulatorResource in serviceBusEmulatorResources) + { + var configFileMount = emulatorResource.Annotations.OfType().LastOrDefault(v => v.Target == AzureServiceBusEmulatorResource.EmulatorConfigJsonPath); + + // At this point there should be a mount for the Config.json file. + if (configFileMount == null) + { + throw new InvalidOperationException("The configuration file mount is not set."); + } + + var configJsonAnnotations = emulatorResource.Annotations.OfType(); + + foreach (var annotation in configJsonAnnotations) + { + using var readStream = new FileStream(configFileMount.Source!, FileMode.Open, FileAccess.Read); + var jsonObject = JsonNode.Parse(readStream); + readStream.Close(); + + using var writeStream = new FileStream(configFileMount.Source!, FileMode.Open, FileAccess.Write); + using var writer = new Utf8JsonWriter(writeStream); + + if (jsonObject == null) + { + throw new InvalidOperationException("The configuration file mount could not be parsed."); + } + annotation.Configure(jsonObject); + jsonObject.WriteTo(writer); + } + } + return Task.CompletedTask; }); @@ -443,7 +482,23 @@ public static IResourceBuilder WithDataVolume(t /// Path to the file on the AppHost where the emulator configuration is located. /// A reference to the . public static IResourceBuilder WithConfigJson(this IResourceBuilder builder, string path) - => builder.WithBindMount(path, AzureServiceBusEmulatorResource.EmulatorConfigJsonPath, isReadOnly: true); + => builder.WithBindMount(path, AzureServiceBusEmulatorResource.EmulatorConfigJsonPath, isReadOnly: false); + + /// + /// Alters the JSON configuration document used by the emulator. + /// + /// The builder for the . + /// A callback to update the JSON object representation of the configuration. + /// A reference to the . + public static IResourceBuilder ConfigureJson(this IResourceBuilder builder, Action configJson) + { + ArgumentNullException.ThrowIfNull(builder); + ArgumentNullException.ThrowIfNull(configJson); + + builder.WithAnnotation(new ConfigJsonAnnotation(configJson)); + + return builder; + } /// /// Configures the gateway port for the Azure Service Bus emulator. diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ConfigJsonAnnotation.cs b/src/Aspire.Hosting.Azure.ServiceBus/ConfigJsonAnnotation.cs new file mode 100644 index 0000000000..4b57ba9738 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ConfigJsonAnnotation.cs @@ -0,0 +1,20 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Text.Json.Nodes; +using Aspire.Hosting.ApplicationModel; + +namespace Aspire.Hosting.Azure.ServiceBus; + +/// +/// Represents an annotation for updating the JSON content of a mounted document. +/// +internal sealed class ConfigJsonAnnotation : IResourceAnnotation +{ + public ConfigJsonAnnotation(Action configure) + { + Configure = configure; + } + + public Action Configure { get; } +} diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index 41060b55c6..8d040d0a1c 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -104,12 +104,12 @@ Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ServiceBusTopic(string! id, stri Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusTopic! Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Annotations.get -> Aspire.Hosting.ApplicationModel.ResourceAnnotationCollection! -override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Name.get -> string! static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.ConfigureJson(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, System.Action! configJson) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.RunAsEmulator(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, System.Action!>? configureContainer = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithConfigJson(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! path) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.WithDataBindMount(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string? path = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! From af5ff577e7e7399e3dd9310e9b86a05b33c8cb41 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 22 Nov 2024 18:20:53 -0800 Subject: [PATCH 12/17] Add tests --- .../Aspire.Hosting.Azure.ServiceBus.csproj | 4 +- .../AzureServiceBusExtensions.cs | 44 +- .../ServiceBusHealthCheck.cs | 54 +++ .../Aspire.Hosting.Azure.Tests.csproj | 4 +- .../AzureServiceBusExtensionsTests.cs | 409 ++++++++++++++++++ 5 files changed, 498 insertions(+), 17 deletions(-) create mode 100644 src/Aspire.Hosting.Azure.ServiceBus/ServiceBusHealthCheck.cs diff --git a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj index 022424d4a8..47dce81240 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj +++ b/src/Aspire.Hosting.Azure.ServiceBus/Aspire.Hosting.Azure.ServiceBus.csproj @@ -1,9 +1,9 @@ - + $(DefaultTargetFramework) true - aspire integration hosting azure + aspire integration hosting azure servicebus Azure Service Bus resource types for .NET Aspire. $(SharedDir)AzureServiceBus_256x.png diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index d353a2aa97..c25b944c08 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -7,9 +7,9 @@ using Aspire.Hosting.Azure; using Aspire.Hosting.Azure.ServiceBus; using Aspire.Hosting.Utils; -using Azure.Messaging.ServiceBus; using Azure.Provisioning; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; using AzureProvisioning = Azure.Provisioning.ServiceBus; namespace Aspire.Hosting; @@ -292,11 +292,20 @@ public static IResourceBuilder RunAsEmulator(this IReso context.EnvironmentVariables.Add("MSSQL_SA_PASSWORD", password); })); - ServiceBusClient? client = null; string? connectionString = null; + string[]? queueNames = null; + string[]? topicNames = null; builder.ApplicationBuilder.Eventing.Subscribe(builder.Resource, async (@event, ct) => { + var serviceBusEmulatorResources = builder.ApplicationBuilder.Resources.OfType().Where(x => x is { } serviceBusResource && serviceBusResource.IsEmulator); + + if (!serviceBusEmulatorResources.Any()) + { + // No-op if there is no Azure Service Bus emulator resource. + return; + } + connectionString = await builder.Resource.ConnectionStringExpression.GetValueAsync(ct).ConfigureAwait(false); if (connectionString == null) @@ -304,20 +313,11 @@ public static IResourceBuilder RunAsEmulator(this IReso throw new DistributedApplicationException($"ConnectionStringAvailableEvent was published for the '{builder.Resource.Name}' resource but the connection string was null."); } - client = new ServiceBusClient(connectionString); + queueNames = serviceBusEmulatorResources.SelectMany(x => x.Queues).Select(x => x.Name).ToArray(); + topicNames = serviceBusEmulatorResources.SelectMany(x => x.Topics).Select(x => x.Name).ToArray(); }); var healthCheckKey = $"{builder.Resource.Name}_check"; - builder.ApplicationBuilder.Services.AddHealthChecks().AddAzureServiceBusQueue(connectionStringFactory: sp => - { - return connectionString ?? throw new InvalidOperationException("ServiceBusClient is not initialized."); - }, queueNameFactory: sp => - { - var queueName = builder.Resource.Queues[0].Name; - return queueName ?? throw new InvalidOperationException("Queue name is not initialized."); - }, name: healthCheckKey); - - builder.WithHealthCheck(healthCheckKey); if (configureContainer != null) { @@ -326,6 +326,22 @@ public static IResourceBuilder RunAsEmulator(this IReso configureContainer(surrogateBuilder); } + // To use the existing ServiceBus health check we would need to know if there is any queue or topic defined. + // We can register a health check for a queue and then no-op if there are no queues. Same for topics. This custom + // can be registered and will then iterate over the queues and topics. If no queues or no topics are defined + // then the health check will be successful. + + builder.ApplicationBuilder.Services.AddHealthChecks() + .Add(new HealthCheckRegistration( + healthCheckKey, + sp => new ServiceBusHealthCheck( + () => connectionString ?? throw new DistributedApplicationException($"{nameof(connectionString)} was not initialized."), + () => queueNames ?? throw new DistributedApplicationException($"{nameof(queueNames)} was not initialized."), + () => topicNames ?? throw new DistributedApplicationException($"{nameof(topicNames)} was not initialized.")), + failureStatus: default, + tags: default, + timeout: default)); + builder.ApplicationBuilder.Eventing.Subscribe((e, ct) => { var serviceBusEmulatorResources = builder.ApplicationBuilder.Resources.OfType().Where(x => x is { } serviceBusResource && serviceBusResource.IsEmulator); @@ -354,7 +370,7 @@ public static IResourceBuilder RunAsEmulator(this IReso writer.WriteStartObject("UserConfig"); // "UserConfig": { writer.WriteStartArray("Namespaces"); // "Namespaces": [ writer.WriteStartObject(); // { - writer.WriteString("Name", "sbemulatorns"); // "Name": "sbemulatorns" + writer.WriteString("Name", emulatorResource.Name); writer.WriteStartArray("Queues"); // "Queues": [ foreach (var queue in emulatorResource.Queues) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusHealthCheck.cs b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusHealthCheck.cs new file mode 100644 index 0000000000..a3fd1d5114 --- /dev/null +++ b/src/Aspire.Hosting.Azure.ServiceBus/ServiceBusHealthCheck.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Azure.Messaging.ServiceBus.Administration; +using Microsoft.Extensions.Diagnostics.HealthChecks; + +namespace Aspire.Hosting.Azure.ServiceBus; + +/// +/// The standard ServiceBus health check is not sufficient since it requires predefined knowledge that there is at least one queue or one topic. +/// At the time we register the health check, we may not know if there are any of each. +/// +internal sealed class ServiceBusHealthCheck : IHealthCheck +{ + private readonly Func _connectionStringFactory; + private readonly Func> _queueNamesFactory; + private readonly Func> _topicNamesFactory; + + public ServiceBusHealthCheck(Func connectionStringFactory, Func> queueNamesFactory, Func> topicNamesFactory) + { + ArgumentNullException.ThrowIfNull(connectionStringFactory); + ArgumentNullException.ThrowIfNull(queueNamesFactory); + ArgumentNullException.ThrowIfNull(topicNamesFactory); + + _connectionStringFactory = connectionStringFactory; + _queueNamesFactory = queueNamesFactory; + _topicNamesFactory = topicNamesFactory; + } + + /// + public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default) + { + var serviceBusManagementClient = new ServiceBusAdministrationClient(_connectionStringFactory()); + + try + { + foreach (var queueName in _queueNamesFactory()) + { + await serviceBusManagementClient.GetQueueRuntimePropertiesAsync(queueName, cancellationToken).ConfigureAwait(false); + } + + foreach (var topicName in _topicNamesFactory()) + { + await serviceBusManagementClient.GetTopicRuntimePropertiesAsync(topicName, cancellationToken).ConfigureAwait(false); + } + + return HealthCheckResult.Healthy(); + } + catch (Exception ex) + { + return new HealthCheckResult(context.Registration.FailureStatus, exception: ex); + } + } +} diff --git a/tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csproj b/tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csproj index c28a6677a8..e4e7b4e8c3 100644 --- a/tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csproj +++ b/tests/Aspire.Hosting.Azure.Tests/Aspire.Hosting.Azure.Tests.csproj @@ -1,4 +1,4 @@ - + $(DefaultTargetFramework) @@ -24,12 +24,14 @@ + + diff --git a/tests/Aspire.Hosting.Azure.Tests/AzureServiceBusExtensionsTests.cs b/tests/Aspire.Hosting.Azure.Tests/AzureServiceBusExtensionsTests.cs index 8712e85ba1..9f74f05997 100644 --- a/tests/Aspire.Hosting.Azure.Tests/AzureServiceBusExtensionsTests.cs +++ b/tests/Aspire.Hosting.Azure.Tests/AzureServiceBusExtensionsTests.cs @@ -1,7 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Text.Json.Nodes; +using Aspire.Components.Common.Tests; +using Aspire.Hosting.ApplicationModel; +using Aspire.Hosting.Azure.ServiceBus; using Aspire.Hosting.Utils; +using Azure.Messaging.ServiceBus; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Diagnostics.HealthChecks; +using Microsoft.Extensions.Hosting; using Xunit; using Xunit.Abstractions; @@ -63,4 +71,405 @@ param principalId string output.WriteLine(manifest.BicepText); Assert.Equal(expectedBicep, manifest.BicepText); } + + [Fact] + [RequiresDocker] + public async Task VerifyWaitForOnServiceBusEmulatorBlocksDependentResources() + { + var cts = new CancellationTokenSource(TimeSpan.FromMinutes(3)); + using var builder = TestDistributedApplicationBuilder.Create(output); + + var healthCheckTcs = new TaskCompletionSource(); + builder.Services.AddHealthChecks().AddAsyncCheck("blocking_check", () => + { + return healthCheckTcs.Task; + }); + + var resource = builder.AddAzureServiceBus("resource") + .AddQueue("queue1") + .RunAsEmulator() + .WithHealthCheck("blocking_check"); + + var dependentResource = builder.AddContainer("nginx", "mcr.microsoft.com/cbl-mariner/base/nginx", "1.22") + .WaitFor(resource); + + using var app = builder.Build(); + + var pendingStart = app.StartAsync(cts.Token); + + var rns = app.Services.GetRequiredService(); + + await rns.WaitForResourceAsync(resource.Resource.Name, KnownResourceStates.Running, cts.Token); + + await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Waiting, cts.Token); + + healthCheckTcs.SetResult(HealthCheckResult.Healthy()); + + await rns.WaitForResourceHealthyAsync(resource.Resource.Name, cts.Token); + + await rns.WaitForResourceAsync(dependentResource.Resource.Name, KnownResourceStates.Running, cts.Token); + + await pendingStart; + + await app.StopAsync(); + } + + [Fact] + [RequiresDocker] + public async Task VerifyAzureServiceBusEmulatorResource() + { + using var builder = TestDistributedApplicationBuilder.Create().WithTestAndResourceLogging(output); + var serviceBus = builder.AddAzureServiceBus("servicebusns") + .RunAsEmulator() + .AddQueue("queue1") + .AddQueue("topic1"); + + using var app = builder.Build(); + await app.StartAsync(); + + var hb = Host.CreateApplicationBuilder(); + hb.Configuration["ConnectionStrings:servicebusns"] = await serviceBus.Resource.ConnectionStringExpression.GetValueAsync(CancellationToken.None); + hb.AddAzureServiceBusClient("servicebusns"); + + using var host = hb.Build(); + await host.StartAsync(); + + var serviceBusClient = host.Services.GetRequiredService(); + var sender = serviceBusClient.CreateSender("queue1"); + + await sender.SendMessageAsync(new ServiceBusMessage("Hello world!")); + + var receiver = serviceBusClient.CreateReceiver("queue1"); + var message = await receiver.PeekMessageAsync().WaitAsync(TimeSpan.FromSeconds(5)); + + Assert.Equal("Hello world!", message.Body.ToString()); + } + + [Fact] + public void AzureServiceBusUseEmulatorCallbackWithWithDataBindMountResultsInBindMountAnnotationWithDefaultPath() + { + using var builder = TestDistributedApplicationBuilder.Create(); + var serviceBus = builder.AddAzureServiceBus("sb").RunAsEmulator(configureContainer: builder => + { + builder.WithDataBindMount(); + }); + + // Ignoring the annotation created for the custom Config.json file + var volumeAnnotation = serviceBus.Resource.Annotations.OfType().Single(a => !a.Target.Contains("Config.json")); + Assert.Equal(Path.Combine(builder.AppHostDirectory, ".servicebus", "sb"), volumeAnnotation.Source); + Assert.Equal("/data", volumeAnnotation.Target); + Assert.Equal(ContainerMountType.BindMount, volumeAnnotation.Type); + Assert.False(volumeAnnotation.IsReadOnly); + } + + [Fact] + public void AzureServiceBusUseEmulatorCallbackWithWithDataBindMountResultsInBindMountAnnotation() + { + using var builder = TestDistributedApplicationBuilder.Create(); + var serviceBus = builder.AddAzureServiceBus("sb").RunAsEmulator(configureContainer: builder => + { + builder.WithDataBindMount("mydata"); + }); + + // Ignoring the annotation created for the custom Config.json file + var volumeAnnotation = serviceBus.Resource.Annotations.OfType().Single(a => !a.Target.Contains("Config.json")); + Assert.Equal(Path.Combine(builder.AppHostDirectory, "mydata"), volumeAnnotation.Source); + Assert.Equal("/data", volumeAnnotation.Target); + Assert.Equal(ContainerMountType.BindMount, volumeAnnotation.Type); + Assert.False(volumeAnnotation.IsReadOnly); + } + + [Fact] + public void AddAzureServiceBusUseEmulatorCallbackWithWithDataVolumeResultsInVolumeAnnotationWithDefaultName() + { + using var builder = TestDistributedApplicationBuilder.Create(); + var serviceBus = builder.AddAzureServiceBus("sb").RunAsEmulator(configureContainer: builder => + { + builder.WithDataVolume(); + }); + + // Ignoring the annotation created for the custom Config.json file + var volumeAnnotation = serviceBus.Resource.Annotations.OfType().Single(a => !a.Target.Contains("Config.json")); + Assert.Equal($"{builder.GetVolumePrefix()}-sb-data", volumeAnnotation.Source); + Assert.Equal("/data", volumeAnnotation.Target); + Assert.Equal(ContainerMountType.Volume, volumeAnnotation.Type); + Assert.False(volumeAnnotation.IsReadOnly); + } + + [Fact] + public void AddAzureServiceBusUseEmulatorCallbackWithWithDataVolumeResultsInVolumeAnnotation() + { + using var builder = TestDistributedApplicationBuilder.Create(); + var serviceBus = builder.AddAzureServiceBus("sb").RunAsEmulator(configureContainer: builder => + { + builder.WithDataVolume("mydata"); + }); + + // Ignoring the annotation created for the custom Config.json file + var volumeAnnotation = serviceBus.Resource.Annotations.OfType().Single(a => !a.Target.Contains("Config.json")); + Assert.Equal("mydata", volumeAnnotation.Source); + Assert.Equal("/data", volumeAnnotation.Target); + Assert.Equal(ContainerMountType.Volume, volumeAnnotation.Type); + Assert.False(volumeAnnotation.IsReadOnly); + } + + [Theory] + [InlineData(null)] + [InlineData(8081)] + [InlineData(9007)] + public void AddAzureServiceBusWithEmulatorGetsExpectedPort(int? port = null) + { + using var builder = TestDistributedApplicationBuilder.Create(); + var serviceBus = builder.AddAzureServiceBus("sb").RunAsEmulator(configureContainer: builder => + { + builder.WithGatewayPort(port); + }); + + Assert.Collection( + serviceBus.Resource.Annotations.OfType(), + e => Assert.Equal(port, e.Port) + ); + } + + [Theory] + [InlineData(null)] + [InlineData("2.3.97-preview")] + [InlineData("1.0.7")] + public void AddAzureServiceBusWithEmulatorGetsExpectedImageTag(string? imageTag) + { + using var builder = TestDistributedApplicationBuilder.Create(); + var serviceBus = builder.AddAzureServiceBus("sb"); + + serviceBus.RunAsEmulator(container => + { + if (!string.IsNullOrEmpty(imageTag)) + { + container.WithImageTag(imageTag); + } + }); + + var containerImageAnnotation = serviceBus.Resource.Annotations.OfType().FirstOrDefault(); + Assert.NotNull(containerImageAnnotation); + + Assert.Equal(imageTag ?? ServiceBusEmulatorContainerImageTags.Tag, containerImageAnnotation.Tag); + Assert.Equal(ServiceBusEmulatorContainerImageTags.Registry, containerImageAnnotation.Registry); + Assert.Equal(ServiceBusEmulatorContainerImageTags.Image, containerImageAnnotation.Image); + } + + [Fact] + public async Task AzureServiceBusEmulatorResourceInitializesProvisioningModel() + { + using var builder = TestDistributedApplicationBuilder.Create(); + + global::Azure.Provisioning.ServiceBus.ServiceBusQueue? queue = null; + global::Azure.Provisioning.ServiceBus.ServiceBusTopic? topic = null; + global::Azure.Provisioning.ServiceBus.ServiceBusSubscription? subscription = null; + global::Azure.Provisioning.ServiceBus.ServiceBusRule? rule = null; + + var serviceBus = builder.AddAzureServiceBus("servicebusns") + .AddQueue("queue1", queue => + { + queue.DeadLetteringOnMessageExpiration = true; + queue.DefaultMessageTimeToLive = TimeSpan.FromMinutes(1); + queue.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + queue.ForwardDeadLetteredMessagesTo = "someQueue"; + queue.LockDuration = TimeSpan.FromMinutes(5); + queue.MaxDeliveryCount = 10; + queue.RequiresDuplicateDetection = true; + queue.RequiresSession = true; + }) + .AddTopic("topic1", topic => + { + topic.DefaultMessageTimeToLive = TimeSpan.FromMinutes(1); + topic.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + topic.RequiresDuplicateDetection = true; + }) + .AddSubscription("topic1", "subscription1", subscription => + { + subscription.DeadLetteringOnMessageExpiration = true; + subscription.DefaultMessageTimeToLive = TimeSpan.FromMinutes(1); + subscription.LockDuration = TimeSpan.FromMinutes(5); + subscription.MaxDeliveryCount = 10; + subscription.ForwardDeadLetteredMessagesTo = ""; + subscription.RequiresSession = true; + }) + .AddRule("topic1", "subscription1", "rule1", rule => + { + rule.FilterType = ServiceBusFilterType.SqlFilter; + rule.CorrelationFilter = new() + { + ContentType = "application/text", + CorrelationId = "id1", + Subject = "subject1", + MessageId = "msgid1", + ReplyTo = "someQueue", + ReplyToSessionId = "sessionId", + SessionId = "session1", + SendTo = "xyz" + }; + }) + .ConfigureInfrastructure(infrastructure => + { + queue = infrastructure.GetProvisionableResources().OfType().Single(); + topic = infrastructure.GetProvisionableResources().OfType().Single(); + subscription = infrastructure.GetProvisionableResources().OfType().Single(); + rule = infrastructure.GetProvisionableResources().OfType().Single(); + }); + + using var app = builder.Build(); + + var manifest = await ManifestUtils.GetManifestWithBicep(serviceBus.Resource); + + Assert.NotNull(queue); + Assert.Equal("queue1", queue.Name.Value); + Assert.True(queue.DeadLetteringOnMessageExpiration.Value); + Assert.Equal(TimeSpan.FromMinutes(1), queue.DefaultMessageTimeToLive.Value); + Assert.Equal(TimeSpan.FromSeconds(20), queue.DuplicateDetectionHistoryTimeWindow.Value); + Assert.Equal("someQueue", queue.ForwardDeadLetteredMessagesTo.Value); + Assert.Equal(TimeSpan.FromMinutes(5), queue.LockDuration.Value); + Assert.Equal(10, queue.MaxDeliveryCount.Value); + Assert.True(queue.RequiresDuplicateDetection.Value); + Assert.True(queue.RequiresSession.Value); + + Assert.NotNull(topic); + Assert.Equal("topic1", topic.Name.Value); + Assert.Equal(TimeSpan.FromMinutes(1), topic.DefaultMessageTimeToLive.Value); + Assert.Equal(TimeSpan.FromSeconds(20), topic.DuplicateDetectionHistoryTimeWindow.Value); + Assert.True(topic.RequiresDuplicateDetection.Value); + + Assert.NotNull(subscription); + Assert.Equal("subscription1", subscription.Name.Value); + Assert.True(subscription.DeadLetteringOnMessageExpiration.Value); + Assert.Equal(TimeSpan.FromMinutes(1), subscription.DefaultMessageTimeToLive.Value); + Assert.Equal(TimeSpan.FromMinutes(5), subscription.LockDuration.Value); + Assert.Equal(10, subscription.MaxDeliveryCount.Value); + Assert.Equal("", subscription.ForwardDeadLetteredMessagesTo.Value); + Assert.True(subscription.RequiresSession.Value); + + Assert.NotNull(rule); + Assert.Equal("rule1", rule.Name.Value); + Assert.Equal(global::Azure.Provisioning.ServiceBus.ServiceBusFilterType.SqlFilter, rule.FilterType.Value); + Assert.Equal("application/text", rule.CorrelationFilter.ContentType.Value); + Assert.Equal("id1", rule.CorrelationFilter.CorrelationId.Value); + Assert.Equal("subject1", rule.CorrelationFilter.Subject.Value); + Assert.Equal("msgid1", rule.CorrelationFilter.MessageId.Value); + Assert.Equal("someQueue", rule.CorrelationFilter.ReplyTo.Value); + Assert.Equal("sessionId", rule.CorrelationFilter.ReplyToSessionId.Value); + Assert.Equal("session1", rule.CorrelationFilter.SessionId.Value); + Assert.Equal("xyz", rule.CorrelationFilter.SendTo.Value); + } + + [Fact] + public async Task AzureServiceBusEmulatorResourceGeneratesConfigJson() + { + using var builder = TestDistributedApplicationBuilder.Create(); + + var serviceBus = builder.AddAzureServiceBus("servicebusns") + .RunAsEmulator() + .AddQueue("queue1", queue => + { + queue.DeadLetteringOnMessageExpiration = true; + queue.DefaultMessageTimeToLive = TimeSpan.FromMinutes(1); + queue.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + queue.ForwardDeadLetteredMessagesTo = "someQueue"; + queue.LockDuration = TimeSpan.FromMinutes(5); + queue.MaxDeliveryCount = 10; + queue.RequiresDuplicateDetection = true; + queue.RequiresSession = true; + }) + .AddTopic("topic1", topic => + { + topic.DefaultMessageTimeToLive = TimeSpan.FromMinutes(1); + topic.DuplicateDetectionHistoryTimeWindow = TimeSpan.FromSeconds(20); + topic.RequiresDuplicateDetection = true; + }) + .AddSubscription("topic1", "subscription1", subscription => + { + subscription.DeadLetteringOnMessageExpiration = true; + subscription.DefaultMessageTimeToLive = TimeSpan.FromMinutes(1); + subscription.LockDuration = TimeSpan.FromMinutes(5); + subscription.MaxDeliveryCount = 10; + subscription.ForwardDeadLetteredMessagesTo = ""; + subscription.RequiresSession = true; + }) + .AddRule("topic1", "subscription1", "rule1", rule => + { + rule.FilterType = ServiceBusFilterType.SqlFilter; + rule.CorrelationFilter = new() + { + ContentType = "application/text", + CorrelationId = "id1", + Subject = "subject1", + MessageId = "msgid1", + ReplyTo = "someQueue", + ReplyToSessionId = "sessionId", + SessionId = "session1", + SendTo = "xyz" + }; + }); + + using var app = builder.Build(); + + await builder.Eventing.PublishAsync(new(app.Services, app.Services.GetRequiredService())); + + var serviceBusEmulatorResource = builder.Resources.OfType().Single(x => x is { } serviceBusResource && serviceBusResource.IsEmulator); + var volumeAnnotation = serviceBusEmulatorResource.Annotations.OfType().Single(); + + var configJsonContent = File.ReadAllText(volumeAnnotation.Source!); + + Assert.Equal(""" + {"UserConfig":{"Namespaces":[{"Name":"servicebusns","Queues":[{"Name":"queue1","Properties":{"DeadLetteringOnMessageExpiration":true,"DefaultMessageTimeToLive":"PT1M","DuplicateDetectionHistoryTimeWindow":"PT20S","ForwardDeadLetteredMessagesTo":"someQueue","LockDuration":"PT5M","MaxDeliveryCount":10,"RequiresDuplicateDetection":true,"RequiresSession":true}}],"Topics":[{"Name":"topic1","Properties":{"DefaultMessageTimeToLive":"PT1M","DuplicateDetectionHistoryTimeWindow":"PT20S","RequiresDuplicateDetection":true},"Subscriptions":[{"Name":"subscription1","Properties":{"DeadLetteringOnMessageExpiration":true,"DefaultMessageTimeToLive":"PT1M","ForwardDeadLetteredMessagesTo":"","LockDuration":"PT5M","MaxDeliveryCount":10,"RequiresSession":true},"Rules":[{"Name":"rule1","Properties":{"FilterType":"Sql","CorrelationFilter":{"CorrelationId":"id1","MessageId":"msgid1","To":"xyz","ReplyTo":"someQueue","Label":"subject1","SessionId":"session1","ReplyToSessionId":"sessionId","ContentType":"application/text"}}}]}]}]}],"Logging":{"Type":"File"}}} + """, configJsonContent); + } + + [Fact] + public async Task AzureServiceBusEmulatorResourceGeneratesConfigJsonOnlyChangedProperties() + { + using var builder = TestDistributedApplicationBuilder.Create(); + + var serviceBus = builder.AddAzureServiceBus("servicebusns") + .RunAsEmulator() + .AddQueue("queue1", queue => + { + queue.DefaultMessageTimeToLive = TimeSpan.FromMinutes(1); + }); + + using var app = builder.Build(); + + await builder.Eventing.PublishAsync(new(app.Services, app.Services.GetRequiredService())); + + var serviceBusEmulatorResource = builder.Resources.OfType().Single(x => x is { } serviceBusResource && serviceBusResource.IsEmulator); + var volumeAnnotation = serviceBusEmulatorResource.Annotations.OfType().Single(); + + var configJsonContent = File.ReadAllText(volumeAnnotation.Source!); + + Assert.Equal(""" + {"UserConfig":{"Namespaces":[{"Name":"servicebusns","Queues":[{"Name":"queue1","Properties":{"DefaultMessageTimeToLive":"PT1M"}}],"Topics":[]}],"Logging":{"Type":"File"}}} + """, configJsonContent); + } + + [Fact] + public async Task AzureServiceBusEmulatorResourceGeneratesConfigJsonWithCustomizations() + { + using var builder = TestDistributedApplicationBuilder.Create(); + + var serviceBus = builder.AddAzureServiceBus("servicebusns") + .RunAsEmulator(configure => configure.ConfigureJson(document => + { + document["UserConfig"]!["Logging"] = new JsonObject { ["Type"] = "Console" }; + })); + + using var app = builder.Build(); + + await builder.Eventing.PublishAsync(new(app.Services, app.Services.GetRequiredService())); + + var serviceBusEmulatorResource = builder.Resources.OfType().Single(x => x is { } serviceBusResource && serviceBusResource.IsEmulator); + var volumeAnnotation = serviceBusEmulatorResource.Annotations.OfType().Single(); + + var configJsonContent = File.ReadAllText(volumeAnnotation.Source!); + + Assert.Equal(""" + {"UserConfig":{"Namespaces":[{"Name":"servicebusns","Queues":[],"Topics":[]}],"Logging":{"Type":"Console"}}} + """, configJsonContent); + } } From 781c595952963d72c478d1e549cd54cc3653d5fd Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Fri, 22 Nov 2024 18:35:34 -0800 Subject: [PATCH 13/17] Fix breaking changes --- .../AzureServiceBusExtensions.cs | 23 +++++++++++++++++++ .../PublicAPI.Unshipped.txt | 2 ++ 2 files changed, 25 insertions(+) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index c25b944c08..1d2ef6ce58 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -124,6 +124,17 @@ public static IResourceBuilder AddTopic(this IResourceB return builder; } + /// + /// Adds an Azure Service Bus Queue resource to the application model. This resource requires an to be added to the application model. + /// + /// The Azure Service Bus resource builder. + /// The name of the queue. + /// A reference to the . + public static IResourceBuilder AddQueue(this IResourceBuilder builder, [ResourceName] string name) + { + return builder.AddQueue(name, null); + } + /// /// Adds an Azure Service Bus Queue resource to the application model. This resource requires an to be added to the application model. /// @@ -170,6 +181,18 @@ public static IResourceBuilder AddTopic(this IResourceB return builder; } + /// + /// Adds an Azure Service Bus Subscription resource to the application model. This resource requires an to be added to the application model. + /// + /// The Azure Service Bus resource builder. + /// The name of the topic. + /// The name of the subscription. + /// A reference to the . + public static IResourceBuilder AddSubscription(this IResourceBuilder builder, string topicName, string subscriptionName) + { + return builder.AddSubscription(topicName, subscriptionName, null); + } + /// /// Adds an Azure Service Bus Subscription resource to the application model. This resource requires an to be added to the application model. /// diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index 8d040d0a1c..c9bd6c741d 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -104,8 +104,10 @@ Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ServiceBusTopic(string! id, stri Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusTopic! Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Annotations.get -> Aspire.Hosting.ApplicationModel.ResourceAnnotationCollection! +static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! From 340b389f50ba451e22073890c80aebd9777be893 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 25 Nov 2024 09:19:23 -0800 Subject: [PATCH 14/17] Add comments for CDK and Emulator discrepancies --- .../ApplicationModel/ServiceBusRule.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs index 929ba2dbed..9b4f7c3e41 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/ApplicationModel/ServiceBusRule.cs @@ -132,6 +132,7 @@ public void WriteJsonObjectProperties(Utf8JsonWriter writer) writer.WriteString(nameof(FilterType), rule.FilterType switch { + // The Emulator uses "Sql/Correlation" instead of "SqlFilter/CorrelationFilter" in the CDK (and Bicep template). ServiceBusFilterType.SqlFilter => "Sql", ServiceBusFilterType.CorrelationFilter => "Correlation", _ => throw new NotImplementedException() @@ -155,6 +156,7 @@ public void WriteJsonObjectProperties(Utf8JsonWriter writer) } if (rule.CorrelationFilter.SendTo != null) { + // The CDK uses "SentTo" instead of "To" accepted in the Emulator (and Bicep template). writer.WriteString("To", rule.CorrelationFilter.SendTo); } if (rule.CorrelationFilter.ReplyTo != null) @@ -163,6 +165,7 @@ public void WriteJsonObjectProperties(Utf8JsonWriter writer) } if (rule.CorrelationFilter.Subject != null) { + // The CDK uses "Subject" instead of "Label" accepted in Emulator (and Bicep template). writer.WriteString("Label", rule.CorrelationFilter.Subject); } if (rule.CorrelationFilter.SessionId != null) From 4725b38b198812450b9ee3d79670866ec61095f2 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 25 Nov 2024 09:19:31 -0800 Subject: [PATCH 15/17] Fix API descriptions --- src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt | 2 ++ src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt index 0b17f00a68..b1e38b3ac5 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt @@ -6,7 +6,9 @@ Aspire.Hosting.Azure.AzureServiceBusResource.ServiceBusEndpoint.get -> Aspire.Ho Aspire.Hosting.AzureServiceBusExtensions static Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddAzureServiceBus(this Aspire.Hosting.IDistributedApplicationBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusNamespace!>? configureResource) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusQueue!>? configureQueue) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusSubscription!>? configureSubscription) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusTopic!>? configureTopic) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt index c9bd6c741d..8d040d0a1c 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Unshipped.txt @@ -104,10 +104,8 @@ Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ServiceBusTopic(string! id, stri Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.ToProvisioningEntity() -> Azure.Provisioning.ServiceBus.ServiceBusTopic! Aspire.Hosting.Azure.ServiceBus.ServiceBusTopic.WriteJsonObjectProperties(System.Text.Json.Utf8JsonWriter! writer) -> void override Aspire.Hosting.Azure.AzureServiceBusEmulatorResource.Annotations.get -> Aspire.Hosting.ApplicationModel.ResourceAnnotationCollection! -static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddRule(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, string! ruleName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions, System.Action? configure = null) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action! configure) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! From 59b6ea4d38b1e66a5405a03eee14b069e1e29887 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 25 Nov 2024 09:27:41 -0800 Subject: [PATCH 16/17] Fix breaking change --- .../AzureServiceBusExtensions.cs | 19 +++++++++++++++++-- .../PublicAPI.Shipped.txt | 1 + 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs index 1d2ef6ce58..cfda441b62 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs +++ b/src/Aspire.Hosting.Azure.ServiceBus/AzureServiceBusExtensions.cs @@ -159,9 +159,24 @@ public static IResourceBuilder AddQueue(this IResourceB /// The name of the topic. public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name) { - var topic = new ServiceBusTopic(Infrastructure.NormalizeBicepIdentifier(name), name); + return builder.AddTopic(name, configure: (topic) => { }); + } + + /// + /// Adds an Azure Service Bus Topic resource to the application model. This resource requires an to be added to the application model. + /// + /// The Azure Service Bus resource builder. + /// The name of the topic. + /// The name of the subscriptions. + public static IResourceBuilder AddTopic(this IResourceBuilder builder, [ResourceName] string name, string[] subscriptions) + { + builder.AddTopic(name, configure: (topic) => { }); + + foreach (var subscription in subscriptions) + { + builder.AddSubscription(name, subscription); + } - builder.Resource.Topics.Add(topic); return builder; } diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt index b1e38b3ac5..e651ecf5b1 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt @@ -10,5 +10,6 @@ static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.App static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusQueue!>? configureQueue) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusSubscription!>? configureSubscription) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusTopic!>? configureTopic) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! From cf46fafdddc3f9c4ba70de37a06d1064f7e72940 Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Mon, 25 Nov 2024 09:29:24 -0800 Subject: [PATCH 17/17] Clean delta --- src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt index e651ecf5b1..d79d439341 100644 --- a/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt +++ b/src/Aspire.Hosting.Azure.ServiceBus/PublicAPI.Shipped.txt @@ -10,6 +10,6 @@ static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.App static Aspire.Hosting.AzureServiceBusExtensions.AddQueue(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusQueue!>? configureQueue) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddSubscription(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! topicName, string! subscriptionName, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusSubscription!>? configureSubscription) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! -static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! +static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, string![]! subscriptions) -> Aspire.Hosting.ApplicationModel.IResourceBuilder! static Aspire.Hosting.AzureServiceBusExtensions.AddTopic(this Aspire.Hosting.ApplicationModel.IResourceBuilder! builder, string! name, System.Action!, Aspire.Hosting.ResourceModuleConstruct!, Azure.Provisioning.ServiceBus.ServiceBusTopic!>? configureTopic) -> Aspire.Hosting.ApplicationModel.IResourceBuilder!