From 0eb177b0e4e9394b3a843390f877c75c78fd2662 Mon Sep 17 00:00:00 2001 From: Marc Duiker Date: Mon, 24 Nov 2025 13:52:05 +0100 Subject: [PATCH] Remove docs since they are migrated to the main Docs repo Signed-off-by: Marc Duiker --- daprdocs/content/en/dotnet-sdk-docs/_index.md | 202 ------------------ .../dotnet-sdk-docs/dotnet-advanced/_index.md | 10 - .../dotnet-application-environment.md | 136 ------------ .../dotnet-component-lifetime.md | 80 ------- .../dotnet-multiple-services.md | 98 --------- .../dotnet-sdk-docs/dotnet-bindings/_index.md | 139 ------------ .../dotnet-sdk-docs/dotnet-pub-sub/_index.md | 107 ---------- .../dotnet-state-store/_index.md | 172 --------------- 8 files changed, 944 deletions(-) delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/_index.md delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/_index.md delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-application-environment.md delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-component-lifetime.md delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-multiple-services.md delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/dotnet-bindings/_index.md delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/dotnet-pub-sub/_index.md delete mode 100644 daprdocs/content/en/dotnet-sdk-docs/dotnet-state-store/_index.md diff --git a/daprdocs/content/en/dotnet-sdk-docs/_index.md b/daprdocs/content/en/dotnet-sdk-docs/_index.md deleted file mode 100644 index 715247f..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/_index.md +++ /dev/null @@ -1,202 +0,0 @@ ---- -type: docs -title: "Getting started with the Dapr pluggable components .NET SDK" -linkTitle: ".NET" -weight: 1000 -description: How to get up and running with the Dapr pluggable components .NET SDK -no_list: true -is_preview: true -cascade: - github_repo: https://github.com/dapr-sandbox/components-dotnet-sdk - github_subdir: daprdocs/content/en/dotnet-sdk-docs - path_base_for_github_subdir: content/en/developing-applications/develop-components/pluggable-components/pluggable-components-sdks/pluggable-components-dotnet/ - github_branch: main ---- - -Dapr offers NuGet packages to help with the development of .NET pluggable components. - -## Prerequisites - -- [.NET 6 SDK](https://dotnet.microsoft.com/en-us/download/dotnet) or later -- [Dapr 1.9 CLI]({{% ref install-dapr-cli.md %}}) or later -- Initialized [Dapr environment]({{% ref install-dapr-selfhost.md %}}) -- Linux, Mac, or Windows (with WSL) - -{{% alert title="Note" color="primary" %}} -Development of Dapr pluggable components on Windows requires WSL as some development platforms do not fully support Unix Domain Sockets on "native" Windows. -{{% /alert %}} - -## Project creation - -Creating a pluggable component starts with an empty ASP.NET project. - -```bash -dotnet new web --name -``` - -## Add NuGet packages - -Add the Dapr .NET pluggable components NuGet package. - -```bash -dotnet add package Dapr.PluggableComponents.AspNetCore -``` - -## Create application and service - -Creating a Dapr pluggable component application is similar to creating an ASP.NET application. In `Program.cs`, replace the `WebApplication` related code with the Dapr `DaprPluggableComponentsApplication` equivalent. - -```csharp -using Dapr.PluggableComponents; - -var app = DaprPluggableComponentsApplication.Create(); - -app.RegisterService( - "", - serviceBuilder => - { - // Register one or more components with this service. - }); - -app.Run(); -``` - -This creates an application with a single service. Each service: - -- Corresponds to a single Unix Domain Socket -- Can host one or more component types - -{{% alert title="Note" color="primary" %}} -Only a single component of each type can be registered with an individual service. However, [multiple components of the same type can be spread across multiple services]({{% ref dotnet-multiple-services %}}). -{{% /alert %}} - -## Implement and register components - - - [Implementing an input/output binding component]({{% ref dotnet-bindings %}}) - - [Implementing a pub-sub component]({{% ref dotnet-pub-sub %}}) - - [Implementing a state store component]({{% ref dotnet-state-store %}}) - -## Test components locally - -Pluggable components can be tested by starting the application on the command line and configuring a Dapr sidecar to use it. - -To start the component, in the application directory: - -```bash -dotnet run -``` - -To configure Dapr to use the component, in the resources path directory: - -```yaml -apiVersion: dapr.io/v1alpha1 -kind: Component -metadata: - name: -spec: - type: state. - version: v1 - metadata: - - name: key1 - value: value1 - - name: key2 - value: value2 -``` - -Any `metadata` properties will be passed to the component via its `IPluggableComponent.InitAsync()` method when the component is instantiated. - -To start Dapr (and, optionally, the service making use of the service): - -```bash -dapr run --app-id --resources-path ... -``` - -At this point, the Dapr sidecar will have started and connected via Unix Domain Socket to the component. You can then interact with the component either: -- Through the service using the component (if started), or -- By using the Dapr HTTP or gRPC API directly - -## Create Container - -There are several ways to create a container for your component for eventual deployment. - -### Use .NET SDK - -The [.NET 7 and later SDKs](https://dotnet.microsoft.com/en-us/download/dotnet) enable you to create a .NET-based container for your application *without* a `Dockerfile`, even for those targeting earlier versions of the .NET SDK. This is probably the simplest way of generating a container for your component today. - -{{% alert title="Note" color="primary" %}} -Currently, the .NET 7 SDK requires Docker Desktop on the local machine, a special NuGet package, and Docker Desktop on the local machine to build containers. Future versions of .NET SDK plan to eliminate those requirements. - -Multiple versions of the .NET SDK can be installed on the local machine at the same time. -{{% /alert %}} - -Add the `Microsoft.NET.Build.Containers` NuGet package to the component project. - -```bash -dotnet add package Microsoft.NET.Build.Containers -``` - -Publish the application as a container: - -```bash -dotnet publish --os linux --arch x64 /t:PublishContainer -c Release -``` - -{{% alert title="Note" color="primary" %}} -Ensure the architecture argument `--arch x64` matches that of the component's ultimate deployment target. By default, the architecture of the generated container matches that of the local machine. For example, if the local machine is ARM64-based (for example, a M1 or M2 Mac) and the argument is omitted, an ARM64 container will be generated which may not be compatible with deployment targets expecting an AMD64 container. -{{% /alert %}} - -For more configuration options, such as controlling the container name, tag, and base image, see the [.NET publish as container guide](https://learn.microsoft.com/en-us/dotnet/core/docker/publish-as-container). - -### Use a Dockerfile - -While there are tools that can generate a `Dockerfile` for a .NET application, the .NET SDK itself does not. A typical `Dockerfile` might look like: - -```dockerfile -FROM mcr.microsoft.com/dotnet/aspnet: AS base -WORKDIR /app - -# Creates a non-root user with an explicit UID and adds permission to access the /app folder -# For more info, please refer to https://aka.ms/vscode-docker-dotnet-configure-containers -RUN adduser -u 5678 --disabled-password --gecos "" appuser && chown -R appuser /app -USER appuser - -FROM mcr.microsoft.com/dotnet/sdk: AS build -WORKDIR /src -COPY [".csproj", "/"] -RUN dotnet restore "/.csproj" -COPY . . -WORKDIR "/src/" -RUN dotnet build ".csproj" -c Release -o /app/build - -FROM build AS publish -RUN dotnet publish ".csproj" -c Release -o /app/publish /p:UseAppHost=false - -FROM base AS final -WORKDIR /app -COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", ".dll"] -``` - -Build the image: - -```bash -docker build -f Dockerfile -t : . -``` - -{{% alert title="Note" color="primary" %}} -Paths for `COPY` operations in the `Dockerfile` are relative to the Docker context passed when building the image, while the Docker context itself will vary depending on the needs of the project being built (for example, if it has referenced projects). In the example above, the assumption is that the Docker context is the component project directory. -{{% /alert %}} - -## Demo - -Watch this video for a [demo on building pluggable components with .NET](https://youtu.be/s1p9MNl4VGo?t=1606): - - - -## Next steps - -- [Learn advanced steps for the Pluggable Component .NET SDK]({{% ref "dotnet-advanced" %}}) -- Learn more about using the Pluggable Component .NET SDK for: - - [Bindings]({{% ref "dotnet-bindings" %}}) - - [Pub/sub]({{% ref "dotnet-pub-sub" %}}) - - [State store]({{% ref "dotnet-state-store" %}}) \ No newline at end of file diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/_index.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/_index.md deleted file mode 100644 index be9d7da..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/_index.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -type: docs -title: "Advanced uses of the Dapr pluggable components .NET SDK" -linkTitle: "Advanced" -weight: 2000 -description: How to use advanced techniques with with the Dapr pluggable components .NET SDK -is_preview: true ---- - -While not typically needed by most, these guides show advanced ways to can configure your .NET pluggable components. \ No newline at end of file diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-application-environment.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-application-environment.md deleted file mode 100644 index 8338dc2..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-application-environment.md +++ /dev/null @@ -1,136 +0,0 @@ ---- -type: docs -title: "Application Environment of a .NET Dapr pluggable component" -linkTitle: "Application environment" -weight: 1000 -description: How to configure the environment of a .NET pluggable component -no_list: true -is_preview: true ---- - -A .NET Dapr pluggable component application can be configured for dependency injection, logging, and configuration values similarly to ASP.NET applications. The `DaprPluggableComponentsApplication` exposes a similar set of configuration properties to that exposed by `WebApplicationBuilder`. - -## Dependency injection - -Components registered with services can participate in dependency injection. Arguments in the components constructor will be injected during creation, assuming those types have been registered with the application. You can register them through the `IServiceCollection` exposed by `DaprPluggableComponentsApplication`. - -```csharp -var app = DaprPluggableComponentsApplication.Create(); - -// Register MyService as the singleton implementation of IService. -app.Services.AddSingleton(); - -app.RegisterService( - "", - serviceBuilder => - { - serviceBuilder.RegisterStateStore(); - }); - -app.Run(); - -interface IService -{ - // ... -} - -class MyService : IService -{ - // ... -} - -class MyStateStore : IStateStore -{ - // Inject IService on creation of the state store. - public MyStateStore(IService service) - { - // ... - } - - // ... -} -``` - -{{% alert title="Warning" color="warning" %}} -Use of `IServiceCollection.AddScoped()` is not recommended. Such instances' lifetimes are bound to a single gRPC method call, which does not match the lifetime of an individual component instance. -{{% /alert %}} - -## Logging - -.NET Dapr pluggable components can use the [standard .NET logging mechanisms](https://learn.microsoft.com/en-us/dotnet/core/extensions/logging). The `DaprPluggableComponentsApplication` exposes an `ILoggingBuilder`, through which it can be configured. - -{{% alert title="Note" color="primary" %}} -Like with ASP.NET, logger services (for example, `ILogger`) are pre-registered. -{{% /alert %}} - -```csharp -var app = DaprPluggableComponentsApplication.Create(); - -// Reset the default loggers and setup new ones. -app.Logging.ClearProviders(); -app.Logging.AddConsole(); - -app.RegisterService( - "", - serviceBuilder => - { - serviceBuilder.RegisterStateStore(); - }); - -app.Run(); - -class MyStateStore : IStateStore -{ - // Inject a logger on creation of the state store. - public MyStateStore(ILogger logger) - { - // ... - } - - // ... -} -``` - -## Configuration Values - -Since .NET pluggable components are built on ASP.NET, they can use its [standard configuration mechanisms](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration) and default to the same set of [pre-registered providers](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0#default-application-configuration-sources). The `DaprPluggableComponentsApplication` exposes an `IConfigurationManager` through which it can be configured. - -```csharp -var app = DaprPluggableComponentsApplication.Create(); - -// Reset the default configuration providers and add new ones. -((IConfigurationBuilder)app.Configuration).Sources.Clear(); -app.Configuration.AddEnvironmentVariables(); - -// Get configuration value on startup. -const value = app.Configuration[""]; - -app.RegisterService( - "", - serviceBuilder => - { - serviceBuilder.RegisterStateStore(); - }); - -app.Run(); - -class MyStateStore : IStateStore -{ - // Inject the configuration on creation of the state store. - public MyStateStore(IConfiguration configuration) - { - // ... - } - - // ... -} -``` - -## Next steps - -- [Learn more about the component lifetime]({{% ref "dotnet-component-lifetime" %}}) -- [Learn more about multiple services]({{% ref "dotnet-multiple-services" %}}) -- Learn more about using the Pluggable Component .NET SDK for: - - [Bindings]({{% ref "dotnet-bindings" %}}) - - [Pub/sub]({{% ref "dotnet-pub-sub" %}}) - - [State store]({{% ref "dotnet-state-store" %}}) \ No newline at end of file diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-component-lifetime.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-component-lifetime.md deleted file mode 100644 index 9eac96e..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-component-lifetime.md +++ /dev/null @@ -1,80 +0,0 @@ ---- -type: docs -title: "Lifetimes of .NET Dapr pluggable components" -linkTitle: "Component lifetime" -weight: 1000 -description: How to control the lifetime of a .NET pluggable component -no_list: true -is_preview: true ---- - -There are two ways to register a component: - - - The component operates as a singleton, with lifetime managed by the SDK - - A component's lifetime is determined by the pluggable component and can be multi-instance or a singleton, as needed - -## Singleton components - -Components registered _by type_ are singletons: one instance will serve all configured components of that type associated with that socket. This approach is best when only a single component of that type exists and is shared amongst Dapr applications. - -```csharp -var app = DaprPluggableComponentsApplication.Create(); - -app.RegisterService( - "service-a", - serviceBuilder => - { - serviceBuilder.RegisterStateStore(); - }); - -app.Run(); - -class SingletonStateStore : IStateStore -{ - // ... -} -``` - -## Multi-instance components - -Components can be registered by passing a "factory method". This method will be called for each configured component of that type associated with that socket. The method returns the instance to associate with that component (whether shared or not). This approach is best when multiple components of the same type may be configured with different sets of metadata, when component operations need to be isolated from one another, etc. - -The factory method will be passed context, such as the ID of the configured Dapr component, that can be used to differentiate component instances. - -```csharp -var app = DaprPluggableComponentsApplication.Create(); - -app.RegisterService( - "service-a", - serviceBuilder => - { - serviceBuilder.RegisterStateStore( - context => - { - return new MultiStateStore(context.InstanceId); - }); - }); - -app.Run(); - -class MultiStateStore : IStateStore -{ - private readonly string instanceId; - - public MultiStateStore(string instanceId) - { - this.instanceId = instanceId; - } - - // ... -} -``` - -## Next steps - -- [Learn more about the application environment]({{% ref "dotnet-application-environment" %}}) -- [Learn more about multiple services]({{% ref "dotnet-multiple-services" %}}) -- Learn more about using the Pluggable Component .NET SDK for: - - [Bindings]({{% ref "dotnet-bindings" %}}) - - [Pub/sub]({{% ref "dotnet-pub-sub" %}}) - - [State store]({{% ref "dotnet-state-store" %}}) \ No newline at end of file diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-multiple-services.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-multiple-services.md deleted file mode 100644 index c5ea6a5..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-advanced/dotnet-multiple-services.md +++ /dev/null @@ -1,98 +0,0 @@ ---- -type: docs -title: "Multiple services in a .NET Dapr pluggable component" -linkTitle: "Multiple services" -weight: 1000 -description: How to expose multiple services from a .NET pluggable component -no_list: true -is_preview: true ---- - -A pluggable component can host multiple components of varying types. You might do this: -- To minimize the number of sidecars running in a cluster -- To group related components that are likely to share libraries and implementation, such as: - - A database exposed both as a general state store, and - - Output bindings that allow more specific operations. - -Each Unix Domain Socket can manage calls to one component of each type. To host multiple components of the _same_ type, you can spread those types across multiple sockets. The SDK binds each socket to a "service", with each service composed of one or more component types. - -## Registering multiple services - -Each call to `RegisterService()` binds a socket to a set of registered components, where one of each type of component can be registered per service. - -```csharp -var app = DaprPluggableComponentsApplication.Create(); - -app.RegisterService( - "service-a", - serviceBuilder => - { - serviceBuilder.RegisterStateStore(); - serviceBuilder.RegisterBinding(); - }); - -app.RegisterService( - "service-b", - serviceBuilder => - { - serviceBuilder.RegisterStateStore(); - }); - -app.Run(); - -class MyDatabaseStateStore : IStateStore -{ - // ... -} - -class MyDatabaseOutputBinding : IOutputBinding -{ - // ... -} - -class AnotherStateStore : IStateStore -{ - // ... -} -``` - -## Configuring Multiple Components - -Configuring Dapr to use the hosted components is the same as for any single component - the component YAML refers to the associated socket. - -```yaml -# -# This component uses the state store associated with socket `state-store-a` -# -apiVersion: dapr.io/v1alpha1 -kind: Component -metadata: - name: state-store-a -spec: - type: state.service-a - version: v1 - metadata: [] -``` - -```yaml -# -# This component uses the state store associated with socket `state-store-b` -# -apiVersion: dapr.io/v1alpha1 -kind: Component -metadata: - name: state-store-b -spec: - type: state.service-b - version: v1 - metadata: [] -``` - -## Next steps - -- [Learn more about the component lifetime]({{% ref "dotnet-component-lifetime" %}}) -- [Learn more about the application environment]({{% ref "dotnet-application-environment" %}}) -- Learn more about using the Pluggable Component .NET SDK for: - - [Bindings]({{% ref "dotnet-bindings" %}}) - - [Pub/sub]({{% ref "dotnet-pub-sub" %}}) - - [State store]({{% ref "dotnet-state-store" %}}) \ No newline at end of file diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-bindings/_index.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-bindings/_index.md deleted file mode 100644 index b7d1219..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-bindings/_index.md +++ /dev/null @@ -1,139 +0,0 @@ ---- -type: docs -title: "Implementing a .NET input/output binding component" -linkTitle: "Bindings" -weight: 1000 -description: How to create an input/output binding with the Dapr pluggable components .NET SDK -no_list: true -is_preview: true ---- - -Creating a binding component requires just a few basic steps. - -## Add bindings namespaces - -Add `using` statements for the bindings related namespaces. - -```csharp -using Dapr.PluggableComponents.Components; -using Dapr.PluggableComponents.Components.Bindings; -``` - -## Input bindings: Implement `IInputBinding` - -Create a class that implements the `IInputBinding` interface. - -```csharp -internal sealed class MyBinding : IInputBinding -{ - public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) - { - // Called to initialize the component with its configured metadata... - } - - public async Task ReadAsync(MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default) - { - // Until canceled, check the underlying store for messages and deliver them to the Dapr runtime... - } -} -``` - -Calls to the `ReadAsync()` method are "long-lived", in that the method is not expected to return until canceled (for example, via the `cancellationToken`). As messages are read from the underlying store of the component, they are delivered to the Dapr runtime via the `deliveryHandler` callback. Delivery allows the component to receive notification if/when the application (served by the Dapr runtime) acknowledges processing of the message. - -```csharp - public async Task ReadAsync(MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default) - { - TimeSpan pollInterval = // Polling interval (e.g. from initalization metadata)... - - // Poll the underlying store until canceled... - while (!cancellationToken.IsCancellationRequested) - { - var messages = // Poll underlying store for messages... - - foreach (var message in messages) - { - // Deliver the message to the Dapr runtime... - await deliveryHandler( - new InputBindingReadResponse - { - // Set the message content... - }, - // Callback invoked when application acknowledges the message... - async request => - { - // Process response data or error message... - }) - } - - // Wait for the next poll (or cancellation)... - await Task.Delay(pollInterval, cancellationToken); - } - } -``` - -## Output bindings: Implement `IOutputBinding` - -Create a class that implements the `IOutputBinding` interface. - -```csharp -internal sealed class MyBinding : IOutputBinding -{ - public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) - { - // Called to initialize the component with its configured metadata... - } - - public Task InvokeAsync(OutputBindingInvokeRequest request, CancellationToken cancellationToken = default) - { - // Called to invoke a specific operation... - } - - public Task ListOperationsAsync(CancellationToken cancellationToken = default) - { - // Called to list the operations that can be invoked. - } -} -``` - -## Input and output binding components - -A component can be _both_ an input _and_ output binding, simply by implementing both interfaces. - -```csharp -internal sealed class MyBinding : IInputBinding, IOutputBinding -{ - // IInputBinding Implementation... - - // IOutputBinding Implementation... -} -``` - -## Register binding component - -In the main program file (for example, `Program.cs`), register the binding component in an application service. - -```csharp -using Dapr.PluggableComponents; - -var app = DaprPluggableComponentsApplication.Create(); - -app.RegisterService( - "", - serviceBuilder => - { - serviceBuilder.RegisterBinding(); - }); - -app.Run(); -``` - -{{% alert title="Note" color="primary" %}} -A component that implements both `IInputBinding` and `IOutputBinding` will be registered as both an input and output binding. -{{% /alert %}} - -## Next steps - -- [Learn advanced steps for the Pluggable Component .NET SDK]({{% ref "dotnet-advanced" %}}) -- Learn more about using the Pluggable Component .NET SDK for: - - [Pub/sub]({{% ref "dotnet-pub-sub" %}}) - - [State store]({{% ref "dotnet-state-store" %}}) \ No newline at end of file diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-pub-sub/_index.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-pub-sub/_index.md deleted file mode 100644 index 8120a8e..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-pub-sub/_index.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -type: docs -title: "Implementing a .NET pub/sub component" -linkTitle: "Pub/sub" -weight: 1000 -description: How to create a pub/sub with the Dapr pluggable components .NET SDK -no_list: true -is_preview: true ---- - -Creating a pub/sub component requires just a few basic steps. - -## Add pub/sub namespaces - -Add `using` statements for the pub/sub related namespaces. - -```csharp -using Dapr.PluggableComponents.Components; -using Dapr.PluggableComponents.Components.PubSub; -``` - -## Implement `IPubSub` - -Create a class that implements the `IPubSub` interface. - -```csharp -internal sealed class MyPubSub : IPubSub -{ - public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) - { - // Called to initialize the component with its configured metadata... - } - - public Task PublishAsync(PubSubPublishRequest request, CancellationToken cancellationToken = default) - { - // Send the message to the "topic"... - } - - public Task PullMessagesAsync(PubSubPullMessagesTopic topic, MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default) - { - // Until canceled, check the topic for messages and deliver them to the Dapr runtime... - } -} -``` - -Calls to the `PullMessagesAsync()` method are "long-lived", in that the method is not expected to return until canceled (for example, via the `cancellationToken`). The "topic" from which messages should be pulled is passed via the `topic` argument, while the delivery to the Dapr runtime is performed via the `deliveryHandler` callback. Delivery allows the component to receive notification if/when the application (served by the Dapr runtime) acknowledges processing of the message. - -```csharp - public async Task PullMessagesAsync(PubSubPullMessagesTopic topic, MessageDeliveryHandler deliveryHandler, CancellationToken cancellationToken = default) - { - TimeSpan pollInterval = // Polling interval (e.g. from initalization metadata)... - - // Poll the topic until canceled... - while (!cancellationToken.IsCancellationRequested) - { - var messages = // Poll topic for messages... - - foreach (var message in messages) - { - // Deliver the message to the Dapr runtime... - await deliveryHandler( - new PubSubPullMessagesResponse(topicName) - { - // Set the message content... - }, - // Callback invoked when application acknowledges the message... - async errorMessage => - { - // An empty message indicates the application successfully processed the message... - if (String.IsNullOrEmpty(errorMessage)) - { - // Delete the message from the topic... - } - }) - } - - // Wait for the next poll (or cancellation)... - await Task.Delay(pollInterval, cancellationToken); - } - } -``` - -## Register pub/sub component - -In the main program file (for example, `Program.cs`), register the pub/sub component with an application service. - -```csharp -using Dapr.PluggableComponents; - -var app = DaprPluggableComponentsApplication.Create(); - -app.RegisterService( - "", - serviceBuilder => - { - serviceBuilder.RegisterPubSub(); - }); - -app.Run(); -``` - -## Next steps - -- [Learn advanced steps for the Pluggable Component .NET SDK]({{% ref "dotnet-advanced" %}}) -- Learn more about using the Pluggable Component .NET SDK for: - - [Bindings]({{% ref "dotnet-bindings" %}}) - - [State store]({{% ref "dotnet-state-store" %}}) \ No newline at end of file diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-state-store/_index.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-state-store/_index.md deleted file mode 100644 index acef4c5..0000000 --- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-state-store/_index.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -type: docs -title: "Implementing a .NET state store component" -linkTitle: "State Store" -weight: 1000 -description: How to create a state store with the Dapr pluggable components .NET SDK -no_list: true -is_preview: true ---- - -Creating a state store component requires just a few basic steps. - -## Add state store namespaces - -Add `using` statements for the state store related namespaces. - -```csharp -using Dapr.PluggableComponents.Components; -using Dapr.PluggableComponents.Components.StateStore; -``` - -## Implement `IStateStore` - -Create a class that implements the `IStateStore` interface. - -```csharp -internal sealed class MyStateStore : IStateStore -{ - public Task DeleteAsync(StateStoreDeleteRequest request, CancellationToken cancellationToken = default) - { - // Delete the requested key from the state store... - } - - public Task GetAsync(StateStoreGetRequest request, CancellationToken cancellationToken = default) - { - // Get the requested key value from from the state store, else return null... - } - - public Task InitAsync(MetadataRequest request, CancellationToken cancellationToken = default) - { - // Called to initialize the component with its configured metadata... - } - - public Task SetAsync(StateStoreSetRequest request, CancellationToken cancellationToken = default) - { - // Set the requested key to the specified value in the state store... - } -} -``` - -## Register state store component - -In the main program file (for example, `Program.cs`), register the state store with an application service. - -```csharp -using Dapr.PluggableComponents; - -var app = DaprPluggableComponentsApplication.Create(); - -app.RegisterService( - "", - serviceBuilder => - { - serviceBuilder.RegisterStateStore(); - }); - -app.Run(); -``` - -## Bulk state stores - -State stores that intend to support bulk operations should implement the optional `IBulkStateStore` interface. Its methods mirror those of the base `IStateStore` interface, but include multiple requested values. - -{{% alert title="Note" color="primary" %}} -The Dapr runtime will emulate bulk state store operations for state stores that do _not_ implement `IBulkStateStore` by calling its operations individually. -{{% /alert %}} - -```csharp -internal sealed class MyStateStore : IStateStore, IBulkStateStore -{ - // ... - - public Task BulkDeleteAsync(StateStoreDeleteRequest[] requests, CancellationToken cancellationToken = default) - { - // Delete all of the requested values from the state store... - } - - public Task BulkGetAsync(StateStoreGetRequest[] requests, CancellationToken cancellationToken = default) - { - // Return the values of all of the requested values from the state store... - } - - public Task BulkSetAsync(StateStoreSetRequest[] requests, CancellationToken cancellationToken = default) - { - // Set all of the values of the requested keys in the state store... - } -} -``` - -## Transactional state stores - -State stores that intend to support transactions should implement the optional `ITransactionalStateStore` interface. Its `TransactAsync()` method is passed a request with a sequence of delete and/or set operations to be performed within a transaction. The state store should iterate over the sequence and call each operation's `Visit()` method, passing callbacks that represent the action to take for each type of operation. - -```csharp -internal sealed class MyStateStore : IStateStore, ITransactionalStateStore -{ - // ... - - public async Task TransactAsync(StateStoreTransactRequest request, CancellationToken cancellationToken = default) - { - // Start transaction... - - try - { - foreach (var operation in request.Operations) - { - await operation.Visit( - async deleteRequest => - { - // Process delete request... - - }, - async setRequest => - { - // Process set request... - }); - } - } - catch - { - // Rollback transaction... - - throw; - } - - // Commit transaction... - } -} -``` - -## Queryable state stores - -State stores that intend to support queries should implement the optional `IQueryableStateStore` interface. Its `QueryAsync()` method is passed details about the query, such as the filter(s), result limits and pagination, and sort order(s) of the results. The state store should use those details to generate a set of values to return as part of its response. - -```csharp -internal sealed class MyStateStore : IStateStore, IQueryableStateStore -{ - // ... - - public Task QueryAsync(StateStoreQueryRequest request, CancellationToken cancellationToken = default) - { - // Generate and return results... - } -} -``` - -## ETag and other semantic error handling - -The Dapr runtime has additional handling of certain error conditions resulting from some state store operations. State stores can indicate such conditions by throwing specific exceptions from its operation logic: - -| Exception | Applicable Operations | Description -|---|---|---| -| `ETagInvalidException` | Delete, Set, Bulk Delete, Bulk Set | When an ETag is invalid | -| `ETagMismatchException`| Delete, Set, Bulk Delete, Bulk Set | When an ETag does not match an expected value | -| `BulkDeleteRowMismatchException` | Bulk Delete | When the number of affected rows does not match the expected rows | - -## Next steps - -- [Learn advanced steps for the Pluggable Component .NET SDK]({{% ref "dotnet-advanced" %}}) -- Learn more about using the Pluggable Component .NET SDK for: - - [Bindings]({{% ref "dotnet-bindings" %}}) - - [Pub/sub]({{% ref "dotnet-pub-sub" %}}) \ No newline at end of file