diff --git a/.github/workflows/itests.yml b/.github/workflows/itests.yml
index 0c96fa9c..b79edfab 100644
--- a/.github/workflows/itests.yml
+++ b/.github/workflows/itests.yml
@@ -5,6 +5,8 @@ on:
branches:
- master
- release-*
+ - dev-*
+ - feature-*
tags:
- v*
@@ -12,6 +14,8 @@ on:
branches:
- master
- release-*
+ - dev-*
+ - feature-*
jobs:
build:
@@ -20,18 +24,8 @@ jobs:
strategy:
fail-fast: false
matrix:
- dotnet-version: ['6.0', '7.0', '8.0', '9.0']
+ dotnet-version: ['8.0', '9.0']
include:
- - dotnet-version: '6.0'
- display-name: '.NET 6.0'
- framework: 'net6'
- prefix: 'net6'
- install-version: '6.0.x'
- - dotnet-version: '7.0'
- display-name: '.NET 7.0'
- framework: 'net7'
- prefix: 'net7'
- install-version: '7.0.x'
- dotnet-version: '8.0'
display-name: '.NET 8.0'
framework: 'net8'
@@ -50,7 +44,7 @@ jobs:
GOPROXY: https://proxy.golang.org
DAPR_CLI_VER: 1.15.0
DAPR_RUNTIME_VER: 1.15.3
- DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/release-1.14/install/install.sh
+ DAPR_INSTALL_URL: https://raw.githubusercontent.com/dapr/cli/release-1.15/install/install.sh
DAPR_CLI_REF: ''
steps:
- name: Set up Dapr CLI
@@ -124,10 +118,12 @@ jobs:
with:
dotnet-version: '9.0.x'
dotnet-quality: 'ga'
+ - name: Restore dependencies
+ run: dotnet restore
- name: Build
# disable deterministic builds, just for test run. Deterministic builds break coverage for some reason
- run: dotnet build --configuration release /p:GITHUB_ACTIONS=false
- - name: Run General Tests
+ run: dotnet build --configuration release --no-restore /p:GITHUB_ACTIONS=false
+ - name: Run General Integration Tests
id: tests
continue-on-error: true # proceed if tests fail, the report step will report the failure with more details.
run: |
@@ -142,7 +138,7 @@ jobs:
/p:CollectCoverage=true \
/p:CoverletOutputFormat=opencover \
/p:GITHUB_ACTIONS=false
- - name: Run Generators Tests
+ - name: Run Generators Integration Tests
id: generator-tests
continue-on-error: true # proceed if tests fail, the report step will report the failure with more details.
run: |
diff --git a/.github/workflows/sdk_build.yml b/.github/workflows/sdk_build.yml
index b6e26353..327bba43 100644
--- a/.github/workflows/sdk_build.yml
+++ b/.github/workflows/sdk_build.yml
@@ -5,6 +5,8 @@ on:
branches:
- master
- release-*
+ - dev-*
+ - feature-*
tags:
- v*
@@ -12,6 +14,13 @@ on:
branches:
- master
- release-*
+ - dev-*
+ - feature-*
+
+ workflow_run:
+ workflows: [ "integration-test" ]
+ types:
+ - completed
jobs:
build:
@@ -28,8 +37,10 @@ jobs:
with:
dotnet-version: 9.0.x
dotnet-quality: 'ga'
+ - name: Restore dependencies
+ run: dotnet restore
- name: Build
- run: dotnet build --configuration release
+ run: dotnet build --configuration release --no-restore
- name: Generate Packages
run: dotnet pack --configuration release
- name: Upload packages
@@ -44,18 +55,8 @@ jobs:
strategy:
fail-fast: false
matrix:
- dotnet-version: ['6.0', '7.0', '8.0', '9.0']
+ dotnet-version: ['8.0', '9.0']
include:
- - dotnet-version: '6.0'
- display-name: '.NET 6.0'
- framework: 'net6'
- prefix: 'net6'
- install-version: '6.0.x'
- - dotnet-version: '7.0'
- display-name: '.NET 7.0'
- framework: 'net7'
- prefix: 'net7'
- install-version: '7.0.x'
- dotnet-version: '8.0'
display-name: '.NET 8.0'
framework: 'net8'
@@ -125,7 +126,11 @@ jobs:
name: Publish Packages
needs: ['build', 'test']
runs-on: ubuntu-latest
- if: startswith(github.ref, 'refs/tags/v') && !(endsWith(github.ref, '-rc') || endsWith(github.ref, '-dev') || endsWith(github.ref, '-prerelease'))
+ # Only run this job if workflow_run was successful and we're on a tag
+ if: |
+ (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success') &&
+ startswith(github.ref, 'refs/tags/v') &&
+ !(endsWith(github.ref, '-rc') || endsWith(github.ref, '-dev') || endsWith(github.ref, '-prerelease'))
steps:
- name: Download release artifacts
uses: actions/download-artifact@v4
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 7712340a..041f58f6 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -54,13 +54,13 @@ This section describes the guidelines for contributing code / docs to Dapr.
All contributions come through pull requests. To submit a proposed change, we recommend following this workflow:
1. Make sure there's an issue (bug or proposal) raised, which sets the expectations for the contribution you are about to make.
-1. Fork the relevant repo and create a new branch
-1. Create your change
+2. Fork the relevant repo and create a new branch
+3. Create your change
- Code changes require tests
-1. Update relevant documentation for the change
-1. Commit and open a PR
-1. Wait for the CI process to finish and make sure all checks are green
-1. A maintainer of the project will be assigned, and you can expect a review within a few days
+4. Update relevant documentation for the change
+5. Commit and open a PR
+6. Wait for the CI process to finish and make sure all checks are green
+7. A maintainer of the project will be assigned, and you can expect a review within a few days
#### Use work-in-progress PRs for early feedback
diff --git a/Directory.Packages.props b/Directory.Packages.props
index f4f67b8e..9d95af64 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -4,49 +4,53 @@
true
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 948516fe..faec504b 100644
--- a/README.md
+++ b/README.md
@@ -44,12 +44,21 @@ This repo builds the following packages:
- Dapr.AspNetCore
- Dapr.Actors
- Dapr.Actors.AspNetCore
+- Dapr.Actors.Generators
+- Dapr.AI
+- Dapr.Jobs
+- Dapr.Messaging
- Dapr.Extensions.Configuration
- Dapr.Workflow
+It also builds the following packages which are not intended for public use and contain common types used in the packages above:
+- Dapr.Common
+- Dapr.Protos
+
+
### Prerequisites
-Each project is a normal C# project. At minimum, you need [.NET 6.0 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) to build, test, and generate NuGet packages.
+Each project is a normal C# project. At minimum, you need [.NET 8.0 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) to build, test, and generate NuGet packages.
Also make sure to reference the [.NET SDK contribution guide](https://docs.dapr.io/contributing/sdk-contrib/dotnet-contributing/)
@@ -59,7 +68,7 @@ On macOS or Linux we recommend [Visual Studio Code](https://code.visualstudio.co
**Windows:**
-On Windows, we recommend installing [the latest Visual Studio 2019](https://www.visualstudio.com/vs/) which will set you up with all the .NET build tools and allow you to open the solution files. Community Edition is free and can be used to build everything here.
+On Windows, we recommend installing [the latest Visual Studio 2022](https://www.visualstudio.com/vs/) which will set you up with all the .NET build tools and allow you to open the solution files. Community Edition is free and can be used to build everything here.
Make sure you [update Visual Studio to the most recent release](https://docs.microsoft.com/visualstudio/install/update-visual-studio).
diff --git a/all.sln b/all.sln
index 9a163b1d..9e19c7cf 100644
--- a/all.sln
+++ b/all.sln
@@ -54,7 +54,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControllerSample", "example
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Actor", "Actor", "{02374BD0-BF0B-40F8-A04A-C4C4D61D4992}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IDemoActor", "examples\Actor\IDemoActor\IDemoActor.csproj", "{7957E852-1291-4FAA-9034-FB66CE817FF1}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoActor.Interfaces", "examples\Actor\DemoActor.Interfaces\DemoActor.Interfaces.csproj", "{7957E852-1291-4FAA-9034-FB66CE817FF1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DemoActor", "examples\Actor\DemoActor\DemoActor.csproj", "{626D74DD-4F37-4F74-87A3-5A6888684F5E}"
EndProject
@@ -111,8 +111,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapr.Actors.Generators.Test
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dapr.E2E.Test.Actors.Generators", "test\Dapr.E2E.Test.Actors.Generators\Dapr.E2E.Test.Actors.Generators.csproj", "{B5CDB0DC-B26D-48F1-B934-FE5C1C991940}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cryptography", "examples\Client\Cryptography\Cryptography.csproj", "{C74FBA78-13E8-407F-A173-4555AEE41FF3}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Protos", "src\Dapr.Protos\Dapr.Protos.csproj", "{DFBABB04-50E9-42F6-B470-310E1B545638}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Common", "src\Dapr.Common\Dapr.Common.csproj", "{B445B19C-A925-4873-8CB7-8317898B6970}"
@@ -143,8 +141,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Messaging.Test", "test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Messaging", "src\Dapr.Messaging\Dapr.Messaging.csproj", "{0EAE36A1-B578-4F13-A113-7A477ECA1BDA}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamingSubscriptionExample", "examples\Client\PublishSubscribe\StreamingSubscriptionExample\StreamingSubscriptionExample.csproj", "{290D1278-F613-4DF3-9DF5-F37E38CDC363}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs", "src\Dapr.Jobs\Dapr.Jobs.csproj", "{C8BB6A85-A7EA-40C0-893D-F36F317829B3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Test", "test\Dapr.Jobs.Test\Dapr.Jobs.Test.csproj", "{BF9828E9-5597-4D42-AA6E-6E6C12214204}"
@@ -155,6 +151,48 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JobsSample", "examples\Jobs
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Test", "test\Dapr.Workflow.Test\Dapr.Workflow.Test.csproj", "{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Analyzers", "src\Dapr.Workflow.Analyzers\Dapr.Workflow.Analyzers.csproj", "{55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Workflow.Analyzers.Test", "test\Dapr.Workflow.Analyzers.Test\Dapr.Workflow.Analyzers.Test.csproj", "{CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzers", "src\Dapr.Jobs.Analyzer\Dapr.Jobs.Analyzers.csproj", "{28B87C37-4B52-400F-B84D-64F134931BDC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Jobs.Analyzers.Test", "test\Dapr.Jobs.Analyzer.Test\Dapr.Jobs.Analyzers.Test.csproj", "{CADEAE45-8981-4723-B641-9C28251C7D3B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Actors.Analyzers", "src\Dapr.Actors.Analyzers\Dapr.Actors.Analyzers\Dapr.Actors.Analyzers.csproj", "{E49C822C-E921-48DF-897B-3E603CA596D2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Actors.Analyzers.Test", "test\Dapr.Actors.Analyzers.Test\Dapr.Actors.Analyzers.Test.csproj", "{A2C0F203-11FF-4B7F-A94F-B9FD873573FE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Analyzers.Common", "test\Dapr.Analyzers.Common\Dapr.Analyzers.Common.csproj", "{7E23E229-6823-4D84-AF3A-AE14CEAEF52A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Cryptography", "src\Dapr.Cryptography\Dapr.Cryptography.csproj", "{160EFFA0-F6B9-49E4-B62B-68C0D53DB425}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dapr.Cryptography.Test", "test\Dapr.Cryptography.Test\Dapr.Cryptography.Test.csproj", "{B508EBD6-0F14-480C-A446-45A09052733B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StreamingSubscriptionExample", "examples\Messaging\StreamingSubscriptionExample\StreamingSubscriptionExample.csproj", "{E070F694-335D-4D96-8951-F41D0A5F2A8B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Cryptography", "Cryptography", "{6843B5B3-9E95-4022-B792-8A1DE6BFEFEC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cryptography", "examples\Cryptography\Cryptography.csproj", "{097D5F6F-D26F-4BFB-9074-FA52577EB442}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Messaging", "Messaging", "{442E80E5-8040-4123-B88A-26FD36BA95D9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkflowParallelFanOut", "examples\Workflow\WorkflowParallelFanOut\WorkflowParallelFanOut.csproj", "{5764B1AA-66B8-43AE-9E0D-0B3B71714B92}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Hosting", "Hosting", "{953D770B-2DE8-4D1B-B1D4-ED46F4F5F31A}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Aspire", "Aspire", "{55E08C7F-81C8-4D0B-AB18-87C89B261477}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackendApp", "examples\Hosting\Aspire\ServiceInvocationDemo\BackendApp\BackendApp.csproj", "{3553BE3C-C188-460A-AC4C-D3D82DC0922A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontendApp", "examples\Hosting\Aspire\ServiceInvocationDemo\FrontendApp\FrontendApp.csproj", "{A6AA3F39-AB3E-4475-B3E2-D53549CBDA49}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceInvocationDemo.AppHost", "examples\Hosting\Aspire\ServiceInvocationDemo\ServiceInvocationDemo.AppHost\ServiceInvocationDemo.AppHost.csproj", "{97A47B0B-9D3B-4CF0-A62C-650F2F211A59}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServiceInvocationDemo.ServiceDefaults", "examples\Hosting\Aspire\ServiceInvocationDemo\ServiceInvocationDemo.ServiceDefaults\ServiceInvocationDemo.ServiceDefaults.csproj", "{5BB15C36-BAF7-44F6-BF85-C533B8B47862}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Common", "examples\Hosting\Aspire\ServiceInvocationDemo\Common\Common.csproj", "{6CD90C22-0F79-4D61-8DCE-5BE22C1304C4}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -403,6 +441,74 @@ Global
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {55A7D436-CC8C-47E6-B43A-DFE32E0FE38C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539}.Release|Any CPU.Build.0 = Release|Any CPU
+ {28B87C37-4B52-400F-B84D-64F134931BDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {28B87C37-4B52-400F-B84D-64F134931BDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {28B87C37-4B52-400F-B84D-64F134931BDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {28B87C37-4B52-400F-B84D-64F134931BDC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CADEAE45-8981-4723-B641-9C28251C7D3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CADEAE45-8981-4723-B641-9C28251C7D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CADEAE45-8981-4723-B641-9C28251C7D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CADEAE45-8981-4723-B641-9C28251C7D3B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E49C822C-E921-48DF-897B-3E603CA596D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E49C822C-E921-48DF-897B-3E603CA596D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E49C822C-E921-48DF-897B-3E603CA596D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E49C822C-E921-48DF-897B-3E603CA596D2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A2C0F203-11FF-4B7F-A94F-B9FD873573FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A2C0F203-11FF-4B7F-A94F-B9FD873573FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A2C0F203-11FF-4B7F-A94F-B9FD873573FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A2C0F203-11FF-4B7F-A94F-B9FD873573FE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7E23E229-6823-4D84-AF3A-AE14CEAEF52A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {160EFFA0-F6B9-49E4-B62B-68C0D53DB425}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B508EBD6-0F14-480C-A446-45A09052733B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B508EBD6-0F14-480C-A446-45A09052733B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B508EBD6-0F14-480C-A446-45A09052733B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B508EBD6-0F14-480C-A446-45A09052733B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E070F694-335D-4D96-8951-F41D0A5F2A8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E070F694-335D-4D96-8951-F41D0A5F2A8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E070F694-335D-4D96-8951-F41D0A5F2A8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E070F694-335D-4D96-8951-F41D0A5F2A8B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {097D5F6F-D26F-4BFB-9074-FA52577EB442}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {097D5F6F-D26F-4BFB-9074-FA52577EB442}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {097D5F6F-D26F-4BFB-9074-FA52577EB442}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {097D5F6F-D26F-4BFB-9074-FA52577EB442}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5764B1AA-66B8-43AE-9E0D-0B3B71714B92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5764B1AA-66B8-43AE-9E0D-0B3B71714B92}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5764B1AA-66B8-43AE-9E0D-0B3B71714B92}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5764B1AA-66B8-43AE-9E0D-0B3B71714B92}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3553BE3C-C188-460A-AC4C-D3D82DC0922A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3553BE3C-C188-460A-AC4C-D3D82DC0922A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3553BE3C-C188-460A-AC4C-D3D82DC0922A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3553BE3C-C188-460A-AC4C-D3D82DC0922A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6AA3F39-AB3E-4475-B3E2-D53549CBDA49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A6AA3F39-AB3E-4475-B3E2-D53549CBDA49}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A6AA3F39-AB3E-4475-B3E2-D53549CBDA49}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A6AA3F39-AB3E-4475-B3E2-D53549CBDA49}.Release|Any CPU.Build.0 = Release|Any CPU
+ {97A47B0B-9D3B-4CF0-A62C-650F2F211A59}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {97A47B0B-9D3B-4CF0-A62C-650F2F211A59}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {97A47B0B-9D3B-4CF0-A62C-650F2F211A59}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {97A47B0B-9D3B-4CF0-A62C-650F2F211A59}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5BB15C36-BAF7-44F6-BF85-C533B8B47862}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5BB15C36-BAF7-44F6-BF85-C533B8B47862}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5BB15C36-BAF7-44F6-BF85-C533B8B47862}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5BB15C36-BAF7-44F6-BF85-C533B8B47862}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6CD90C22-0F79-4D61-8DCE-5BE22C1304C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6CD90C22-0F79-4D61-8DCE-5BE22C1304C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6CD90C22-0F79-4D61-8DCE-5BE22C1304C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6CD90C22-0F79-4D61-8DCE-5BE22C1304C4}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -455,7 +561,6 @@ Global
{7C06FE2D-6C62-48F5-A505-F0D715C554DE} = {7592AFA4-426B-42F3-AE82-957C86814482}
{AF89083D-4715-42E6-93E9-38497D12A8A6} = {DD020B34-460F-455F-8D17-CF4A949F100B}
{B5CDB0DC-B26D-48F1-B934-FE5C1C991940} = {DD020B34-460F-455F-8D17-CF4A949F100B}
- {C74FBA78-13E8-407F-A173-4555AEE41FF3} = {A7F41094-8648-446B-AECD-DCC2CC871F73}
{DFBABB04-50E9-42F6-B470-310E1B545638} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
{B445B19C-A925-4873-8CB7-8317898B6970} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
{CDB47863-BEBD-4841-A807-46D868962521} = {DD020B34-460F-455F-8D17-CF4A949F100B}
@@ -471,12 +576,32 @@ Global
{00359961-0C50-4BB1-A794-8B06DE991639} = {BF3ED6BF-ADF3-4D25-8E89-02FB8D945CA9}
{4E04EB35-7FD2-4FDB-B09A-F75CE24053B9} = {DD020B34-460F-455F-8D17-CF4A949F100B}
{0EAE36A1-B578-4F13-A113-7A477ECA1BDA} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
- {290D1278-F613-4DF3-9DF5-F37E38CDC363} = {0EF6EA64-D7C3-420D-9890-EAE8D54A57E6}
{C8BB6A85-A7EA-40C0-893D-F36F317829B3} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
{BF9828E9-5597-4D42-AA6E-6E6C12214204} = {DD020B34-460F-455F-8D17-CF4A949F100B}
{D9697361-232F-465D-A136-4561E0E88488} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78}
{9CAF360E-5AD3-4C4F-89A0-327EEB70D673} = {D9697361-232F-465D-A136-4561E0E88488}
{E90114C6-86FC-43B8-AE5C-D9273CF21FE4} = {DD020B34-460F-455F-8D17-CF4A949F100B}
+ {55A7D436-CC8C-47E6-B43A-DFE32E0FE38C} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
+ {CE0D5FEB-F6DB-4EB8-B8A9-6A4A32944539} = {DD020B34-460F-455F-8D17-CF4A949F100B}
+ {28B87C37-4B52-400F-B84D-64F134931BDC} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
+ {CADEAE45-8981-4723-B641-9C28251C7D3B} = {DD020B34-460F-455F-8D17-CF4A949F100B}
+ {E49C822C-E921-48DF-897B-3E603CA596D2} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
+ {A2C0F203-11FF-4B7F-A94F-B9FD873573FE} = {DD020B34-460F-455F-8D17-CF4A949F100B}
+ {7E23E229-6823-4D84-AF3A-AE14CEAEF52A} = {DD020B34-460F-455F-8D17-CF4A949F100B}
+ {160EFFA0-F6B9-49E4-B62B-68C0D53DB425} = {27C5D71D-0721-4221-9286-B94AB07B58CF}
+ {B508EBD6-0F14-480C-A446-45A09052733B} = {DD020B34-460F-455F-8D17-CF4A949F100B}
+ {6843B5B3-9E95-4022-B792-8A1DE6BFEFEC} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78}
+ {097D5F6F-D26F-4BFB-9074-FA52577EB442} = {6843B5B3-9E95-4022-B792-8A1DE6BFEFEC}
+ {442E80E5-8040-4123-B88A-26FD36BA95D9} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78}
+ {E070F694-335D-4D96-8951-F41D0A5F2A8B} = {442E80E5-8040-4123-B88A-26FD36BA95D9}
+ {5764B1AA-66B8-43AE-9E0D-0B3B71714B92} = {BF3ED6BF-ADF3-4D25-8E89-02FB8D945CA9}
+ {953D770B-2DE8-4D1B-B1D4-ED46F4F5F31A} = {D687DDC4-66C5-4667-9E3A-FD8B78ECAA78}
+ {55E08C7F-81C8-4D0B-AB18-87C89B261477} = {953D770B-2DE8-4D1B-B1D4-ED46F4F5F31A}
+ {3553BE3C-C188-460A-AC4C-D3D82DC0922A} = {55E08C7F-81C8-4D0B-AB18-87C89B261477}
+ {A6AA3F39-AB3E-4475-B3E2-D53549CBDA49} = {55E08C7F-81C8-4D0B-AB18-87C89B261477}
+ {97A47B0B-9D3B-4CF0-A62C-650F2F211A59} = {55E08C7F-81C8-4D0B-AB18-87C89B261477}
+ {5BB15C36-BAF7-44F6-BF85-C533B8B47862} = {55E08C7F-81C8-4D0B-AB18-87C89B261477}
+ {6CD90C22-0F79-4D61-8DCE-5BE22C1304C4} = {55E08C7F-81C8-4D0B-AB18-87C89B261477}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {65220BF2-EAE1-4CB2-AA58-EBE80768CB40}
diff --git a/daprdocs/content/en/dotnet-sdk-contributing/dotnet-contributing.md b/daprdocs/content/en/dotnet-sdk-contributing/dotnet-contributing.md
index ed7e703c..9e75a092 100644
--- a/daprdocs/content/en/dotnet-sdk-contributing/dotnet-contributing.md
+++ b/daprdocs/content/en/dotnet-sdk-contributing/dotnet-contributing.md
@@ -101,17 +101,8 @@ squashing the PR locally and resubmitting to ensure that the sign-off statement
# Languages, Tools and Processes
All source code in the Dapr .NET SDK is written in C# and targets the latest language version available to the earliest
-supported .NET SDK. As of v1.15, this means that because .NET 6 is still supported, the latest language version available
-is [C# version 10](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-10).
-
-As of v1.15, the following versions of .NET are supported:
-
-| Version | Notes |
-| --- |-----------------------------------------------------------------|
-| .NET 6 | Will be discontinued in v1.16 |
-| .NET 7 | Only supported in Dapr.Workflows, will be discontinued in v1.16 |
-| .NET 8 | Will continue to be supported in v1.16 |
-| .NET 9 | Will continue to be supported in v1.16 |
+supported .NET SDK. As of v1.16, this means that both .NET 8 and .NET 9 are supported. The latest language version available
+is [C# version 12](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-version-history#c-version-12)
Contributors are welcome to use whatever IDE they're most comfortable developing in, but please do not submit
IDE-specific preference files along with your contributions as these will be rejected.
\ No newline at end of file
diff --git a/daprdocs/content/en/dotnet-sdk-docs/_index.md b/daprdocs/content/en/dotnet-sdk-docs/_index.md
index f1ebdea6..6770a877 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/_index.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/_index.md
@@ -16,17 +16,9 @@ Dapr offers a variety of packages to help with the development of .NET applicati
## Prerequisites
-- [Dapr CLI]({{% ref install-dapr-cli.md %}}) installed
-- Initialized [Dapr environment]({{% ref install-dapr-selfhost.md %}})
-- [.NET 6](https://dotnet.microsoft.com/download), [.NET 8](https://dotnet.microsoft.com/download) or [.NET 9](https://dotnet.microsoft.com/download) installed
-
-{{% alert title="Note" color="primary" %}}
-
-Note that while .NET 6 is generally supported as the minimum .NET requirement across the Dapr .NET SDK packages
-and .NET 7 is the minimally supported version of .NET by Dapr.Workflows in Dapr v1.15, only .NET 8 and .NET 9 will
-continue to be supported by Dapr in v1.16 and later.
-
-{{% /alert %}}
+- [Dapr CLI]({{< ref install-dapr-cli.md >}}) installed
+- Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}})
+- [.NET 8](https://dotnet.microsoft.com/download) or [.NET 9](https://dotnet.microsoft.com/download) installed
## Installation
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-howto.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-howto.md
index e868a78d..56ef8f8c 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-howto.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-howto.md
@@ -43,17 +43,9 @@ This project contains the implementation of the actor client which calls MyActor
## Prerequisites
-- [Dapr CLI]({{% ref install-dapr-cli.md %}}) installed.
-- Initialized [Dapr environment]({{% ref install-dapr-selfhost.md %}}).
-- [.NET 6](https://dotnet.microsoft.com/download), [.NET 8](https://dotnet.microsoft.com/download) or [.NET 9](https://dotnet.microsoft.com/download) installed
-
-{{% alert title="Note" color="primary" %}}
-
-Note that while .NET 6 is generally supported as the minimum .NET requirement across the Dapr .NET SDK packages
-and .NET 7 is the minimally supported version of .NET by Dapr.Workflows in Dapr v1.15, only .NET 8 and .NET 9 will
-continue to be supported by Dapr in v1.16 and later.
-
-{{% /alert %}}
+- [Dapr CLI]({{< ref install-dapr-cli.md >}}) installed.
+- Initialized [Dapr environment]({{< ref install-dapr-selfhost.md >}}).
+- [.NET 8](https://dotnet.microsoft.com/download) or [.NET 9](https://dotnet.microsoft.com/download) installed
## Step 0: Prepare
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-serialization.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-serialization.md
index 787a7e41..20271f7b 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-serialization.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-actors/dotnet-actors-serialization.md
@@ -3,7 +3,7 @@ type: docs
title: "Actor serialization in the .NET SDK"
linkTitle: "Actor serialization"
weight: 300000
-description: Necessary steps to serialize your types using remoted Actors in .NET
+description: Necessary steps to serialize your types remoted and non-remoted Actors in .NET
---
# Actor Serialization
@@ -254,6 +254,36 @@ a complex versioning scheme for our existing enum values in the state.
{"event": "Conference", "season": "fall"}
```
+### Polymorphic Serialization
+When working with polymorphic types in Dapr Actor clients, it is essential to handle serialization and deserialization correctly to ensure that the appropriate
+derived types are instantiated. Polymorphic serialization allows you to serialize objects of a base type while preserving the specific derived type information.
+
+To enable polymorphic deserialization, you must use the `[JsonPolymorphic]` attribute on your base type. Additionally,
+it is crucial to include the `[AllowOutOfOrderMetadataProperties]` attribute to ensure that metadata properties, such as `$type`
+can be processed correctly by System.Text.Json even if they are not the first properties in the JSON object.
+
+#### Example
+```cs
+[JsonPolymorphic]
+[AllowOutOfOrderMetadataProperties]
+public abstract class SampleValueBase
+{
+ public string CommonProperty { get; set; }
+}
+
+public class DerivedSampleValue : SampleValueBase
+{
+ public string SpecificProperty { get; set; }
+}
+```
+In this example, the `SampleValueBase` class is marked with both `[JsonPolymorphic]` and `[AllowOutOfOrderMetadataProperties]`
+attributes. This setup ensures that the `$type` metadata property can be correctly identified and processed during
+deserialization, regardless of its position in the JSON object.
+
+By following this approach, you can effectively manage polymorphic serialization and deserialization in your Dapr Actor
+clients, ensuring that the correct derived types are instantiated and used.
+
+
## Strongly-typed Dapr Actor client
In this section, you will learn how to configure your classes and records so they are properly serialized and deserialized at runtime when using a strongly-typed actor client. These clients are implemented using .NET interfaces and are not compatible with Dapr Actors written using other languages.
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-howto.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-howto.md
index 7c8095ba..700b9e6f 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-howto.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-howto.md
@@ -7,17 +7,10 @@ description: Learn how to create and use the Dapr Conversational AI client using
---
## Prerequisites
-- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0), or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
+- [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0), or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost)
-{{% alert title="Note" color="primary" %}}
-
-.NET 6 is supported as the minimum required for the Dapr .NET SDK packages in this release. Only .NET 8 and .NET 9
-will be supported in Dapr v1.16 and later releases.
-
-{{% /alert %}}
-
## Installation
To get started with the Dapr AI .NET SDK client, install the [Dapr.AI package](https://www.nuget.org/packages/Dapr.AI) from NuGet:
@@ -84,7 +77,3 @@ Put the Dapr AI .NET SDK to the test. Walk through the samples to see Dapr in ac
This part of the .NET SDK allows you to interface with the Conversations API to send and receive messages from
large language models.
-
-### Send messages
-
-
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-usage.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-usage.md
index b4917e02..444a59a0 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-usage.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-ai/dotnet-ai-conversation-usage.md
@@ -17,7 +17,7 @@ It maintains access to networking resources in the form of TCP sockets used to c
For best performance, create a single long-lived instance of `DaprConversationClient` and provide access to that shared
instance throughout your application. `DaprConversationClient` instances are thread-safe and intended to be shared.
-This can be aided by utilizing the dependency injection functionality. The registration method supports registration using
+This can be aided by utilizing the dependency injection functionality. The registration method supports registration
as a singleton, a scoped instance or as transient (meaning it's recreated every time it's injected), but also enables
registration to utilize values from an `IConfiguration` or other injected service in a way that's impractical when
creating the client from scratch in each of your classes.
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-client/_index.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-client/_index.md
index b6eb7b07..0f77ae8c 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-client/_index.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-client/_index.md
@@ -40,7 +40,7 @@ using var client = new DaprClientBuilder().
// Invokes a POST method named "deposit" that takes input of type "Transaction"
var data = new { id = "17", amount = 99m };
-var account = await client.InvokeMethodAsync("routing", "deposit", data, cancellationToken);
+var account = await client.InvokeMethodAsync("routing", "deposit", data, cancellationToken);
Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
```
{{% /tab %}}
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-code-analysis/_index.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-code-analysis/_index.md
new file mode 100644
index 00000000..d04ace66
--- /dev/null
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-code-analysis/_index.md
@@ -0,0 +1,82 @@
+---
+type: docs
+title: "Overview of Dapr source code analysis"
+linkTitle: "Code Analysis"
+weight: 70000
+description: Code analyzers and fixes for common Dapr issues
+no_list: true
+---
+
+Dapr supports a growing collection of optional Roslyn analyzers and code fix providers that inspect your code for
+code quality issues. Starting with the release of v1.16, developers have the opportunity to install additional projects
+from NuGet alongside each of the standard capability packages to enable these analyzers in their solutions.
+
+{{% alert title="Note" color="primary" %}}
+
+A future release of the Dapr .NET SDK will include these analyzers by default without necessitating a separate package
+install.
+
+{{% /alert %}}
+
+Rule violations will typically be marked as `Info` or `Warning` so that if the analyzer identifies an issue, it won't
+necessarily break builds. All code analysis violations appear with the prefix "DAPR" and are uniquely distinguished
+by a number following this prefix.
+
+{{% alert title="Note" color="primary" %}}
+
+At this time, the first two digits of the diagnostic identifier map one-to-one to distinct Dapr packages, but this
+is subject to change in the future as more analyzers are developed.
+
+{{% /alert %}}
+
+## Install and configure analyzers
+The following packages will be available via NuGet following the v1.16 Dapr release:
+- Dapr.Actors.Analyzers
+- Dapr.Jobs.Analyzers
+- Dapr.Workflow.Analyzers
+
+Install each NuGet package on every project where you want the analyzers to run. The package will be installed as a
+project dependency and analyzers will run as you write your code or as part of a CI/CD build. The analyzers will flag
+issues in your existing code and warn you about new issues as you build your project.
+
+Many of our analyzers have associated code fixes that can be applied to automatically correct the problem. If your IDE
+supports this capability, any available code fixes will show up as an inline menu option in your code.
+
+Further, most of our analyzers should also report a specific line and column number in your code of the syntax that's
+been identified as a key aspect of the rule. If your IDE supports it, double clicking any of the analyzer warnings
+should jump directly to the part of your code responsible for the violating the analyzer's rule.
+
+### Suppress specific analyzers
+If you wish to keep an analyzer from firing against some particular piece of your project, their outputs can be
+individually targeted for suppression through a number of ways. Read more about suppressing analyzers in projects
+or files in the associated [.NET documentation](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/suppress-warnings#use-the-suppressmessageattribute).
+
+### Disable all analyzers
+If you wish to disable all analyzers in your project without removing any packages providing them, set
+the `EnableNETAnalyzers` property to `false` in your csproj file.
+
+## Available Analyzers
+
+| Diagnostic ID | Dapr Package | Category | Severity | Version Added | Description | Code Fix Available |
+| -- | -- |------------------|--------------|-----------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------| -- |
+| DAPR1301 | Dapr.Workflow | Usage | Warning | 1.16 | The workflow type is not registered with the dependency injection provider | Yes |
+| DAPR1302 | Dapr.Workflow | Usage | Warning | 1.16 | The workflow activity type is not registered with the dependency injection provider | Yes |
+| DAPR1401 | Dapr.Actors | Usage | Warning | 1.16 | Actor timer method invocations require the named callback method to exist on type | No |
+| DAPR1402 | Dapr.Actors | Usage | Warning | The actor type is not registered with dependency injection | Yes |
+| DAPR1403 | Dapr.Actors | Interoperability | Info | Set options.UseJsonSerialization to true to support interoperability with non-.NET actors | Yes |
+| DAPR1404 | Dapr.Actors | Usage | Warning | Call app.MapActorsHandlers to map endpoints for Dapr actors | Yes |
+| DAPR1501 | Dapr.Jobs | Usage | Warning | Job invocations require the MapDaprScheduledJobHandler to be set and configured for each anticipated job on IEndpointRouteBuilder | No |
+
+## Analyzer Categories
+The following are each of the eligible categories that an analyzer can be assigned to and are modeled after the
+standard categories used by the.NET analyzers:
+- Design
+- Documentation
+- Globalization
+- Interoperability
+- Maintainability
+- Naming
+- Performance
+- Reliability
+- Security
+- Usage
\ No newline at end of file
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/_index.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/_index.md
new file mode 100644
index 00000000..3fe574f1
--- /dev/null
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/_index.md
@@ -0,0 +1,12 @@
+---
+type: docs
+title: "Dapr Cryptography .NET SDK"
+linkTitle: "Cryptography"
+weight: 51000
+description: Get up and running with the Dapr Cryptography .NET SDK
+---
+
+With the Dapr Cryptography package, you can perform high-performance encryption and decryption operations with Dapr.
+
+To get started with this functionality, walk through the [Dapr Cryptography({{< ref dotnet-cryptography-howto.md >}})
+how-to guide.
\ No newline at end of file
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/dotnet-cryptography-howto.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/dotnet-cryptography-howto.md
new file mode 100644
index 00000000..1bf4f20f
--- /dev/null
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/dotnet-cryptography-howto.md
@@ -0,0 +1,74 @@
+---
+type: docs
+title: "How to: Create an use Dapr Cryptography in the .NET SDK"
+linkTitle: "How to: Use the Cryptography client"
+weight: 510100
+description: Learn how to create and use the Dapr Cryptography client using the .NET SDK
+---
+
+## Prerequisites
+- [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0), or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
+- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
+- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost)
+
+## Installation
+To get started with the Dapr Cryptography client, install the [Dapr.Cryptography package](https://www.nuget.org/packages/Dapr.Cryptography) from NuGet:
+```sh
+dotnet add package Dapr.Cryptography
+```
+
+A `DaprEncryptionClient` maintains access to networking resources in the form of TCP sockets used to communicate with
+the Dapr sidecar.
+
+### Dependency Injection
+
+The `AddDaprEncryptionClient()` method will register the Dapr client with dependency injection and is the recommended approach
+for using this package. This method accepts an optional options delegate for configuring the `DaprEncryptionClient` and a
+`ServiceLifetime` argument, allowing you to specify a different lifetime for the registered services instead of the default `Singleton`
+value.
+
+The following example assumes all default values are acceptable and is sufficient to register the `DaprEncryptionClient`:
+
+```csharp
+services.AddDaprEncryptionClient();
+```
+
+The optional configuration delegate is used to configure the `DaprEncryptionClient` by specifying options on the
+`DaprEncryptionClientBuilder` as in the following example:
+```csharp
+services.AddSingleton();
+services.AddDaprEncryptionClient((serviceProvider, clientBuilder) => {
+ //Inject a service to source a value from
+ var optionsProvider = serviceProvider.GetRequiredService();
+ var standardTimeout = optionsProvider.GetStandardTimeout();
+
+ //Configure the value on the client builder
+ clientBuilder.UseTimeout(standardTimeout);
+});
+```
+
+### Manual Instantiation
+Rather than using dependency injection, a `DaprEncryptionClient` can also be built using the static client builder.
+
+For best performance, create a single long-lived instance of `DaprEncryptionClient` and provide access to that shared instance throughout
+your application. `DaprEncryptionClient` instances are thread-safe and intended to be shared.
+
+Avoid creating a `DaprEncryptionClient` per-operation.
+
+A `DaprEncryptionClient` can be configured by invoking methods on the `DaprEncryptionClientBuilder` class before calling `.Build()`
+to create the client. The settings for each `DaprEncryptionClient` are separate and cannot be changed after calling `.Build()`.
+
+```csharp
+var daprEncryptionClient = new DaprEncryptionClientBuilder()
+ .UseJsonSerializerSettings( ... ) //Configure JSON serializer
+ .Build();
+```
+
+See the .NET [documentation here]({{< ref dotnet-client >}}) for more information about the options available when configuring the Dapr client via the builder.
+
+## Try it out
+Put the Dapr AI .NET SDK to the test. Walk through the samples to see Dapr in action:
+
+| SDK Samples | Description |
+|-------------------------------------------------------------------------------------| ----------- |
+| [SDK samples](https://github.com/dapr/dotnet-sdk/tree/master/examples/Cryptography) | Clone the SDK repo to try out some examples and get started. |
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/dotnet-cryptography-usage.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/dotnet-cryptography-usage.md
new file mode 100644
index 00000000..760e3965
--- /dev/null
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-cryptography/dotnet-cryptography-usage.md
@@ -0,0 +1,131 @@
+---
+type: docs
+title: "Dapr Cryptography Client"
+linkTitle: "Cryptography client"
+weight: 510005
+description: Learn how to create Dapr Crytography clients
+---
+
+The Dapr Cryptography package allows you to perform encryption and decryption operations provided by the Dapr sidecar.
+
+## Lifetime management
+A `DaprEncryptionClient` is a version of the Dapr client that is dedicated to interacting with the Dapr Cryptography API.
+It can be registered alongside a `DaprClient` and other Dapr clients without issue.
+
+It maintains access to networking resources in the form of TCP sockets used to communicate with the Dapr sidecar.
+
+For best performance, create a single long-lived instance of `DaprEncryptionClient` and provide access to that shared
+instance throughout your application. `DaprEncryptionClient` instances are thread-safe and intended to be shared.
+
+This can be aided by utilizing the dependency injection functionality. The registration method supports registration
+as a singleton, a scoped instance, or as a transient (meaning it's recreated every time it's injected), but also enables
+registration to utilize values from an `IConfiguration` or other injected service in a way that's impractical when creating
+the client from scratch in each of your classes.
+
+Avoid creating a `DaprEncryptionClient` for each operation.
+
+## Configuring `DaprEncryptionClient` via `DaprEncryptionClientBuilder`
+A `DaprCryptographyClient` can be configured by invoking methods on the `DaprEncryptionClientBuilder` class before calling
+`.Build()` to create the client itself. The settings for each `DaprEncryptionClientBuilder` are separate can cannot be
+changed after calling `.Build()`.
+
+```cs
+var daprEncryptionClient = new DaprEncryptionClientBuilder()
+ .UseDaprApiToken("abc123") //Specify the API token used to authenticate to the Dapr sidecar
+ .Build();
+```
+
+The `DaprEncryptionClientBuilder` contains settings for:
+- The HTTP endpoint of the Dapr sidecar
+- The gRPC endpoint of the Dapr sidecar
+- The `JsonSerializerOptions` object used to configure JSON serialization
+- The `GrpcChannelOptions` object used to configure gRPC
+- The API token used to authenticate requests to the sidecar
+- The factory method used to create the `HttpClient` instance used by the SDK
+- The timeout used for the `HttpClient` instance when making requests to the sidecar
+
+The SDK will read the following environment variables to configure the default values:
+
+- `DAPR_HTTP_ENDPOINT`: used to find the HTTP endpoint of the Dapr sidecar, example: `https://dapr-api.mycompany.com`
+- `DAPR_GRPC_ENDPOINT`: used to find the gRPC endpoint of the Dapr sidecar, example: `https://dapr-grpc-api.mycompany.com`
+- `DAPR_HTTP_PORT`: if `DAPR_HTTP_ENDPOINT` is not set, this is used to find the HTTP local endpoint of the Dapr sidecar
+- `DAPR_GRPC_PORT`: if `DAPR_GRPC_ENDPOINT` is not set, this is used to find the gRPC local endpoint of the Dapr sidecar
+- `DAPR_API_TOKEN`: used to set the API token
+
+### Configuring gRPC channel options
+
+Dapr's use of `CancellationToken` for cancellation relies on the configuration of the gRPC channel options. If you need
+to configure these options yourself, make sure to enable the [ThrowOperationCanceledOnCancellation setting](https://grpc.github.io/grpc/csharp-dotnet/api/Grpc.Net.Client.GrpcChannelOptions.html#Grpc_Net_Client_GrpcChannelOptions_ThrowOperationCanceledOnCancellation).
+
+```cs
+var daprEncryptionClient = new DaprEncryptionClientBuilder()
+ .UseGrpcChannelOptions(new GrpcChannelOptions { .. ThrowOperationCanceledOnCancellation = true })
+ .Build();
+```
+
+## Using cancellation with `DaprEncryptionClient`
+The APIs on `DaprEncryptionClient` perform asynchronous operations and accept an optional `CancellationToken` parameter. This
+follows a standard .NET practice for cancellable operations. Note that when cancellation occurs, there is no guarantee that
+the remote endpoint stops processing the request, only that the client has stopped waiting for completion.
+
+When an operation is cancelled, it will throw an `OperationCancelledException`.
+
+## Configuring `DaprEncryptionClient` via dependency injection
+Using the built-in extension methods for registering the `DaprEncryptionClient` in a dependency injection container can
+provide the benefit of registering the long-lived service a single time, centralize complex configuration and improve
+performance by ensuring similarly long-lived resources are re-purposed when possible (e.g. `HttpClient` instances).
+
+There are three overloads available to give the developer the greatest flexibility in configuring the client for their
+scenario. Each of these will register the `IHttpClientFactory` on your behalf if not already registered, and configure
+the `DaprEncryptionClientBuilder` to use it when creating the `HttpClient` instance in order to re-use the same instance as
+much as possible and avoid socket exhaustion and other issues.
+
+In the first approach, there's no configuration done by the developer and the `DaprEncryptionClient` is configured with the
+default settings.
+
+```cs
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Services.AddDaprEncryptionClent(); //Registers the `DaprEncryptionClient` to be injected as needed
+var app = builder.Build();
+```
+
+Sometimes the developer will need to configure the created client using the various configuration options detailed
+above. This is done through an overload that passes in the `DaprEncryptionClientBuiler` and exposes methods for configuring
+the necessary options.
+
+```cs
+var builder = WebApplication.CreateBuilder(args);
+
+builder.Services.AddDaprEncryptionClient((_, daprEncrpyptionClientBuilder) => {
+ //Set the API token
+ daprEncryptionClientBuilder.UseDaprApiToken("abc123");
+ //Specify a non-standard HTTP endpoint
+ daprEncryptionClientBuilder.UseHttpEndpoint("http://dapr.my-company.com");
+});
+
+var app = builder.Build();
+```
+
+Finally, it's possible that the developer may need to retrieve information from another service in order to populate
+these configuration values. That value may be provided from a `DaprClient` instance, a vendor-specific SDK or some
+local service, but as long as it's also registered in DI, it can be injected into this configuration operation via the
+last overload:
+
+```cs
+var builder = WebApplication.CreateBuilder(args);
+
+//Register a fictional service that retrieves secrets from somewhere
+builder.Services.AddSingleton();
+
+builder.Services.AddDaprEncryptionClient((serviceProvider, daprEncryptionClientBuilder) => {
+ //Retrieve an instance of the `SecretService` from the service provider
+ var secretService = serviceProvider.GetRequiredService();
+ var daprApiToken = secretService.GetSecret("DaprApiToken").Value;
+
+ //Configure the `DaprEncryptionClientBuilder`
+ daprEncryptionClientBuilder.UseDaprApiToken(daprApiToken);
+});
+
+var app = builder.Build();
+```
\ No newline at end of file
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-dapr-aspire.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-dapr-aspire.md
index 543cf94b..664b8a2c 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-dapr-aspire.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-dapr-aspire.md
@@ -23,14 +23,15 @@ While Aspire also assists with deployment of your application to various cloud h
Amazon AWS, deployment is currently outside the scope of this guide. More information can be found in Aspire's
documentation [here](https://learn.microsoft.com/en-us/dotnet/aspire/deployment/overview).
+An end-to-end demonstration featuring the following and demonstrating service invocation between multiple Dapr-enabled
+services can be found [here](https://github.com/dapr/dotnet-sdk/tree/master/examples/Hosting/Aspire/ServiceInvocationDemo).
+
## Prerequisites
-- While the Dapr .NET SDK is compatible with [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0),
-[.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0),
-.NET Aspire is only compatible with [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or
-[.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0).
+- Both the Dapr .NET SDK and .NET Aspire are compatible with [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0)
+or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0)
- An OCI compliant container runtime such as [Docker Desktop](https://www.docker.com/products/docker-desktop) or
[Podman](https://podman.io/)
-- Install and initialize Dapr v1.13 or later
+- Install and initialize Dapr v1.16 or later
## Using .NET Aspire via CLI
@@ -59,17 +60,18 @@ resilience, service discovery and telemetry capabilities offered by Aspire (thes
offered in Dapr itself).
- `aspiredemo.sln` is the file that maintains the layout of your current solution
-We'll next create a project that'll serve as our Dapr application. From the same directory, use the following
-to create an empty ASP.NET Core project called `MyApp`. This will be created relative to your current directory in
-`MyApp\MyApp.csproj`.
+We'll next create twp projects that'll serve as our Dapr application and demonstrate Dapr functionality. From the same
+directory, use the following to create an empty ASP.NET Core project called `FrontEndApp` and another called
+'BackEndApp'. Either one will be created relative to your current directory in
+`FrontEndApp\FrontEndApp.csproj` and `BackEndApp\BackEndApp.csproj`, respectively.
```sh
-dotnet new web MyApp
+dotnet new web --name FrontEndApp
```
Next we'll configure the AppHost project to add the necessary package to support local Dapr development. Navigate
into the AppHost directory with the following and install the `CommunityToolkit.Aspire.Hosting.Dapr` package from NuGet into the project.
-We'll also add a reference to our `MyApp` project so we can reference it during the registration process.
+We'll also add a reference to our `FrontEndApp` project so we can reference it during the registration process.
{{% alert color="primary" %}}
@@ -80,7 +82,8 @@ This package was previously called `Aspire.Hosting.Dapr`, which has been [marked
```sh
cd aspiredemo.AppHost
dotnet add package CommunityToolkit.Aspire.Hosting.Dapr
-dotnet add reference ../MyApp/
+dotnet add reference ../FrontEndApp/
+dotnet add reference ../BackEndApp/
```
Next, we need to configure Dapr as a resource to be loaded alongside your project. Open the `Program.cs` file in that
@@ -99,8 +102,12 @@ Because we've already added a project reference to `MyApp`, we need to start by
as well. Add the following before the `builder.Build().Run()` line:
```csharp
-var myApp = builder
- .AddProject("myapp")
+var backEndApp = builder
+ .AddProject("be")
+ .WithDaprSidecar();
+
+var frontEndApp = builder
+ .AddProject("fe")
.WithDaprSidecar();
```
@@ -116,7 +123,7 @@ the following example:
```csharp
DaprSidecarOptions sidecarOptions = new()
{
- AppId = "my-other-app",
+ AppId = "how-dapr-identifies-your-app",
AppPort = 8080, //Note that this argument is required if you intend to configure pubsub, actors or workflows as of Aspire v9.0
DaprGrpcPort = 50001,
DaprHttpPort = 3500,
@@ -124,7 +131,7 @@ DaprSidecarOptions sidecarOptions = new()
};
builder
- .AddProject("myotherapp")
+ .AddProject("be")
.WithReference(myApp)
.WithDaprSidecar(sidecarOptions);
```
@@ -138,6 +145,9 @@ change in a future release as a fix has been merged and can be tracked [here](ht
{{% /alert %}}
+Finally, let's add an endpoint to the back-end app that we can invoke using Dapr's service invocation to display to a
+page to demonstrate that Dapr is working as expected.
+
When you open the solution in your IDE, ensure that the `aspiredemo.AppHost` is configured as your startup project, but
when you launch it in a debug configuration, you'll note that your integrated console should reflect your expected Dapr
logs and it will be available to your application.
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-experimental-attributes.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-experimental-attributes.md
new file mode 100644
index 00000000..12825be2
--- /dev/null
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-experimental-attributes.md
@@ -0,0 +1,138 @@
+---
+type: docs
+title: "Dapr .NET SDK Development with Dapr CLI"
+linkTitle: "Experimental Attributes"
+weight: 61000
+description: Learn about local development with the Dapr CLI
+---
+
+## Experimental Attributes
+
+### Introduction to Experimental Attributes
+
+With the release of .NET 8, C# 12 introduced the `[Experimental]` attribute, which provides a standardized way to mark
+APIs that are still in development or experimental. This attribute is defined in the `System.Diagnostics.CodeAnalysis`
+namespace and requires a diagnostic ID parameter used to generate compiler warnings when the experimental API
+is used.
+
+In the Dapr .NET SDK, we now use the `[Experimental]` attribute instead of `[Obsolete]` to mark building blocks and
+components that have not yet passed the stable lifecycle certification. This approach provides a clearer distinction
+between:
+
+1. **Experimental APIs** - Features that are available but still evolving and have not yet been certified as stable
+according to the [Dapr Component Certification Lifecycle](https://docs.dapr.io/operations/components/certification-lifecycle/).
+
+2. **Obsolete APIs** - Features that are truly deprecated and will be removed in a future release.
+
+### Usage in the Dapr .NET SDK
+
+In the Dapr .NET SDK, we apply the `[Experimental]` attribute at the class level for building blocks that are still in
+the Alpha or Beta stages of the [Component Certification Lifecycle](https://docs.dapr.io/operations/components/certification-lifecycle/).
+The attribute includes:
+
+- A diagnostic ID that identifies the experimental building block
+- A URL that points to the relevant documentation for that block
+
+For example:
+
+```csharp
+using System.Diagnostics.CodeAnalysis;
+namespace Dapr.Cryptography.Encryption
+{
+ [Experimental("DAPR_CRYPTOGRAPHY", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/cryptography/cryptography-overview/")]
+ public class DaprEncryptionClient
+ {
+ // Implementation
+ }
+}
+```
+
+The diagnostic IDs follow a naming convention of `DAPR_[BUILDING_BLOCK_NAME]`, such as:
+
+- `DAPR_CONVERSATION` - For the Conversation building block
+- `DAPR_CRYPTOGRAPHY` - For the Cryptography building block
+- `DAPR_JOBS` - For the Jobs building block
+- `DAPR_DISTRIBUTEDLOCK` - For the Distributed Lock building block
+
+### Suppressing Experimental Warnings
+
+When you use APIs marked with the `[Experimental]` attribute, the compiler will generate errors.
+To build your solution without marking your own code as experimental, you will need to suppress these errors. Here are
+several approaches to do this:
+
+#### Option 1: Using #pragma directive
+
+You can use the `#pragma warning` directive to suppress the warning for specific sections of code:
+
+```csharp
+// Disable experimental warning
+#pragma warning disable DAPR_CRYPTOGRAPHY
+// Your code using the experimental API
+var client = new DaprEncryptionClient();
+// Re-enable the warning
+#pragma warning restore DAPR_CRYPTOGRAPHY
+```
+
+This approach is useful when you want to suppress warnings only for specific sections of your code.
+
+#### Option 2: Project-level suppression
+
+To suppress warnings for an entire project, add the following to your `.csproj` file.
+file.
+
+```xml
+
+ $(NoWarn);DAPR_CRYPTOGRAPHY
+
+```
+
+You can include multiple diagnostic IDs separated by semicolons:
+
+```xml
+
+ $(NoWarn);DAPR_CONVERSATION;DAPR_JOBS;DAPR_DISTRIBUTEDLOCK;DAPR_CRYPTOGRAPHY
+
+```
+
+This approach is particularly useful for test projects that need to use experimental APIs.
+
+#### Option 3: Directory-level suppression
+
+For suppressing warnings across multiple projects in a directory, add a `Directory.Build.props` file:
+
+```xml
+
+ $(NoWarn);DAPR_CONVERSATION;DAPR_JOBS;DAPR_DISTRIBUTEDLOCK;DAPR_CRYPTOGRAPHY
+
+```
+
+This file should be placed in the root directory of your test projects. You can learn more about using
+`Directory.Build.props` files in the
+[MSBuild documentation](https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory).
+
+### Lifecycle of Experimental APIs
+
+As building blocks move through the certification lifecycle and reach the "Stable" stage, the `[Experimental]` attribute will be removed. No migration or code changes will be required from users when this happens, except for the removal of any warning suppressions if they were added.
+
+Conversely, the `[Obsolete]` attribute will now be reserved exclusively for APIs that are truly deprecated and scheduled for removal. When you see a method or class marked with `[Obsolete]`, you should plan to migrate away from it according to the migration guidance provided in the attribute message.
+
+### Best Practices
+
+1. **In application code:**
+ - Be cautious when using experimental APIs, as they may change in future releases
+ - Consider isolating usage of experimental APIs to make future updates easier
+ - Document your use of experimental APIs for team awareness
+
+2. **In test code:**
+ - Use project-level suppression to avoid cluttering test code with warning suppressions
+ - Regularly review which experimental APIs you're using and check if they've been stabilized
+
+3. **When contributing to the SDK:**
+ - Use `[Experimental]` for new building blocks that haven't completed certification
+ - Use `[Obsolete]` only for truly deprecated APIs
+ - Provide clear documentation links in the `UrlFormat` parameter
+
+### Additional Resources
+
+- [Dapr Component Certification Lifecycle](https://docs.dapr.io/operations/components/certification-lifecycle/)
+- [C# Experimental Attribute Documentation](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-12.0/experimental-attribute)
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-tye.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-tye.md
deleted file mode 100644
index 0077bd56..00000000
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-development/dotnet-development-tye.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-type: docs
-title: "Dapr .NET SDK Development with Project Tye"
-linkTitle: "Project Tye"
-weight: 50000
-description: Learn about local development with Project Tye
----
-
-## Project Tye
-
-[.NET Project Tye](https://github.com/dotnet/tye/) is a microservices development tool designed to make running many .NET services easy. Tye enables you to store a configuration of multiple .NET services, processes, and container images as a runnable application.
-
-Tye is advantageous for a .NET Dapr developer because:
-
-- Tye has the ability to automate the dapr CLI built-in
-- Tye understands .NET's conventions and requires almost no configuration for .NET services
-- Tye can manage the lifetime of your dependencies in containers
-
-Pros/cons:
-- **Pro:** Tye can automate all of the steps described above. You no longer need to think about concepts like ports or app-ids.
-- **Pro:** Since Tye can also manage containers for you, you can make those part of the application definition and stop the long-running containers on your machine.
-
-### Using Tye
-
-Follow the [Tye Getting Started](https://github.com/dotnet/tye/blob/master/docs/getting_started.md) to install the `tye` CLI and create a `tye.yaml` for your application.
-
-Next follow the steps in the [Tye Dapr recipe](https://github.com/dotnet/tye/blob/master/docs/recipes/dapr.md) to add Dapr. Make sure to specify the relative path to your components folder with `components-path` in `tye.yaml`.
-
-Next add any additional container dependencies and add component definitions to the folder you created earlier.
-
-You should end up with something like this:
-
-```yaml
-name: store-application
-extensions:
-
- # Configuration for dapr goes here.
-- name: dapr
- components-path:
-
-# Services to run go here.
-services:
-
- # The name will be used as the app-id. For a .NET project, Tye only needs the path to the project file.
-- name: orders
- project: orders/orders.csproj
-- name: products
- project: products/products.csproj
-- name: store
- project: store/store.csproj
-
- # Containers you want to run need an image name and set of ports to expose.
-- name: redis
- image: redis
- bindings:
- - port: 6973
-```
-
-Checkin `tye.yaml` in source control with the application code.
-
-You can now use `tye run` to launch the whole application from one terminal. When running, Tye has a dashboard at `http://localhost:8000` to view application status and logs.
-
-### Next steps
-
-Tye runs your services locally as normal .NET process. If you need to debug, then use the attach feature of your debugger to attach to one of the running processes. Since Tye is .NET aware, it has the ability to [start a process suspended](https://github.com/dotnet/tye/blob/master/docs/reference/commandline/tye-run.md#options) for startup debugging.
-
-Tye also has an [option](https://github.com/dotnet/tye/blob/master/docs/reference/commandline/tye-run.md#options) to run your services in containers if you wish to test locally in containers.
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-jobs/dotnet-jobs-howto.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-jobs/dotnet-jobs-howto.md
index be4d2705..6fe122c9 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-jobs/dotnet-jobs-howto.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-jobs/dotnet-jobs-howto.md
@@ -18,15 +18,9 @@ In the .NET example project:
## Prerequisites
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost)
-- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
+- [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
- [Dapr.Jobs](https://www.nuget.org/packages/Dapr.Jobs) NuGet package installed to your project
-{{% alert title="Note" color="primary" %}}
-
-Note that while .NET 6 is the minimum support version of .NET in Dapr v1.15, only .NET 8 and .NET 9 will continue to be supported by Dapr in v1.16 and later.
-
-{{% /alert %}}
-
## Set up the environment
Clone the [.NET SDK repo](https://github.com/dapr/dotnet-sdk).
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-messaging/dotnet-messaging-pubsub-howto.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-messaging/dotnet-messaging-pubsub-howto.md
index b128d884..5b748b61 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-messaging/dotnet-messaging-pubsub-howto.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-messaging/dotnet-messaging-pubsub-howto.md
@@ -17,15 +17,9 @@ runtime and which do not require an endpoint to be pre-configured. In this guide
## Prerequisites
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost)
-- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
+- [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
- [Dapr.Messaging](https://www.nuget.org/packages/Dapr.Messaging) NuGet package installed to your project
-{{% alert title="Note" color="primary" %}}
-
-Note that while .NET 6 is the minimum support version of .NET in Dapr v1.15, only .NET 8 and .NET 9 will continue to be supported by Dapr in v1.16 and later.
-
-{{% /alert %}}
-
## Set up the environment
Clone the [.NET SDK repo](https://github.com/dapr/dotnet-sdk).
diff --git a/daprdocs/content/en/dotnet-sdk-docs/dotnet-workflow/dotnet-workflow-howto.md b/daprdocs/content/en/dotnet-sdk-docs/dotnet-workflow/dotnet-workflow-howto.md
index 61425b3c..d38652dd 100644
--- a/daprdocs/content/en/dotnet-sdk-docs/dotnet-workflow/dotnet-workflow-howto.md
+++ b/daprdocs/content/en/dotnet-sdk-docs/dotnet-workflow/dotnet-workflow-howto.md
@@ -20,14 +20,7 @@ In the .NET example project:
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
-- [.NET 7](https://dotnet.microsoft.com/download/dotnet/7.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
-
-{{% alert title="Note" color="primary" %}}
-
-Dapr.Workflows supports .NET 7 or newer in v1.15. However, following the release of Dapr v1.16, only
-.NET 8 and .NET 9 will be supported.
-
-{{% /alert %}}
+- [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
## Set up the environment
diff --git a/examples/AI/ConversationalAI/ConversationalAI.csproj b/examples/AI/ConversationalAI/ConversationalAI.csproj
index 976265a5..182363d2 100644
--- a/examples/AI/ConversationalAI/ConversationalAI.csproj
+++ b/examples/AI/ConversationalAI/ConversationalAI.csproj
@@ -1,7 +1,6 @@
- net8.0
enable
enable
diff --git a/examples/Actor/ActorClient/ActorClient.csproj b/examples/Actor/ActorClient/ActorClient.csproj
index 0d1d94f5..9631e517 100644
--- a/examples/Actor/ActorClient/ActorClient.csproj
+++ b/examples/Actor/ActorClient/ActorClient.csproj
@@ -2,12 +2,11 @@
Exe
- net6
-
+
diff --git a/examples/Actor/ActorClient/Program.cs b/examples/Actor/ActorClient/Program.cs
index 950869b2..b578d488 100644
--- a/examples/Actor/ActorClient/Program.cs
+++ b/examples/Actor/ActorClient/Program.cs
@@ -11,146 +11,123 @@
// limitations under the License.
// ------------------------------------------------------------------------
-using Dapr.Actors.Communication;
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+using Dapr.Actors;
+using Dapr.Actors.Client;
using IDemoActor;
-namespace ActorClient
+var data = new MyData("ValueA", "ValueB");
+
+// Create an actor Id.
+var actorId = new ActorId("abc");
+
+// Make strongly typed Actor calls with Remoting.
+// DemoActor is the type registered with Dapr runtime in the service.
+var proxy = ActorProxy.Create(actorId, "DemoActor");
+
+Console.WriteLine("Making call using actor proxy to save data.");
+await proxy.SaveData(data, TimeSpan.FromMinutes(10));
+Console.WriteLine("Making call using actor proxy to get data.");
+var receivedData = await proxy.GetData();
+Console.WriteLine($"Received data is {receivedData}.");
+
+// Making some more calls to test methods.
+try
{
- using System;
- using System.Threading;
- using System.Threading.Tasks;
- using Dapr.Actors;
- using Dapr.Actors.Client;
+ Console.WriteLine("Making calls to an actor method which has no argument and no return type.");
+ await proxy.TestNoArgumentNoReturnType();
+}
+catch (Exception ex)
+{
+ Console.WriteLine($"ERROR: Got exception while making call to method with No Argument & No Return Type. Exception: {ex}");
+}
- ///
- /// Actor Client class.
- ///
- public class Program
+try
+{
+ await proxy.TestThrowException();
+}
+catch (ActorMethodInvocationException ex)
+{
+ if (ex.InnerException is ActorInvokeException invokeEx && invokeEx.ActualExceptionType is "System.NotImplementedException")
{
- ///
- /// Entry point.
- ///
- /// Arguments.
- /// A representing the asynchronous operation.
- public static async Task Main(string[] args)
- {
- var data = new MyData()
- {
- PropertyA = "ValueA",
- PropertyB = "ValueB",
- };
-
- // Create an actor Id.
- var actorId = new ActorId("abc");
-
- // Make strongly typed Actor calls with Remoting.
- // DemoActor is the type registered with Dapr runtime in the service.
- var proxy = ActorProxy.Create(actorId, "DemoActor");
-
- Console.WriteLine("Making call using actor proxy to save data.");
- await proxy.SaveData(data, TimeSpan.FromMinutes(10));
- Console.WriteLine("Making call using actor proxy to get data.");
- var receivedData = await proxy.GetData();
- Console.WriteLine($"Received data is {receivedData}.");
-
- // Making some more calls to test methods.
- try
- {
- Console.WriteLine("Making calls to an actor method which has no argument and no return type.");
- await proxy.TestNoArgumentNoReturnType();
- }
- catch (Exception ex)
- {
- Console.WriteLine($"ERROR: Got exception while making call to method with No Argument & No Return Type. Exception: {ex}");
- }
-
- try
- {
- await proxy.TestThrowException();
- }
- catch (ActorMethodInvocationException ex)
- {
- if (ex.InnerException is ActorInvokeException invokeEx && invokeEx.ActualExceptionType is "System.NotImplementedException")
- {
- Console.WriteLine($"Got Correct Exception from actor method invocation.");
- }
- else
- {
- Console.WriteLine($"Got Incorrect Exception from actor method invocation. Exception {ex.InnerException}");
- }
- }
-
- // Making calls without Remoting, this shows method invocation using InvokeMethodAsync methods, the method name and its payload is provided as arguments to InvokeMethodAsync methods.
- Console.WriteLine("Making calls without Remoting.");
- var nonRemotingProxy = ActorProxy.Create(actorId, "DemoActor");
- await nonRemotingProxy.InvokeMethodAsync("TestNoArgumentNoReturnType");
- await nonRemotingProxy.InvokeMethodAsync("SaveData", data);
- await nonRemotingProxy.InvokeMethodAsync("GetData");
-
- Console.WriteLine("Registering the timer and reminder");
- await proxy.RegisterTimer();
- await proxy.RegisterReminder();
- Console.WriteLine("Waiting so the timer and reminder can be triggered");
- await Task.Delay(6000);
-
- Console.WriteLine("Making call using actor proxy to get data after timer and reminder triggered");
- receivedData = await proxy.GetData();
- Console.WriteLine($"Received data is {receivedData}.");
-
- Console.WriteLine("Getting details of the registered reminder");
- var reminder = await proxy.GetReminder();
- Console.WriteLine($"Received reminder is {reminder}.");
-
- Console.WriteLine("Deregistering timer. Timers would any way stop if the actor is deactivated as part of Dapr garbage collection.");
- await proxy.UnregisterTimer();
- Console.WriteLine("Deregistering reminder. Reminders are durable and would not stop until an explicit deregistration or the actor is deleted.");
- await proxy.UnregisterReminder();
-
- Console.WriteLine("Registering reminder with repetitions - The reminder will repeat 3 times.");
- await proxy.RegisterReminderWithRepetitions(3);
- Console.WriteLine("Waiting so the reminder can be triggered");
- await Task.Delay(5000);
- Console.WriteLine("Getting details of the registered reminder");
- reminder = await proxy.GetReminder();
- Console.WriteLine($"Received reminder is {reminder?.ToString() ?? "None"} (expecting None).");
- Console.WriteLine("Registering reminder with ttl and repetitions, i.e. reminder stops when either condition is met - The reminder will repeat 2 times.");
- await proxy.RegisterReminderWithTtlAndRepetitions(TimeSpan.FromSeconds(5), 2);
- Console.WriteLine("Getting details of the registered reminder");
- reminder = await proxy.GetReminder();
- Console.WriteLine($"Received reminder is {reminder}.");
- Console.WriteLine("Deregistering reminder. Reminders are durable and would not stop until an explicit deregistration or the actor is deleted.");
- await proxy.UnregisterReminder();
-
- Console.WriteLine("Registering reminder and Timer with TTL - The reminder will self delete after 10 seconds.");
- await proxy.RegisterReminderWithTtl(TimeSpan.FromSeconds(10));
- await proxy.RegisterTimerWithTtl(TimeSpan.FromSeconds(10));
- Console.WriteLine("Getting details of the registered reminder");
- reminder = await proxy.GetReminder();
- Console.WriteLine($"Received reminder is {reminder}.");
-
- // Track the reminder.
- var timer = new Timer(async state => Console.WriteLine($"Received data: {await proxy.GetData()}"), null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
- await Task.Delay(TimeSpan.FromSeconds(21));
- await timer.DisposeAsync();
-
- Console.WriteLine("Creating a Bank Actor");
- var bank = ActorProxy.Create(ActorId.CreateRandom(), "DemoActor");
- while (true)
- {
- var balance = await bank.GetAccountBalance();
- Console.WriteLine($"Balance for account '{balance.AccountId}' is '{balance.Balance:c}'.");
-
- Console.WriteLine($"Withdrawing '{10m:c}'...");
- try
- {
- await bank.Withdraw(new WithdrawRequest() { Amount = 10m, });
- }
- catch (ActorMethodInvocationException ex)
- {
- Console.WriteLine("Overdraft: " + ex.Message);
- break;
- }
- }
- }
+ Console.WriteLine($"Got Correct Exception from actor method invocation.");
+ }
+ else
+ {
+ Console.WriteLine($"Got Incorrect Exception from actor method invocation. Exception {ex.InnerException}");
+ }
+}
+
+// Making calls without Remoting, this shows method invocation using InvokeMethodAsync methods, the method name and its payload is provided as arguments to InvokeMethodAsync methods.
+Console.WriteLine("Making calls without Remoting.");
+var nonRemotingProxy = ActorProxy.Create(actorId, "DemoActor");
+await nonRemotingProxy.InvokeMethodAsync("TestNoArgumentNoReturnType");
+await nonRemotingProxy.InvokeMethodAsync("SaveData", data);
+await nonRemotingProxy.InvokeMethodAsync("GetData");
+
+Console.WriteLine("Registering the timer and reminder");
+await proxy.RegisterTimer();
+await proxy.RegisterReminder();
+Console.WriteLine("Waiting so the timer and reminder can be triggered");
+await Task.Delay(6000);
+
+Console.WriteLine("Making call using actor proxy to get data after timer and reminder triggered");
+receivedData = await proxy.GetData();
+Console.WriteLine($"Received data is {receivedData}.");
+
+Console.WriteLine("Getting details of the registered reminder");
+var reminder = await proxy.GetReminder();
+Console.WriteLine($"Received reminder is {reminder}.");
+
+Console.WriteLine("Deregistering timer. Timers would any way stop if the actor is deactivated as part of Dapr garbage collection.");
+await proxy.UnregisterTimer();
+Console.WriteLine("Deregistering reminder. Reminders are durable and would not stop until an explicit deregistration or the actor is deleted.");
+await proxy.UnregisterReminder();
+
+Console.WriteLine("Registering reminder with repetitions - The reminder will repeat 3 times.");
+await proxy.RegisterReminderWithRepetitions(3);
+Console.WriteLine("Waiting so the reminder can be triggered");
+await Task.Delay(5000);
+Console.WriteLine("Getting details of the registered reminder");
+reminder = await proxy.GetReminder();
+Console.WriteLine($"Received reminder is {reminder?.ToString() ?? "None"} (expecting None).");
+Console.WriteLine("Registering reminder with ttl and repetitions, i.e. reminder stops when either condition is met - The reminder will repeat 2 times.");
+await proxy.RegisterReminderWithTtlAndRepetitions(TimeSpan.FromSeconds(5), 2);
+Console.WriteLine("Getting details of the registered reminder");
+reminder = await proxy.GetReminder();
+Console.WriteLine($"Received reminder is {reminder}.");
+Console.WriteLine("Deregistering reminder. Reminders are durable and would not stop until an explicit deregistration or the actor is deleted.");
+await proxy.UnregisterReminder();
+
+Console.WriteLine("Registering reminder and Timer with TTL - The reminder will self delete after 10 seconds.");
+await proxy.RegisterReminderWithTtl(TimeSpan.FromSeconds(10));
+await proxy.RegisterTimerWithTtl(TimeSpan.FromSeconds(10));
+Console.WriteLine("Getting details of the registered reminder");
+reminder = await proxy.GetReminder();
+Console.WriteLine($"Received reminder is {reminder}.");
+
+// Track the reminder.
+var timer = new Timer(async state => Console.WriteLine($"Received data: {await proxy.GetData()}"), null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
+await Task.Delay(TimeSpan.FromSeconds(21));
+await timer.DisposeAsync();
+
+Console.WriteLine("Creating a Bank Actor");
+var bank = ActorProxy.Create(ActorId.CreateRandom(), "DemoActor");
+while (true)
+{
+ var balance = await bank.GetAccountBalance();
+ Console.WriteLine($"Balance for account '{balance.AccountId}' is '{balance.Balance:c}'.");
+
+ Console.WriteLine($"Withdrawing '{10m:c}'...");
+ try
+ {
+ await bank.Withdraw(new WithdrawRequest(10m));
+ }
+ catch (ActorMethodInvocationException ex)
+ {
+ Console.WriteLine($"Overdraft: {ex.Message}");
+ break;
}
}
diff --git a/examples/Actor/IDemoActor/IDemoActor.csproj b/examples/Actor/DemoActor.Interfaces/DemoActor.Interfaces.csproj
similarity index 71%
rename from examples/Actor/IDemoActor/IDemoActor.csproj
rename to examples/Actor/DemoActor.Interfaces/DemoActor.Interfaces.csproj
index 9f774479..f4955942 100644
--- a/examples/Actor/IDemoActor/IDemoActor.csproj
+++ b/examples/Actor/DemoActor.Interfaces/DemoActor.Interfaces.csproj
@@ -1,7 +1,8 @@
- net6
+ IDemoActor
+ enable
diff --git a/examples/Actor/IDemoActor/IBankActor.cs b/examples/Actor/DemoActor.Interfaces/IBankActor.cs
similarity index 55%
rename from examples/Actor/IDemoActor/IBankActor.cs
rename to examples/Actor/DemoActor.Interfaces/IBankActor.cs
index c495f027..92d84742 100644
--- a/examples/Actor/IDemoActor/IBankActor.cs
+++ b/examples/Actor/DemoActor.Interfaces/IBankActor.cs
@@ -15,32 +15,18 @@ using System;
using System.Threading.Tasks;
using Dapr.Actors;
-namespace IDemoActor
+namespace IDemoActor;
+
+public interface IBankActor : IActor
{
- public interface IBankActor : IActor
- {
- Task GetAccountBalance();
+ Task GetAccountBalance();
- Task Withdraw(WithdrawRequest withdraw);
- }
-
- public class AccountBalance
- {
- public string AccountId { get; set; }
-
- public decimal Balance { get; set; }
- }
-
- public class WithdrawRequest
- {
- public decimal Amount { get; set; }
- }
-
- public class OverdraftException : Exception
- {
- public OverdraftException(decimal balance, decimal amount)
- : base($"Your current balance is {balance:c} - that's not enough to withdraw {amount:c}.")
- {
- }
- }
+ Task Withdraw(WithdrawRequest withdraw);
}
+
+public sealed record AccountBalance(string AccountId, decimal Balance);
+
+public sealed record WithdrawRequest(decimal Amount);
+
+public class OverdraftException(decimal balance, decimal amount)
+ : Exception($"Your current balance is {balance:c} - that's not enough to withdraw {amount:c}.");
diff --git a/examples/Actor/DemoActor.Interfaces/IDemoActor.cs b/examples/Actor/DemoActor.Interfaces/IDemoActor.cs
new file mode 100644
index 00000000..c5fefdb9
--- /dev/null
+++ b/examples/Actor/DemoActor.Interfaces/IDemoActor.cs
@@ -0,0 +1,129 @@
+// ------------------------------------------------------------------------
+// Copyright 2021 The Dapr Authors
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ------------------------------------------------------------------------
+
+using System;
+using System.Threading.Tasks;
+using Dapr.Actors;
+
+namespace IDemoActor;
+
+///
+/// Interface for Actor method.
+///
+public interface IDemoActor : IActor
+{
+ ///
+ /// Method to save data.
+ ///
+ /// DAta to save.
+ /// TTL of state key.
+ /// A task that represents the asynchronous save operation.
+ Task SaveData(MyData data, TimeSpan ttl);
+
+ ///
+ /// Method to get data.
+ ///
+ /// A task that represents the asynchronous save operation.
+ Task GetData();
+
+ ///
+ /// A test method which throws exception.
+ ///
+ /// A task that represents the asynchronous save operation.
+ Task TestThrowException();
+
+ ///
+ /// A test method which validates calls for methods with no arguments and no return types.
+ ///
+ /// A task that represents the asynchronous save operation.
+ Task TestNoArgumentNoReturnType();
+
+ ///
+ /// Registers a reminder.
+ ///
+ /// A task that represents the asynchronous save operation.
+ Task RegisterReminder();
+
+ ///
+ /// Registers a reminder.
+ ///
+ /// TimeSpan that dictates when the reminder expires.
+ /// A task that represents the asynchronous save operation.
+ Task RegisterReminderWithTtl(TimeSpan ttl);
+
+ ///
+ /// Unregisters the registered reminder.
+ ///
+ /// Task representing the operation.
+ Task UnregisterReminder();
+
+ ///
+ /// Registers a timer.
+ ///
+ /// A task that represents the asynchronous save operation.
+ Task RegisterTimer();
+
+ ///
+ /// Registers a timer.
+ ///
+ /// Optional TimeSpan that dictates when the timer expires.
+ /// A task that represents the asynchronous save operation.
+ Task RegisterTimerWithTtl(TimeSpan ttl);
+
+ ///
+ /// Registers a reminder with repetitions.
+ ///
+ /// The number of repetitions for which the reminder should be invoked.
+ /// A task that represents the asynchronous save operation.
+ Task RegisterReminderWithRepetitions(int repetitions);
+
+ ///
+ /// Registers a reminder with ttl and repetitions.
+ ///
+ /// TimeSpan that dictates when the timer expires.
+ /// The number of repetitions for which the reminder should be invoked.
+ /// A task that represents the asynchronous save operation.
+ Task RegisterReminderWithTtlAndRepetitions(TimeSpan ttl, int repetitions);
+
+ ///
+ /// Gets the registered reminder.
+ ///
+ /// A task that returns the reminder after completion.
+ Task GetReminder();
+
+ ///
+ /// Unregisters the registered timer.
+ ///
+ /// A task that represents the asynchronous save operation.
+ Task UnregisterTimer();
+}
+
+///
+/// Data Used by the Sample Actor.
+///
+public sealed record MyData(string? PropertyA, string? PropertyB)
+{
+ ///
+ public override string ToString() => $"PropertyA: {PropertyA ?? "null"}, PropertyB: {PropertyB ?? "null"}";
+}
+
+public class ActorReminderData
+{
+ public string? Name { get; set; }
+
+ public TimeSpan DueTime { get; set; }
+
+ public TimeSpan Period { get; set; }
+
+ public override string ToString() => $"Name: {this.Name}, DueTime: {this.DueTime}, Period: {this.Period}";
+}
diff --git a/examples/Actor/DemoActor/BankService.cs b/examples/Actor/DemoActor/BankService.cs
index a24eaded..22d2ac44 100644
--- a/examples/Actor/DemoActor/BankService.cs
+++ b/examples/Actor/DemoActor/BankService.cs
@@ -13,24 +13,23 @@
using IDemoActor;
-namespace DemoActor
+namespace DemoActor;
+
+public sealed class BankService
{
- public class BankService
+ // Allow overdraft of up to 50 (of whatever currency).
+ private const decimal OverdraftThreshold = -50m;
+
+ public decimal Withdraw(decimal balance, decimal amount)
{
- // Allow overdraft of up to 50 (of whatever currency).
- private readonly decimal OverdraftThreshold = -50m;
+ // Imagine putting some complex auditing logic here in addition to the basics.
- public decimal Withdraw(decimal balance, decimal amount)
+ var updated = balance - amount;
+ if (updated < OverdraftThreshold)
{
- // Imagine putting some complex auditing logic here in addition to the basics.
-
- var updated = balance - amount;
- if (updated < OverdraftThreshold)
- {
- throw new OverdraftException(balance, amount);
- }
-
- return updated;
+ throw new OverdraftException(balance, amount);
}
+
+ return updated;
}
}
diff --git a/examples/Actor/DemoActor/DemoActor.cs b/examples/Actor/DemoActor/DemoActor.cs
index b5ef53e9..3e5de369 100644
--- a/examples/Actor/DemoActor/DemoActor.cs
+++ b/examples/Actor/DemoActor/DemoActor.cs
@@ -17,195 +17,182 @@ using System.Threading.Tasks;
using Dapr.Actors.Runtime;
using IDemoActor;
-namespace DemoActor
+namespace DemoActor;
+
+// The following example showcases a few features of Actors
+//
+// Every actor should inherit from the Actor type, and must implement one or more actor interfaces.
+// In this case the actor interfaces are DemoActor.Interfaces and IBankActor.
+//
+// For Actors to use Reminders, it must derive from IRemindable.
+// If you don't intend to use Reminder feature, you can skip implementing IRemindable and reminder
+// specific methods which are shown in the code below.
+public class DemoActor(ActorHost host, BankService bank) : Actor(host), IDemoActor.IDemoActor, IBankActor, IRemindable
{
- // The following example showcases a few features of Actors
- //
- // Every actor should inherit from the Actor type, and must implement one or more actor interfaces.
- // In this case the actor interfaces are IDemoActor and IBankActor.
- //
- // For Actors to use Reminders, it must derive from IRemindable.
- // If you don't intend to use Reminder feature, you can skip implementing IRemindable and reminder
- // specific methods which are shown in the code below.
- public class DemoActor : Actor, IDemoActor.IDemoActor, IBankActor, IRemindable
+ private const string StateName = "my_data";
+
+ public async Task SaveData(MyData data, TimeSpan ttl)
{
- private const string StateName = "my_data";
+ Console.WriteLine($"This is Actor id {this.Id} with data {data}.");
- private readonly BankService bank;
+ // Set State using StateManager, state is saved after the method execution.
+ await this.StateManager.SetStateAsync(StateName, data, ttl);
+ }
- public DemoActor(ActorHost host, BankService bank)
- : base(host)
- {
- // BankService is provided by dependency injection.
- // See Program.cs
- this.bank = bank;
- }
+ public Task GetData()
+ {
+ // Get state using StateManager.
+ return this.StateManager.GetStateAsync(StateName);
+ }
- public async Task SaveData(MyData data, TimeSpan ttl)
- {
- Console.WriteLine($"This is Actor id {this.Id} with data {data}.");
+ public Task TestThrowException()
+ {
+ throw new NotImplementedException();
+ }
- // Set State using StateManager, state is saved after the method execution.
- await this.StateManager.SetStateAsync(StateName, data, ttl);
- }
+ public Task TestNoArgumentNoReturnType()
+ {
+ return Task.CompletedTask;
+ }
- public Task GetData()
- {
- // Get state using StateManager.
- return this.StateManager.GetStateAsync(StateName);
- }
+ public async Task RegisterReminder()
+ {
+ await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
+ }
- public Task TestThrowException()
- {
- throw new NotImplementedException();
- }
-
- public Task TestNoArgumentNoReturnType()
- {
- return Task.CompletedTask;
- }
-
- public async Task RegisterReminder()
- {
- await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5));
- }
-
- public async Task RegisterReminderWithTtl(TimeSpan ttl)
- {
- await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), ttl);
- }
+ public async Task RegisterReminderWithTtl(TimeSpan ttl)
+ {
+ await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5), ttl);
+ }
- public async Task RegisterReminderWithRepetitions(int repetitions)
- {
- await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1), repetitions);
- }
+ public async Task RegisterReminderWithRepetitions(int repetitions)
+ {
+ await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1), repetitions);
+ }
- public async Task RegisterReminderWithTtlAndRepetitions(TimeSpan ttl, int repetitions)
- {
- await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1), repetitions, ttl);
- }
+ public async Task RegisterReminderWithTtlAndRepetitions(TimeSpan ttl, int repetitions)
+ {
+ await this.RegisterReminderAsync("TestReminder", null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1), repetitions, ttl);
+ }
- public async Task GetReminder()
- {
- var reminder = await this.GetReminderAsync("TestReminder");
+ public async Task GetReminder()
+ {
+ var reminder = await this.GetReminderAsync("TestReminder");
- return reminder is not null
- ? new ActorReminderData
- {
- Name = reminder.Name,
- Period = reminder.Period,
- DueTime = reminder.DueTime
- }
- : null;
- }
+ return reminder is not null
+ ? new ActorReminderData
+ {
+ Name = reminder.Name,
+ Period = reminder.Period,
+ DueTime = reminder.DueTime
+ }
+ : null;
+ }
- public Task UnregisterReminder()
+ public Task UnregisterReminder()
+ {
+ return this.UnregisterReminderAsync("TestReminder");
+ }
+
+ public async Task ReceiveReminderAsync(string reminderName, byte[] state, TimeSpan dueTime, TimeSpan period)
+ {
+ // This method is invoked when an actor reminder is fired.
+ var actorState = await this.StateManager.GetStateAsync(StateName);
+ var updatedActorState = actorState with
{
- return this.UnregisterReminderAsync("TestReminder");
- }
+ PropertyB = $"Reminder triggered at '{DateTime.Now:yyyy-MM-ddTHH:mm:ss}'"
+ };
+ await this.StateManager.SetStateAsync(StateName, updatedActorState, ttl: TimeSpan.FromMinutes(5));
+ }
- public async Task ReceiveReminderAsync(string reminderName, byte[] state, TimeSpan dueTime, TimeSpan period)
+ class TimerParams
+ {
+ public int IntParam { get; set; }
+ public string? StringParam { get; set; }
+ }
+
+ ///
+ public Task RegisterTimer()
+ {
+ var timerParams = new TimerParams
{
- // This method is invoked when an actor reminder is fired.
- var actorState = await this.StateManager.GetStateAsync(StateName);
- actorState.PropertyB = $"Reminder triggered at '{DateTime.Now:yyyy-MM-ddTHH:mm:ss}'";
- await this.StateManager.SetStateAsync(StateName, actorState, ttl: TimeSpan.FromMinutes(5));
- }
+ IntParam = 100,
+ StringParam = "timer test",
+ };
- class TimerParams
+ var serializedTimerParams = JsonSerializer.SerializeToUtf8Bytes(timerParams);
+ return this.RegisterTimerAsync("TestTimer", nameof(this.TimerCallback), serializedTimerParams, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3));
+ }
+
+ public Task RegisterTimerWithTtl(TimeSpan ttl)
+ {
+ var timerParams = new TimerParams
{
- public int IntParam { get; set; }
- public string StringParam { get; set; }
- }
+ IntParam = 100,
+ StringParam = "timer test",
+ };
- ///
- public Task RegisterTimer()
+ var serializedTimerParams = JsonSerializer.SerializeToUtf8Bytes(timerParams);
+ return this.RegisterTimerAsync("TestTimer", nameof(this.TimerCallback), serializedTimerParams, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3), ttl);
+ }
+
+ public Task UnregisterTimer()
+ {
+ return this.UnregisterTimerAsync("TestTimer");
+ }
+
+ // This method is called whenever an actor is activated.
+ // An actor is activated the first time any of its methods are invoked.
+ protected override Task OnActivateAsync()
+ {
+ // Provides opportunity to perform some optional setup.
+ return Task.CompletedTask;
+ }
+
+ // This method is called whenever an actor is deactivated after a period of inactivity.
+ protected override Task OnDeactivateAsync()
+ {
+ // Provides Opportunity to perform optional cleanup.
+ return Task.CompletedTask;
+ }
+
+ ///
+ /// This method is called when the timer is triggered based on its registration.
+ /// It updates the PropertyA value.
+ ///
+ /// Timer input data.
+ /// A task that represents the asynchronous operation.
+ public async Task TimerCallback(byte[] data)
+ {
+ var state = await this.StateManager.GetStateAsync(StateName);
+ var updatedState = state with { PropertyA = $"Timer triggered at '{DateTime.Now:yyyyy-MM-ddTHH:mm:s}'" };
+ await this.StateManager.SetStateAsync(StateName, updatedState, ttl: TimeSpan.FromMinutes(5));
+ var timerParams = JsonSerializer.Deserialize(data);
+ if (timerParams != null)
{
- var timerParams = new TimerParams
- {
- IntParam = 100,
- StringParam = "timer test",
- };
-
- var serializedTimerParams = JsonSerializer.SerializeToUtf8Bytes(timerParams);
- return this.RegisterTimerAsync("TestTimer", nameof(this.TimerCallback), serializedTimerParams, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3));
- }
-
- public Task RegisterTimerWithTtl(TimeSpan ttl)
- {
- var timerParams = new TimerParams
- {
- IntParam = 100,
- StringParam = "timer test",
- };
-
- var serializedTimerParams = JsonSerializer.SerializeToUtf8Bytes(timerParams);
- return this.RegisterTimerAsync("TestTimer", nameof(this.TimerCallback), serializedTimerParams, TimeSpan.FromSeconds(3), TimeSpan.FromSeconds(3), ttl);
- }
-
- public Task UnregisterTimer()
- {
- return this.UnregisterTimerAsync("TestTimer");
- }
-
- // This method is called whenever an actor is activated.
- // An actor is activated the first time any of its methods are invoked.
- protected override Task OnActivateAsync()
- {
- // Provides opportunity to perform some optional setup.
- return Task.CompletedTask;
- }
-
- // This method is called whenever an actor is deactivated after a period of inactivity.
- protected override Task OnDeactivateAsync()
- {
- // Provides Opportunity to perform optional cleanup.
- return Task.CompletedTask;
- }
-
- ///
- /// This method is called when the timer is triggered based on its registration.
- /// It updates the PropertyA value.
- ///
- /// Timer input data.
- /// A task that represents the asynchronous operation.
- public async Task TimerCallback(byte[] data)
- {
- var state = await this.StateManager.GetStateAsync(StateName);
- state.PropertyA = $"Timer triggered at '{DateTime.Now:yyyyy-MM-ddTHH:mm:s}'";
- await this.StateManager.SetStateAsync(StateName, state, ttl: TimeSpan.FromMinutes(5));
- var timerParams = JsonSerializer.Deserialize(data);
- Console.WriteLine("Timer parameter1: " + timerParams.IntParam);
- Console.WriteLine("Timer parameter2: " + timerParams.StringParam);
- }
-
- public async Task GetAccountBalance()
- {
- var starting = new AccountBalance()
- {
- AccountId = this.Id.GetId(),
- Balance = 100m, // Start new accounts with 100, we're pretty generous.
- };
-
- var balance = await this.StateManager.GetOrAddStateAsync("balance", starting);
- return balance;
- }
-
- public async Task Withdraw(WithdrawRequest withdraw)
- {
- var starting = new AccountBalance()
- {
- AccountId = this.Id.GetId(),
- Balance = 100m, // Start new accounts with 100, we're pretty generous.
- };
-
- var balance = await this.StateManager.GetOrAddStateAsync("balance", starting);
-
- // Throws Overdraft exception if the account doesn't have enough money.
- var updated = this.bank.Withdraw(balance.Balance, withdraw.Amount);
-
- balance.Balance = updated;
- await this.StateManager.SetStateAsync("balance", balance);
+ Console.WriteLine($"Timer parameter1: {timerParams.IntParam}");
+ Console.WriteLine($"Timer parameter2: {timerParams.StringParam ?? ""}");
}
}
+
+ public async Task GetAccountBalance()
+ {
+ var starting = new AccountBalance(this.Id.GetId(), 100m); // Start new accounts with 100 million; we're pretty generous
+
+ var balance = await this.StateManager.GetOrAddStateAsync("balance", starting);
+ return balance;
+ }
+
+ public async Task Withdraw(WithdrawRequest withdraw)
+ {
+ var starting = new AccountBalance(this.Id.GetId(), 100m); // Start new accounts with 100 million; we're pretty generous.
+
+ var balance = await this.StateManager.GetOrAddStateAsync("balance", starting);
+
+ // Throws Overdraft exception if the account doesn't have enough money.
+ var updated = bank.Withdraw(balance.Balance, withdraw.Amount);
+
+ balance = balance with { Balance = updated };
+ await this.StateManager.SetStateAsync("balance", balance);
+ }
}
diff --git a/examples/Actor/DemoActor/DemoActor.csproj b/examples/Actor/DemoActor/DemoActor.csproj
index 24a42ee0..f6bf9e8e 100644
--- a/examples/Actor/DemoActor/DemoActor.csproj
+++ b/examples/Actor/DemoActor/DemoActor.csproj
@@ -1,13 +1,10 @@
-
- net6
-
-
true
true
demo-actor
+ enable
@@ -18,7 +15,7 @@
-
+
diff --git a/examples/Actor/DemoActor/Program.cs b/examples/Actor/DemoActor/Program.cs
index 1d538b47..575bc718 100644
--- a/examples/Actor/DemoActor/Program.cs
+++ b/examples/Actor/DemoActor/Program.cs
@@ -11,23 +11,23 @@
// limitations under the License.
// ------------------------------------------------------------------------
-using Microsoft.AspNetCore.Hosting;
+using DemoActor;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-namespace DemoActor
+var builder = WebApplication.CreateBuilder(args);
+builder.Services.AddSingleton();
+builder.Services.AddActors(options =>
{
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
+ options.Actors.RegisterActor();
+});
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
- }
+var app = builder.Build();
+if (app.Environment.IsDevelopment())
+{
+ app.UseDeveloperExceptionPage();
}
+
+app.UseRouting();
+app.MapActorsHandlers();
diff --git a/examples/Actor/DemoActor/Startup.cs b/examples/Actor/DemoActor/Startup.cs
deleted file mode 100644
index f1165e3c..00000000
--- a/examples/Actor/DemoActor/Startup.cs
+++ /dev/null
@@ -1,59 +0,0 @@
-// ------------------------------------------------------------------------
-// Copyright 2021 The Dapr Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ------------------------------------------------------------------------
-
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-
-namespace DemoActor
-{
- public class Startup
- {
- public Startup(IConfiguration configuration)
- {
- this.Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddSingleton();
- services.AddActors(options =>
- {
- options.Actors.RegisterActor();
- });
- }
-
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
- else
- {
- app.UseHsts();
- }
-
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapActorsHandlers();
- });
- }
- }
-}
diff --git a/examples/Actor/IDemoActor/IDemoActor.cs b/examples/Actor/IDemoActor/IDemoActor.cs
deleted file mode 100644
index 6f2d3280..00000000
--- a/examples/Actor/IDemoActor/IDemoActor.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-// ------------------------------------------------------------------------
-// Copyright 2021 The Dapr Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ------------------------------------------------------------------------
-
-using System;
-using System.Threading.Tasks;
-using Dapr.Actors;
-
-namespace IDemoActor
-{
- ///
- /// Interface for Actor method.
- ///
- public interface IDemoActor : IActor
- {
- ///
- /// Method to save data.
- ///
- /// DAta to save.
- /// TTL of state key.
- /// A task that represents the asynchronous save operation.
- Task SaveData(MyData data, TimeSpan ttl);
-
- ///
- /// Method to get data.
- ///
- /// A task that represents the asynchronous save operation.
- Task GetData();
-
- ///
- /// A test method which throws exception.
- ///
- /// A task that represents the asynchronous save operation.
- Task TestThrowException();
-
- ///
- /// A test method which validates calls for methods with no arguments and no return types.
- ///
- /// A task that represents the asynchronous save operation.
- Task TestNoArgumentNoReturnType();
-
- ///
- /// Registers a reminder.
- ///
- /// A task that represents the asynchronous save operation.
- Task RegisterReminder();
-
- ///
- /// Registers a reminder.
- ///
- /// TimeSpan that dictates when the reminder expires.
- /// A task that represents the asynchronous save operation.
- Task RegisterReminderWithTtl(TimeSpan ttl);
-
- ///
- /// Unregisters the registered reminder.
- ///
- /// Task representing the operation.
- Task UnregisterReminder();
-
- ///
- /// Registers a timer.
- ///
- /// A task that represents the asynchronous save operation.
- Task RegisterTimer();
-
- ///
- /// Registers a timer.
- ///
- /// Optional TimeSpan that dictates when the timer expires.
- /// A task that represents the asynchronous save operation.
- Task RegisterTimerWithTtl(TimeSpan ttl);
-
- ///
- /// Registers a reminder with repetitions.
- ///
- /// The number of repetitions for which the reminder should be invoked.
- /// A task that represents the asynchronous save operation.
- Task RegisterReminderWithRepetitions(int repetitions);
-
- ///
- /// Registers a reminder with ttl and repetitions.
- ///
- /// TimeSpan that dictates when the timer expires.
- /// The number of repetitions for which the reminder should be invoked.
- /// A task that represents the asynchronous save operation.
- Task RegisterReminderWithTtlAndRepetitions(TimeSpan ttl, int repetitions);
-
- ///
- /// Gets the registered reminder.
- ///
- /// The name of the reminder.
- /// A task that returns the reminder after completion.
- Task GetReminder();
-
- ///
- /// Unregisters the registered timer.
- ///
- /// A task that represents the asynchronous save operation.
- Task UnregisterTimer();
- }
-
- ///
- /// Data Used by the Sample Actor.
- ///
- public class MyData
- {
- ///
- /// Gets or sets the value for PropertyA.
- ///
- public string PropertyA { get; set; }
-
- ///
- /// Gets or sets the value for PropertyB.
- ///
- public string PropertyB { get; set; }
-
- ///
- public override string ToString()
- {
- var propAValue = this.PropertyA ?? "null";
- var propBValue = this.PropertyB ?? "null";
- return $"PropertyA: {propAValue}, PropertyB: {propBValue}";
- }
- }
-
- public class ActorReminderData
- {
- public string Name { get; set; }
-
- public TimeSpan DueTime { get; set; }
-
- public TimeSpan Period { get; set; }
-
- public override string ToString()
- {
- return $"Name: {this.Name}, DueTime: {this.DueTime}, Period: {this.Period}";
- }
- }
-}
diff --git a/examples/Actor/README.md b/examples/Actor/README.md
index 89b6bf0b..34cd496e 100644
--- a/examples/Actor/README.md
+++ b/examples/Actor/README.md
@@ -4,7 +4,7 @@ The Actor example shows how to create a virtual actor (`DemoActor`) and invoke i
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://github.com/dapr/dotnet-sdk/)
diff --git a/examples/AspNetCore/ControllerSample/Account.cs b/examples/AspNetCore/ControllerSample/Account.cs
index ed2bddd2..bcd0d350 100644
--- a/examples/AspNetCore/ControllerSample/Account.cs
+++ b/examples/AspNetCore/ControllerSample/Account.cs
@@ -11,21 +11,20 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace ControllerSample
+namespace ControllerSample;
+
+///
+/// Class representing an Account for samples.
+///
+public class Account
{
///
- /// Class representing an Account for samples.
+ /// Gets or sets account id.
///
- public class Account
- {
- ///
- /// Gets or sets account id.
- ///
- public string Id { get; set; }
+ public string Id { get; set; }
- ///
- /// Gets or sets account balance.
- ///
- public decimal Balance { get; set; }
- }
+ ///
+ /// Gets or sets account balance.
+ ///
+ public decimal Balance { get; set; }
}
\ No newline at end of file
diff --git a/examples/AspNetCore/ControllerSample/ControllerSample.csproj b/examples/AspNetCore/ControllerSample/ControllerSample.csproj
index 6dbe750a..061510f9 100644
--- a/examples/AspNetCore/ControllerSample/ControllerSample.csproj
+++ b/examples/AspNetCore/ControllerSample/ControllerSample.csproj
@@ -1,9 +1,5 @@
-
- net6
-
-
diff --git a/examples/AspNetCore/ControllerSample/Controllers/SampleController.cs b/examples/AspNetCore/ControllerSample/Controllers/SampleController.cs
index 5b339288..195c5ea5 100644
--- a/examples/AspNetCore/ControllerSample/Controllers/SampleController.cs
+++ b/examples/AspNetCore/ControllerSample/Controllers/SampleController.cs
@@ -13,286 +13,285 @@
using System.Linq;
-namespace ControllerSample.Controllers
+namespace ControllerSample.Controllers;
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Dapr;
+using Dapr.AspNetCore;
+using Dapr.Client;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Logging;
+
+///
+/// Sample showing Dapr integration with controller.
+///
+[ApiController]
+public class SampleController : ControllerBase
{
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Text.Json;
- using System.Threading.Tasks;
- using Dapr;
- using Dapr.AspNetCore;
- using Dapr.Client;
- using Microsoft.AspNetCore.Mvc;
- using Microsoft.Extensions.Logging;
+ ///
+ /// SampleController Constructor with logger injection
+ ///
+ ///
+ public SampleController(ILogger logger)
+ {
+ this.logger = logger;
+ }
///
- /// Sample showing Dapr integration with controller.
+ /// State store name.
///
- [ApiController]
- public class SampleController : ControllerBase
+ public const string StoreName = "statestore";
+
+ private readonly ILogger logger;
+
+ ///
+ /// Gets the account information as specified by the id.
+ ///
+ /// Account information for the id from Dapr state store.
+ /// Account information.
+ [HttpGet("{account}")]
+ public ActionResult Get([FromState(StoreName)] StateEntry account)
{
- ///
- /// SampleController Constructor with logger injection
- ///
- ///
- public SampleController(ILogger logger)
+ if (account.Value is null)
{
- this.logger = logger;
+ return this.NotFound();
}
- ///
- /// State store name.
- ///
- public const string StoreName = "statestore";
+ return account.Value;
+ }
- private readonly ILogger logger;
+ ///
+ /// Method for depositing to account as specified in transaction.
+ ///
+ /// Transaction info.
+ /// State client to interact with Dapr runtime.
+ /// A representing the result of the asynchronous operation.
+ /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
+ [Topic("pubsub", "deposit", "amountDeadLetterTopic", false)]
+ [HttpPost("deposit")]
+ public async Task> Deposit(Transaction transaction, [FromServices] DaprClient daprClient)
+ {
+ // Example reading cloudevent properties from the headers
+ var headerEntries = Request.Headers.Aggregate("", (current, header) => current + ($"------- Header: {header.Key} : {header.Value}" + Environment.NewLine));
- ///
- /// Gets the account information as specified by the id.
- ///
- /// Account information for the id from Dapr state store.
- /// Account information.
- [HttpGet("{account}")]
- public ActionResult Get([FromState(StoreName)] StateEntry account)
+ logger.LogInformation(headerEntries);
+
+ logger.LogInformation("Enter deposit");
+ var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
+ state.Value ??= new Account() { Id = transaction.Id, };
+ logger.LogInformation("Id is {0}, the amount to be deposited is {1}", transaction.Id, transaction.Amount);
+
+ if (transaction.Amount < 0m)
{
- if (account.Value is null)
- {
- return this.NotFound();
- }
-
- return account.Value;
- }
-
- ///
- /// Method for depositing to account as specified in transaction.
- ///
- /// Transaction info.
- /// State client to interact with Dapr runtime.
- /// A representing the result of the asynchronous operation.
- /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
- [Topic("pubsub", "deposit", "amountDeadLetterTopic", false)]
- [HttpPost("deposit")]
- public async Task> Deposit(Transaction transaction, [FromServices] DaprClient daprClient)
- {
- // Example reading cloudevent properties from the headers
- var headerEntries = Request.Headers.Aggregate("", (current, header) => current + ($"------- Header: {header.Key} : {header.Value}" + Environment.NewLine));
-
- logger.LogInformation(headerEntries);
-
- logger.LogInformation("Enter deposit");
- var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
- state.Value ??= new Account() { Id = transaction.Id, };
- logger.LogInformation("Id is {0}, the amount to be deposited is {1}", transaction.Id, transaction.Amount);
-
- if (transaction.Amount < 0m)
- {
- return BadRequest(new { statusCode = 400, message = "bad request" });
- }
-
- state.Value.Balance += transaction.Amount;
- logger.LogInformation("Balance for Id {0} is {1}", state.Value.Id, state.Value.Balance);
- await state.SaveAsync();
- return state.Value;
- }
-
- ///
- /// Method for depositing multiple times to the account as specified in transaction.
- ///
- /// List of entries of type BulkMessageModel received from dapr.
- /// State client to interact with Dapr runtime.
- /// A representing the result of the asynchronous operation.
- /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
- [Topic("pubsub", "multideposit", "amountDeadLetterTopic", false)]
- [BulkSubscribe("multideposit", 500, 2000)]
- [HttpPost("multideposit")]
- public async Task> MultiDeposit([FromBody]
- BulkSubscribeMessage>
- bulkMessage, [FromServices] DaprClient daprClient)
- {
- logger.LogInformation("Enter bulk deposit");
-
- List entries = new List();
-
- foreach (var entry in bulkMessage.Entries)
- {
- try
- {
- var transaction = entry.Event.Data;
-
- var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
- state.Value ??= new Account() { Id = transaction.Id, };
- logger.LogInformation("Id is {0}, the amount to be deposited is {1}",
- transaction.Id, transaction.Amount);
-
- if (transaction.Amount < 0m)
- {
- return BadRequest(new { statusCode = 400, message = "bad request" });
- }
-
- state.Value.Balance += transaction.Amount;
- logger.LogInformation("Balance is {0}", state.Value.Balance);
- await state.SaveAsync();
- entries.Add(
- new BulkSubscribeAppResponseEntry(entry.EntryId, BulkSubscribeAppResponseStatus.SUCCESS));
- }
- catch (Exception e)
- {
- logger.LogError(e.Message);
- entries.Add(new BulkSubscribeAppResponseEntry(entry.EntryId, BulkSubscribeAppResponseStatus.RETRY));
- }
- }
-
- return new BulkSubscribeAppResponse(entries);
- }
-
- ///
- /// Method for viewing the error message when the deposit/withdrawal amounts
- /// are negative.
- ///
- /// Transaction info.
- [Topic("pubsub", "amountDeadLetterTopic")]
- [HttpPost("deadLetterTopicRoute")]
- public ActionResult ViewErrorMessage(Transaction transaction)
- {
- logger.LogInformation("The amount cannot be negative: {0}", transaction.Amount);
- return Ok();
- }
-
- ///
- /// Method for withdrawing from account as specified in transaction.
- ///
- /// Transaction info.
- /// State client to interact with Dapr runtime.
- /// A representing the result of the asynchronous operation.
- /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
- [Topic("pubsub", "withdraw", "amountDeadLetterTopic", false)]
- [HttpPost("withdraw")]
- public async Task> Withdraw(Transaction transaction, [FromServices] DaprClient daprClient)
- {
- logger.LogInformation("Enter withdraw method...");
- var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
- logger.LogInformation("Id is {0}, the amount to be withdrawn is {1}", transaction.Id, transaction.Amount);
-
- if (state.Value == null)
- {
- return this.NotFound();
- }
-
- if (transaction.Amount < 0m)
- {
- return BadRequest(new { statusCode = 400, message = "bad request" });
- }
-
- state.Value.Balance -= transaction.Amount;
- logger.LogInformation("Balance is {0}", state.Value.Balance);
- await state.SaveAsync();
- return state.Value;
- }
-
- ///
- /// Method for withdrawing from account as specified in transaction.
- ///
- /// Transaction info.
- /// State client to interact with Dapr runtime.
- /// A representing the result of the asynchronous operation.
- /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
- [Topic("pubsub", "withdraw", "event.type ==\"withdraw.v2\"", 1)]
- [HttpPost("withdraw.v2")]
- public async Task> WithdrawV2(TransactionV2 transaction,
- [FromServices] DaprClient daprClient)
- {
- logger.LogInformation("Enter withdraw.v2");
- if (transaction.Channel == "mobile" && transaction.Amount > 10000)
- {
- return this.Unauthorized("mobile transactions for large amounts are not permitted.");
- }
-
- var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
-
- if (state.Value == null)
- {
- return this.NotFound();
- }
-
- state.Value.Balance -= transaction.Amount;
- await state.SaveAsync();
- return state.Value;
- }
-
- ///
- /// Method for depositing to account as specified in transaction via a raw message.
- ///
- /// Transaction info.
- /// State client to interact with Dapr runtime.
- /// A representing the result of the asynchronous operation.
- /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
- [Topic("pubsub", "rawDeposit", true)]
- [HttpPost("rawDeposit")]
- public async Task> RawDeposit([FromBody] JsonDocument rawTransaction,
- [FromServices] DaprClient daprClient)
- {
- var transactionString = rawTransaction.RootElement.GetProperty("data_base64").GetString();
- logger.LogInformation(
- $"Enter deposit: {transactionString} - {Encoding.UTF8.GetString(Convert.FromBase64String(transactionString))}");
- var transactionJson = JsonSerializer.Deserialize(Convert.FromBase64String(transactionString));
- var transaction =
- JsonSerializer.Deserialize(transactionJson.RootElement.GetProperty("data").GetRawText());
- var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
- state.Value ??= new Account() { Id = transaction.Id, };
- logger.LogInformation("Id is {0}, the amount to be deposited is {1}", transaction.Id, transaction.Amount);
-
- if (transaction.Amount < 0m)
- {
- return BadRequest(new { statusCode = 400, message = "bad request" });
- }
-
- state.Value.Balance += transaction.Amount;
- logger.LogInformation("Balance is {0}", state.Value.Balance);
- await state.SaveAsync();
- return state.Value;
- }
-
- ///
- /// Method for returning a BadRequest result which will cause Dapr sidecar to throw an RpcException
- ///
- [HttpPost("throwException")]
- public async Task> ThrowException(Transaction transaction,
- [FromServices] DaprClient daprClient)
- {
- logger.LogInformation("Enter ThrowException");
- var task = Task.Delay(10);
- await task;
return BadRequest(new { statusCode = 400, message = "bad request" });
}
- ///
- ///
- /// Method which uses for binding this endpoint to a subscription.
- ///
- ///
- /// This endpoint will be bound to a subscription where the topic name is the value of the environment variable 'CUSTOM_TOPIC'
- /// and the pubsub name is the value of the environment variable 'CUSTOM_PUBSUB'.
- ///
- ///
- [CustomTopic("%CUSTOM_PUBSUB%", "%CUSTOM_TOPIC%")]
- [HttpPost("exampleCustomTopic")]
- public ActionResult ExampleCustomTopic(Transaction transaction)
+ state.Value.Balance += transaction.Amount;
+ logger.LogInformation("Balance for Id {0} is {1}", state.Value.Id, state.Value.Balance);
+ await state.SaveAsync();
+ return state.Value;
+ }
+
+ ///
+ /// Method for depositing multiple times to the account as specified in transaction.
+ ///
+ /// List of entries of type BulkMessageModel received from dapr.
+ /// State client to interact with Dapr runtime.
+ /// A representing the result of the asynchronous operation.
+ /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
+ [Topic("pubsub", "multideposit", "amountDeadLetterTopic", false)]
+ [BulkSubscribe("multideposit", 500, 2000)]
+ [HttpPost("multideposit")]
+ public async Task> MultiDeposit([FromBody]
+ BulkSubscribeMessage>
+ bulkMessage, [FromServices] DaprClient daprClient)
+ {
+ logger.LogInformation("Enter bulk deposit");
+
+ List entries = new List();
+
+ foreach (var entry in bulkMessage.Entries)
{
- return Ok();
+ try
+ {
+ var transaction = entry.Event.Data;
+
+ var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
+ state.Value ??= new Account() { Id = transaction.Id, };
+ logger.LogInformation("Id is {0}, the amount to be deposited is {1}",
+ transaction.Id, transaction.Amount);
+
+ if (transaction.Amount < 0m)
+ {
+ return BadRequest(new { statusCode = 400, message = "bad request" });
+ }
+
+ state.Value.Balance += transaction.Amount;
+ logger.LogInformation("Balance is {0}", state.Value.Balance);
+ await state.SaveAsync();
+ entries.Add(
+ new BulkSubscribeAppResponseEntry(entry.EntryId, BulkSubscribeAppResponseStatus.SUCCESS));
+ }
+ catch (Exception e)
+ {
+ logger.LogError(e.Message);
+ entries.Add(new BulkSubscribeAppResponseEntry(entry.EntryId, BulkSubscribeAppResponseStatus.RETRY));
+ }
}
- ///
- /// Method which uses for binding this endpoint to a subscription and adds routingkey metadata.
- ///
- ///
- ///
- [Topic("pubsub", "topicmetadata")]
- [TopicMetadata("routingKey", "keyA")]
- [HttpPost("examplecustomtopicmetadata")]
- public ActionResult ExampleCustomTopicMetadata(Transaction transaction)
- {
- return Ok();
- }
+ return new BulkSubscribeAppResponse(entries);
}
-}
+
+ ///
+ /// Method for viewing the error message when the deposit/withdrawal amounts
+ /// are negative.
+ ///
+ /// Transaction info.
+ [Topic("pubsub", "amountDeadLetterTopic")]
+ [HttpPost("deadLetterTopicRoute")]
+ public ActionResult ViewErrorMessage(Transaction transaction)
+ {
+ logger.LogInformation("The amount cannot be negative: {0}", transaction.Amount);
+ return Ok();
+ }
+
+ ///
+ /// Method for withdrawing from account as specified in transaction.
+ ///
+ /// Transaction info.
+ /// State client to interact with Dapr runtime.
+ /// A representing the result of the asynchronous operation.
+ /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
+ [Topic("pubsub", "withdraw", "amountDeadLetterTopic", false)]
+ [HttpPost("withdraw")]
+ public async Task> Withdraw(Transaction transaction, [FromServices] DaprClient daprClient)
+ {
+ logger.LogInformation("Enter withdraw method...");
+ var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
+ logger.LogInformation("Id is {0}, the amount to be withdrawn is {1}", transaction.Id, transaction.Amount);
+
+ if (state.Value == null)
+ {
+ return this.NotFound();
+ }
+
+ if (transaction.Amount < 0m)
+ {
+ return BadRequest(new { statusCode = 400, message = "bad request" });
+ }
+
+ state.Value.Balance -= transaction.Amount;
+ logger.LogInformation("Balance is {0}", state.Value.Balance);
+ await state.SaveAsync();
+ return state.Value;
+ }
+
+ ///
+ /// Method for withdrawing from account as specified in transaction.
+ ///
+ /// Transaction info.
+ /// State client to interact with Dapr runtime.
+ /// A representing the result of the asynchronous operation.
+ /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
+ [Topic("pubsub", "withdraw", "event.type ==\"withdraw.v2\"", 1)]
+ [HttpPost("withdraw.v2")]
+ public async Task> WithdrawV2(TransactionV2 transaction,
+ [FromServices] DaprClient daprClient)
+ {
+ logger.LogInformation("Enter withdraw.v2");
+ if (transaction.Channel == "mobile" && transaction.Amount > 10000)
+ {
+ return this.Unauthorized("mobile transactions for large amounts are not permitted.");
+ }
+
+ var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
+
+ if (state.Value == null)
+ {
+ return this.NotFound();
+ }
+
+ state.Value.Balance -= transaction.Amount;
+ await state.SaveAsync();
+ return state.Value;
+ }
+
+ ///
+ /// Method for depositing to account as specified in transaction via a raw message.
+ ///
+ /// Transaction info.
+ /// State client to interact with Dapr runtime.
+ /// A representing the result of the asynchronous operation.
+ /// "pubsub", the first parameter into the Topic attribute, is name of the default pub/sub configured by the Dapr CLI.
+ [Topic("pubsub", "rawDeposit", true)]
+ [HttpPost("rawDeposit")]
+ public async Task> RawDeposit([FromBody] JsonDocument rawTransaction,
+ [FromServices] DaprClient daprClient)
+ {
+ var transactionString = rawTransaction.RootElement.GetProperty("data_base64").GetString();
+ logger.LogInformation(
+ $"Enter deposit: {transactionString} - {Encoding.UTF8.GetString(Convert.FromBase64String(transactionString))}");
+ var transactionJson = JsonSerializer.Deserialize(Convert.FromBase64String(transactionString));
+ var transaction =
+ JsonSerializer.Deserialize(transactionJson.RootElement.GetProperty("data").GetRawText());
+ var state = await daprClient.GetStateEntryAsync(StoreName, transaction.Id);
+ state.Value ??= new Account() { Id = transaction.Id, };
+ logger.LogInformation("Id is {0}, the amount to be deposited is {1}", transaction.Id, transaction.Amount);
+
+ if (transaction.Amount < 0m)
+ {
+ return BadRequest(new { statusCode = 400, message = "bad request" });
+ }
+
+ state.Value.Balance += transaction.Amount;
+ logger.LogInformation("Balance is {0}", state.Value.Balance);
+ await state.SaveAsync();
+ return state.Value;
+ }
+
+ ///
+ /// Method for returning a BadRequest result which will cause Dapr sidecar to throw an RpcException
+ ///
+ [HttpPost("throwException")]
+ public async Task> ThrowException(Transaction transaction,
+ [FromServices] DaprClient daprClient)
+ {
+ logger.LogInformation("Enter ThrowException");
+ var task = Task.Delay(10);
+ await task;
+ return BadRequest(new { statusCode = 400, message = "bad request" });
+ }
+
+ ///
+ ///
+ /// Method which uses for binding this endpoint to a subscription.
+ ///
+ ///
+ /// This endpoint will be bound to a subscription where the topic name is the value of the environment variable 'CUSTOM_TOPIC'
+ /// and the pubsub name is the value of the environment variable 'CUSTOM_PUBSUB'.
+ ///
+ ///
+ [CustomTopic("%CUSTOM_PUBSUB%", "%CUSTOM_TOPIC%")]
+ [HttpPost("exampleCustomTopic")]
+ public ActionResult ExampleCustomTopic(Transaction transaction)
+ {
+ return Ok();
+ }
+
+ ///
+ /// Method which uses for binding this endpoint to a subscription and adds routingkey metadata.
+ ///
+ ///
+ ///
+ [Topic("pubsub", "topicmetadata")]
+ [TopicMetadata("routingKey", "keyA")]
+ [HttpPost("examplecustomtopicmetadata")]
+ public ActionResult ExampleCustomTopicMetadata(Transaction transaction)
+ {
+ return Ok();
+ }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/ControllerSample/CustomTopicAttribute.cs b/examples/AspNetCore/ControllerSample/CustomTopicAttribute.cs
index 5c9996ae..eb96ba89 100644
--- a/examples/AspNetCore/ControllerSample/CustomTopicAttribute.cs
+++ b/examples/AspNetCore/ControllerSample/CustomTopicAttribute.cs
@@ -13,33 +13,32 @@
using Dapr.AspNetCore;
-namespace ControllerSample
+namespace ControllerSample;
+
+using System;
+using Dapr;
+
+///
+/// Sample custom implementation that returns topic metadata from environment variables.
+///
+[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
+public class CustomTopicAttribute : Attribute, ITopicMetadata
{
- using System;
- using Dapr;
-
- ///
- /// Sample custom implementation that returns topic metadata from environment variables.
- ///
- [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
- public class CustomTopicAttribute : Attribute, ITopicMetadata
+ public CustomTopicAttribute(string pubsubName, string name)
{
- public CustomTopicAttribute(string pubsubName, string name)
- {
- this.PubsubName = Environment.ExpandEnvironmentVariables(pubsubName);
- this.Name = Environment.ExpandEnvironmentVariables(name);
- }
-
- ///
- public string PubsubName { get; }
-
- ///
- public string Name { get; }
-
- ///
- public new string Match { get; }
-
- ///
- public int Priority { get; }
+ this.PubsubName = Environment.ExpandEnvironmentVariables(pubsubName);
+ this.Name = Environment.ExpandEnvironmentVariables(name);
}
-}
+
+ ///
+ public string PubsubName { get; }
+
+ ///
+ public string Name { get; }
+
+ ///
+ public new string Match { get; }
+
+ ///
+ public int Priority { get; }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/ControllerSample/Program.cs b/examples/AspNetCore/ControllerSample/Program.cs
index 251d11fc..68eb85cc 100644
--- a/examples/AspNetCore/ControllerSample/Program.cs
+++ b/examples/AspNetCore/ControllerSample/Program.cs
@@ -11,35 +11,34 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace ControllerSample
+namespace ControllerSample;
+
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+
+///
+/// Controller Sample.
+///
+public class Program
{
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
+ ///
+ /// Main for Controller Sample.
+ ///
+ /// Arguments.
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
///
- /// Controller Sample.
+ /// Creates WebHost Builder.
///
- public class Program
- {
- ///
- /// Main for Controller Sample.
- ///
- /// Arguments.
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
-
- ///
- /// Creates WebHost Builder.
- ///
- /// Arguments.
- /// Returns IHostbuilder.
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
- }
-}
+ /// Arguments.
+ /// Returns IHostbuilder.
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/ControllerSample/README.md b/examples/AspNetCore/ControllerSample/README.md
index 3b2ca02b..cf2afc06 100644
--- a/examples/AspNetCore/ControllerSample/README.md
+++ b/examples/AspNetCore/ControllerSample/README.md
@@ -12,7 +12,7 @@ The application also registers for pub/sub with the `deposit`, `multideposit` an
## Prerequisitess
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/AspNetCore/ControllerSample/Startup.cs b/examples/AspNetCore/ControllerSample/Startup.cs
index ddc6d1c5..17afa06b 100644
--- a/examples/AspNetCore/ControllerSample/Startup.cs
+++ b/examples/AspNetCore/ControllerSample/Startup.cs
@@ -16,68 +16,67 @@ using Dapr;
using Dapr.AspNetCore;
-namespace ControllerSample
+namespace ControllerSample;
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+///
+/// Startup class.
+///
+public class Startup
{
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Hosting;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Configuration.
+ public Startup(IConfiguration configuration)
+ {
+ this.Configuration = configuration;
+ }
///
- /// Startup class.
+ /// Gets the configuration.
///
- public class Startup
+ public IConfiguration Configuration { get; }
+
+ ///
+ /// Configures Services.
+ ///
+ /// Service Collection.
+ public void ConfigureServices(IServiceCollection services)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// Configuration.
- public Startup(IConfiguration configuration)
- {
- this.Configuration = configuration;
- }
-
- ///
- /// Gets the configuration.
- ///
- public IConfiguration Configuration { get; }
-
- ///
- /// Configures Services.
- ///
- /// Service Collection.
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddControllers().AddDapr();
- }
-
- ///
- /// Configures Application Builder and WebHost environment.
- ///
- /// Application builder.
- /// Webhost environment.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseCloudEvents(new CloudEventsMiddlewareOptions
- {
- ForwardCloudEventPropertiesAsHeaders = true
- });
-
- app.UseAuthorization();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapSubscribeHandler();
- endpoints.MapControllers();
- });
- }
+ services.AddControllers().AddDapr();
}
-}
+
+ ///
+ /// Configures Application Builder and WebHost environment.
+ ///
+ /// Application builder.
+ /// Webhost environment.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseRouting();
+
+ app.UseCloudEvents(new CloudEventsMiddlewareOptions
+ {
+ ForwardCloudEventPropertiesAsHeaders = true
+ });
+
+ app.UseAuthorization();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapSubscribeHandler();
+ endpoints.MapControllers();
+ });
+ }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/ControllerSample/Transaction.cs b/examples/AspNetCore/ControllerSample/Transaction.cs
index 2d6f5a5a..5b7a1c86 100644
--- a/examples/AspNetCore/ControllerSample/Transaction.cs
+++ b/examples/AspNetCore/ControllerSample/Transaction.cs
@@ -11,24 +11,23 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace ControllerSample
+namespace ControllerSample;
+
+using System.ComponentModel.DataAnnotations;
+
+///
+/// Represents a transaction used by sample code.
+///
+public class Transaction
{
- using System.ComponentModel.DataAnnotations;
+ ///
+ /// Gets or sets account id for the transaction.
+ ///
+ [Required]
+ public string Id { get; set; }
///
- /// Represents a transaction used by sample code.
- ///
- public class Transaction
- {
- ///
- /// Gets or sets account id for the transaction.
- ///
- [Required]
- public string Id { get; set; }
-
- ///
- /// Gets or sets amount for the transaction.
- ///
+/// Represents a transaction used by sample code.
+///
+public class TransactionV2
{
- using System.ComponentModel.DataAnnotations;
+ ///
+ /// Gets or sets account id for the transaction.
+ ///
+ [Required]
+ public string Id { get; set; }
///
- /// Represents a transaction used by sample code.
+ /// Gets or sets amount for the transaction.
///
- public class TransactionV2
- {
- ///
- /// Gets or sets account id for the transaction.
- ///
- [Required]
- public string Id { get; set; }
+ [Range(0, double.MaxValue)]
+ public decimal Amount { get; set; }
- ///
- /// Gets or sets amount for the transaction.
- ///
- [Range(0, double.MaxValue)]
- public decimal Amount { get; set; }
-
- ///
- /// Gets or sets channel from which this transaction was received.
- ///
- [Required]
- public string Channel { get; set; }
- }
+ ///
+ /// Gets or sets channel from which this transaction was received.
+ ///
+ [Required]
+ public string Channel { get; set; }
}
\ No newline at end of file
diff --git a/examples/AspNetCore/GrpcServiceSample/GrpcServiceSample.csproj b/examples/AspNetCore/GrpcServiceSample/GrpcServiceSample.csproj
index 2319f6a5..5e1a27ed 100644
--- a/examples/AspNetCore/GrpcServiceSample/GrpcServiceSample.csproj
+++ b/examples/AspNetCore/GrpcServiceSample/GrpcServiceSample.csproj
@@ -1,7 +1,6 @@
- net6
true
diff --git a/examples/AspNetCore/GrpcServiceSample/Models/Account.cs b/examples/AspNetCore/GrpcServiceSample/Models/Account.cs
index 0b6f810d..91746bef 100644
--- a/examples/AspNetCore/GrpcServiceSample/Models/Account.cs
+++ b/examples/AspNetCore/GrpcServiceSample/Models/Account.cs
@@ -11,21 +11,20 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace GrpcServiceSample.Models
+namespace GrpcServiceSample.Models;
+
+///
+/// Class representing an Account for samples.
+///
+public class Account
{
///
- /// Class representing an Account for samples.
+ /// Gets or sets account id.
///
- public class Account
- {
- ///
- /// Gets or sets account id.
- ///
- public string Id { get; set; }
+ public string Id { get; set; }
- ///
- /// Gets or sets account balance.
- ///
- public decimal Balance { get; set; }
- }
-}
+ ///
+ /// Gets or sets account balance.
+ ///
+ public decimal Balance { get; set; }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/GrpcServiceSample/Models/GetAccountInput.cs b/examples/AspNetCore/GrpcServiceSample/Models/GetAccountInput.cs
index bcb835bd..7d7f59fc 100644
--- a/examples/AspNetCore/GrpcServiceSample/Models/GetAccountInput.cs
+++ b/examples/AspNetCore/GrpcServiceSample/Models/GetAccountInput.cs
@@ -11,16 +11,15 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace GrpcServiceSample.Models
+namespace GrpcServiceSample.Models;
+
+///
+/// BankService GetAccount input model
+///
+public class GetAccountInput
{
///
- /// BankService GetAccount input model
+ /// Id of account
///
- public class GetAccountInput
- {
- ///
- /// Id of account
- ///
- public string Id { get; set; }
- }
-}
+ public string Id { get; set; }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/GrpcServiceSample/Models/Transaction.cs b/examples/AspNetCore/GrpcServiceSample/Models/Transaction.cs
index 7a1ef7cb..a13e5c5e 100644
--- a/examples/AspNetCore/GrpcServiceSample/Models/Transaction.cs
+++ b/examples/AspNetCore/GrpcServiceSample/Models/Transaction.cs
@@ -13,23 +13,22 @@
using System.ComponentModel.DataAnnotations;
-namespace GrpcServiceSample.Models
+namespace GrpcServiceSample.Models;
+
+///
+/// Represents a transaction used by sample code.
+///
+public class Transaction
{
///
- /// Represents a transaction used by sample code.
+ /// Gets or sets account id for the transaction.
///
- public class Transaction
- {
- ///
- /// Gets or sets account id for the transaction.
- ///
- [Required]
- public string Id { get; set; }
+ [Required]
+ public string Id { get; set; }
- ///
- /// Gets or sets amount for the transaction.
- ///
- [Range(0, double.MaxValue)]
- public decimal Amount { get; set; }
- }
-}
+ ///
+ /// Gets or sets amount for the transaction.
+ ///
+ [Range(0, double.MaxValue)]
+ public decimal Amount { get; set; }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/GrpcServiceSample/Program.cs b/examples/AspNetCore/GrpcServiceSample/Program.cs
index dbec5ba2..d7af0170 100644
--- a/examples/AspNetCore/GrpcServiceSample/Program.cs
+++ b/examples/AspNetCore/GrpcServiceSample/Program.cs
@@ -15,39 +15,38 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.Extensions.Hosting;
-namespace GrpcServiceSample
+namespace GrpcServiceSample;
+
+///
+/// GrpcService Sample
+///
+public class Program
{
///
- /// GrpcService Sample
+ /// Entry point
///
- public class Program
+ ///
+ public static void Main(string[] args)
{
- ///
- /// Entry point
- ///
- ///
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
-
- ///
- /// Creates WebHost Builder.
- ///
- ///
- ///
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.ConfigureKestrel(options =>
- {
- // Setup a HTTP/2 endpoint without TLS.
- options.ListenLocalhost(5050, o => o.Protocols =
- HttpProtocols.Http2);
- });
-
- webBuilder.UseStartup();
- });
+ CreateHostBuilder(args).Build().Run();
}
-}
+
+ ///
+ /// Creates WebHost Builder.
+ ///
+ ///
+ ///
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.ConfigureKestrel(options =>
+ {
+ // Setup a HTTP/2 endpoint without TLS.
+ options.ListenLocalhost(5050, o => o.Protocols =
+ HttpProtocols.Http2);
+ });
+
+ webBuilder.UseStartup();
+ });
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/GrpcServiceSample/README.md b/examples/AspNetCore/GrpcServiceSample/README.md
index d08e96cd..4e0a615e 100644
--- a/examples/AspNetCore/GrpcServiceSample/README.md
+++ b/examples/AspNetCore/GrpcServiceSample/README.md
@@ -11,7 +11,7 @@ The application also registers for pub/sub with the `deposit` and `withdraw` top
## Prerequisitess
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/AspNetCore/GrpcServiceSample/Services/BankingService.cs b/examples/AspNetCore/GrpcServiceSample/Services/BankingService.cs
index 9518fd61..05b03784 100644
--- a/examples/AspNetCore/GrpcServiceSample/Services/BankingService.cs
+++ b/examples/AspNetCore/GrpcServiceSample/Services/BankingService.cs
@@ -22,158 +22,157 @@ using Grpc.Core;
using GrpcServiceSample.Generated;
using Microsoft.Extensions.Logging;
-namespace GrpcServiceSample.Services
+namespace GrpcServiceSample.Services;
+
+///
+/// BankAccount gRPC service
+///
+public class BankingService : AppCallback.AppCallbackBase
{
///
- /// BankAccount gRPC service
+ /// State store name.
///
- public class BankingService : AppCallback.AppCallbackBase
+ public const string StoreName = "statestore";
+
+ private readonly ILogger _logger;
+ private readonly DaprClient _daprClient;
+
+ ///
+ /// Constructor
+ ///
+ ///
+ ///
+ public BankingService(DaprClient daprClient, ILogger logger)
{
- ///
- /// State store name.
- ///
- public const string StoreName = "statestore";
-
- private readonly ILogger _logger;
- private readonly DaprClient _daprClient;
-
- ///
- /// Constructor
- ///
- ///
- ///
- public BankingService(DaprClient daprClient, ILogger logger)
- {
- _daprClient = daprClient;
- _logger = logger;
- }
-
- readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
-
- ///
- /// implement OnIvoke to support getaccount, deposit and withdraw
- ///
- ///
- ///
- ///
- public override async Task OnInvoke(InvokeRequest request, ServerCallContext context)
- {
- var response = new InvokeResponse();
- switch (request.Method)
- {
- case "getaccount":
- var input = request.Data.Unpack();
- var output = await GetAccount(input, context);
- response.Data = Any.Pack(output);
- break;
- case "deposit":
- case "withdraw":
- var transaction = request.Data.Unpack();
- var account = request.Method == "deposit" ?
- await Deposit(transaction, context) :
- await Withdraw(transaction, context);
- response.Data = Any.Pack(account);
- break;
- default:
- break;
- }
- return response;
- }
-
- ///
- /// implement ListTopicSubscriptions to register deposit and withdraw subscriber
- ///
- ///
- ///
- ///
- public override Task ListTopicSubscriptions(Empty request, ServerCallContext context)
- {
- var result = new ListTopicSubscriptionsResponse();
- result.Subscriptions.Add(new TopicSubscription
- {
- PubsubName = "pubsub",
- Topic = "deposit"
- });
- result.Subscriptions.Add(new TopicSubscription
- {
- PubsubName = "pubsub",
- Topic = "withdraw"
- });
- return Task.FromResult(result);
- }
-
- ///
- /// implement OnTopicEvent to handle deposit and withdraw event
- ///
- ///
- ///
- ///
- public override async Task OnTopicEvent(TopicEventRequest request, ServerCallContext context)
- {
- if (request.PubsubName == "pubsub")
- {
- var input = JsonSerializer.Deserialize(request.Data.ToStringUtf8(), this.jsonOptions);
- var transaction = new GrpcServiceSample.Generated.Transaction() { Id = input.Id, Amount = (int)input.Amount, };
- if (request.Topic == "deposit")
- {
- await Deposit(transaction, context);
- }
- else
- {
- await Withdraw(transaction, context);
- }
- }
-
- return new TopicEventResponse();
- }
-
- ///
- /// GetAccount
- ///
- ///
- ///
- ///
- public async Task GetAccount(GetAccountRequest input, ServerCallContext context)
- {
- var state = await _daprClient.GetStateEntryAsync(StoreName, input.Id);
- return new GrpcServiceSample.Generated.Account() { Id = state.Value.Id, Balance = (int)state.Value.Balance, };
- }
-
- ///
- /// Deposit
- ///
- ///
- ///
- ///
- public async Task Deposit(GrpcServiceSample.Generated.Transaction transaction, ServerCallContext context)
- {
- _logger.LogDebug("Enter deposit");
- var state = await _daprClient.GetStateEntryAsync(StoreName, transaction.Id);
- state.Value ??= new Models.Account() { Id = transaction.Id, };
- state.Value.Balance += transaction.Amount;
- await state.SaveAsync();
- return new GrpcServiceSample.Generated.Account() { Id = state.Value.Id, Balance = (int)state.Value.Balance, };
- }
-
- ///
- /// Withdraw
- ///
- ///
- ///
- ///
- public async Task Withdraw(GrpcServiceSample.Generated.Transaction transaction, ServerCallContext context)
- {
- _logger.LogDebug("Enter withdraw");
- var state = await _daprClient.GetStateEntryAsync(StoreName, transaction.Id);
-
- if (state.Value == null)
- {
- throw new Exception($"NotFound: {transaction.Id}");
- }
-
- state.Value.Balance -= transaction.Amount;
- await state.SaveAsync();
- return new GrpcServiceSample.Generated.Account() { Id = state.Value.Id, Balance = (int)state.Value.Balance, };
- }
+ _daprClient = daprClient;
+ _logger = logger;
}
-}
+
+ readonly JsonSerializerOptions jsonOptions = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
+
+ ///
+ /// implement OnIvoke to support getaccount, deposit and withdraw
+ ///
+ ///
+ ///
+ ///
+ public override async Task OnInvoke(InvokeRequest request, ServerCallContext context)
+ {
+ var response = new InvokeResponse();
+ switch (request.Method)
+ {
+ case "getaccount":
+ var input = request.Data.Unpack();
+ var output = await GetAccount(input, context);
+ response.Data = Any.Pack(output);
+ break;
+ case "deposit":
+ case "withdraw":
+ var transaction = request.Data.Unpack();
+ var account = request.Method == "deposit" ?
+ await Deposit(transaction, context) :
+ await Withdraw(transaction, context);
+ response.Data = Any.Pack(account);
+ break;
+ default:
+ break;
+ }
+ return response;
+ }
+
+ ///
+ /// implement ListTopicSubscriptions to register deposit and withdraw subscriber
+ ///
+ ///
+ ///
+ ///
+ public override Task ListTopicSubscriptions(Empty request, ServerCallContext context)
+ {
+ var result = new ListTopicSubscriptionsResponse();
+ result.Subscriptions.Add(new TopicSubscription
+ {
+ PubsubName = "pubsub",
+ Topic = "deposit"
+ });
+ result.Subscriptions.Add(new TopicSubscription
+ {
+ PubsubName = "pubsub",
+ Topic = "withdraw"
+ });
+ return Task.FromResult(result);
+ }
+
+ ///
+ /// implement OnTopicEvent to handle deposit and withdraw event
+ ///
+ ///
+ ///
+ ///
+ public override async Task OnTopicEvent(TopicEventRequest request, ServerCallContext context)
+ {
+ if (request.PubsubName == "pubsub")
+ {
+ var input = JsonSerializer.Deserialize(request.Data.ToStringUtf8(), this.jsonOptions);
+ var transaction = new GrpcServiceSample.Generated.Transaction() { Id = input.Id, Amount = (int)input.Amount, };
+ if (request.Topic == "deposit")
+ {
+ await Deposit(transaction, context);
+ }
+ else
+ {
+ await Withdraw(transaction, context);
+ }
+ }
+
+ return new TopicEventResponse();
+ }
+
+ ///
+ /// GetAccount
+ ///
+ ///
+ ///
+ ///
+ public async Task GetAccount(GetAccountRequest input, ServerCallContext context)
+ {
+ var state = await _daprClient.GetStateEntryAsync(StoreName, input.Id);
+ return new GrpcServiceSample.Generated.Account() { Id = state.Value.Id, Balance = (int)state.Value.Balance, };
+ }
+
+ ///
+ /// Deposit
+ ///
+ ///
+ ///
+ ///
+ public async Task Deposit(GrpcServiceSample.Generated.Transaction transaction, ServerCallContext context)
+ {
+ _logger.LogDebug("Enter deposit");
+ var state = await _daprClient.GetStateEntryAsync(StoreName, transaction.Id);
+ state.Value ??= new Models.Account() { Id = transaction.Id, };
+ state.Value.Balance += transaction.Amount;
+ await state.SaveAsync();
+ return new GrpcServiceSample.Generated.Account() { Id = state.Value.Id, Balance = (int)state.Value.Balance, };
+ }
+
+ ///
+ /// Withdraw
+ ///
+ ///
+ ///
+ ///
+ public async Task Withdraw(GrpcServiceSample.Generated.Transaction transaction, ServerCallContext context)
+ {
+ _logger.LogDebug("Enter withdraw");
+ var state = await _daprClient.GetStateEntryAsync(StoreName, transaction.Id);
+
+ if (state.Value == null)
+ {
+ throw new Exception($"NotFound: {transaction.Id}");
+ }
+
+ state.Value.Balance -= transaction.Amount;
+ await state.SaveAsync();
+ return new GrpcServiceSample.Generated.Account() { Id = state.Value.Id, Balance = (int)state.Value.Balance, };
+ }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/GrpcServiceSample/Startup.cs b/examples/AspNetCore/GrpcServiceSample/Startup.cs
index 4aa5ac7d..f2c60649 100644
--- a/examples/AspNetCore/GrpcServiceSample/Startup.cs
+++ b/examples/AspNetCore/GrpcServiceSample/Startup.cs
@@ -19,47 +19,46 @@ using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-namespace GrpcServiceSample
+namespace GrpcServiceSample;
+
+///
+/// Startup class.
+///
+public class Startup
{
///
- /// Startup class.
+ /// Configure Services
///
- public class Startup
+ ///
+ public void ConfigureServices(IServiceCollection services)
{
- ///
- /// Configure Services
- ///
- ///
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddGrpc();
+ services.AddGrpc();
- services.AddDaprClient();
- }
-
- ///
- /// Configure app
- ///
- ///
- ///
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapGrpcService();
-
- endpoints.MapGet("/", async context =>
- {
- await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
- });
- });
- }
+ services.AddDaprClient();
}
-}
+
+ ///
+ /// Configure app
+ ///
+ ///
+ ///
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseRouting();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapGrpcService();
+
+ endpoints.MapGet("/", async context =>
+ {
+ await context.Response.WriteAsync("Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
+ });
+ });
+ }
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/RoutingSample/Account.cs b/examples/AspNetCore/RoutingSample/Account.cs
index ede662b1..5aac78ce 100644
--- a/examples/AspNetCore/RoutingSample/Account.cs
+++ b/examples/AspNetCore/RoutingSample/Account.cs
@@ -11,21 +11,20 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace RoutingSample
+namespace RoutingSample;
+
+///
+/// Class representing an Account for samples.
+///
+public class Account
{
///
- /// Class representing an Account for samples.
+ /// Gets or sets account id.
///
- public class Account
- {
- ///
- /// Gets or sets account id.
- ///
- public string Id { get; set; }
+ public string Id { get; set; }
- ///
- /// Gets or sets account balance.
- ///
- public decimal Balance { get; set; }
- }
+ ///
+ /// Gets or sets account balance.
+ ///
+ public decimal Balance { get; set; }
}
\ No newline at end of file
diff --git a/examples/AspNetCore/RoutingSample/Program.cs b/examples/AspNetCore/RoutingSample/Program.cs
index 505f58d1..6aa86d12 100644
--- a/examples/AspNetCore/RoutingSample/Program.cs
+++ b/examples/AspNetCore/RoutingSample/Program.cs
@@ -11,35 +11,34 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace RoutingSample
+namespace RoutingSample;
+
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+
+///
+/// Controller Sample.
+///
+public static class Program
{
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
+ ///
+ /// Main for Controller Sample.
+ ///
+ /// Arguments.
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
///
- /// Controller Sample.
+ /// Creates WebHost Builder.
///
- public static class Program
- {
- ///
- /// Main for Controller Sample.
- ///
- /// Arguments.
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
-
- ///
- /// Creates WebHost Builder.
- ///
- /// Arguments.
- /// Returns IHostbuilder.
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
- }
-}
+ /// Arguments.
+ /// Returns IHostbuilder.
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/RoutingSample/README.md b/examples/AspNetCore/RoutingSample/README.md
index 901c51c4..8f486c45 100644
--- a/examples/AspNetCore/RoutingSample/README.md
+++ b/examples/AspNetCore/RoutingSample/README.md
@@ -12,7 +12,7 @@ The application also registers for pub/sub with the `deposit`, `multideposit`, a
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/AspNetCore/RoutingSample/RoutingSample.csproj b/examples/AspNetCore/RoutingSample/RoutingSample.csproj
index 6dbe750a..061510f9 100644
--- a/examples/AspNetCore/RoutingSample/RoutingSample.csproj
+++ b/examples/AspNetCore/RoutingSample/RoutingSample.csproj
@@ -1,9 +1,5 @@
-
- net6
-
-
diff --git a/examples/AspNetCore/RoutingSample/Startup.cs b/examples/AspNetCore/RoutingSample/Startup.cs
index 3d71e9e1..3e7d7b0c 100644
--- a/examples/AspNetCore/RoutingSample/Startup.cs
+++ b/examples/AspNetCore/RoutingSample/Startup.cs
@@ -11,254 +11,253 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace RoutingSample
+namespace RoutingSample;
+
+using System;
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Threading.Tasks;
+using Dapr;
+using Dapr.AspNetCore;
+using Dapr.Client;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+///
+/// Startup class.
+///
+public class Startup
{
- using System;
- using System.Collections.Generic;
- using System.Text.Json;
- using System.Threading.Tasks;
- using Dapr;
- using Dapr.AspNetCore;
- using Dapr.Client;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.Logging;
+ ///
+ /// State store name.
+ ///
+ public const string StoreName = "statestore";
///
- /// Startup class.
+ /// Pubsub component name. "pubsub" is name of the default pub/sub configured by the Dapr CLI.
///
- public class Startup
+ public const string PubsubName = "pubsub";
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Configuration.
+ public Startup(IConfiguration configuration)
{
- ///
- /// State store name.
- ///
- public const string StoreName = "statestore";
+ this.Configuration = configuration;
+ }
- ///
- /// Pubsub component name. "pubsub" is name of the default pub/sub configured by the Dapr CLI.
- ///
- public const string PubsubName = "pubsub";
+ ///
+ /// Gets the configuration.
+ ///
+ public IConfiguration Configuration { get; }
- ///
- /// Initializes a new instance of the class.
- ///
- /// Configuration.
- public Startup(IConfiguration configuration)
+ ///
+ /// Configures Services.
+ ///
+ /// Service Collection.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddDaprClient();
+
+ services.AddSingleton(new JsonSerializerOptions()
{
- this.Configuration = configuration;
+ PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
+ PropertyNameCaseInsensitive = true,
+ });
+ }
+
+ ///
+ /// Configures Application Builder and WebHost environment.
+ ///
+ /// Application builder.
+ /// Webhost environment.
+ /// Options for JSON serialization.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, JsonSerializerOptions serializerOptions,
+ ILogger logger)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
}
- ///
- /// Gets the configuration.
- ///
- public IConfiguration Configuration { get; }
+ app.UseRouting();
- ///
- /// Configures Services.
- ///
- /// Service Collection.
- public void ConfigureServices(IServiceCollection services)
+ app.UseCloudEvents();
+
+ app.UseEndpoints(endpoints =>
{
- services.AddDaprClient();
+ endpoints.MapSubscribeHandler();
- services.AddSingleton(new JsonSerializerOptions()
+ var depositTopicOptions = new TopicOptions();
+ depositTopicOptions.PubsubName = PubsubName;
+ depositTopicOptions.Name = "deposit";
+ depositTopicOptions.DeadLetterTopic = "amountDeadLetterTopic";
+
+ var withdrawTopicOptions = new TopicOptions();
+ withdrawTopicOptions.PubsubName = PubsubName;
+ withdrawTopicOptions.Name = "withdraw";
+ withdrawTopicOptions.DeadLetterTopic = "amountDeadLetterTopic";
+
+ var multiDepositTopicOptions = new TopicOptions { PubsubName = PubsubName, Name = "multideposit" };
+
+ var bulkSubscribeTopicOptions = new BulkSubscribeTopicOptions
{
- PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
- PropertyNameCaseInsensitive = true,
- });
- }
+ TopicName = "multideposit", MaxMessagesCount = 250, MaxAwaitDurationMs = 1000
+ };
- ///
- /// Configures Application Builder and WebHost environment.
- ///
- /// Application builder.
- /// Webhost environment.
- /// Options for JSON serialization.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env, JsonSerializerOptions serializerOptions,
- ILogger logger)
+ endpoints.MapGet("{id}", Balance);
+ endpoints.MapPost("deposit", Deposit).WithTopic(depositTopicOptions);
+ endpoints.MapPost("multideposit", MultiDeposit).WithTopic(multiDepositTopicOptions).WithBulkSubscribe(bulkSubscribeTopicOptions);
+ endpoints.MapPost("deadLetterTopicRoute", ViewErrorMessage).WithTopic(PubsubName, "amountDeadLetterTopic");
+ endpoints.MapPost("withdraw", Withdraw).WithTopic(withdrawTopicOptions);
+ });
+
+ async Task Balance(HttpContext context)
{
- if (env.IsDevelopment())
+ logger.LogInformation("Enter Balance");
+ var client = context.RequestServices.GetRequiredService();
+
+ var id = (string)context.Request.RouteValues["id"];
+ logger.LogInformation("id is {0}", id);
+ var account = await client.GetStateAsync(StoreName, id);
+ if (account == null)
{
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseCloudEvents();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapSubscribeHandler();
-
- var depositTopicOptions = new TopicOptions();
- depositTopicOptions.PubsubName = PubsubName;
- depositTopicOptions.Name = "deposit";
- depositTopicOptions.DeadLetterTopic = "amountDeadLetterTopic";
-
- var withdrawTopicOptions = new TopicOptions();
- withdrawTopicOptions.PubsubName = PubsubName;
- withdrawTopicOptions.Name = "withdraw";
- withdrawTopicOptions.DeadLetterTopic = "amountDeadLetterTopic";
-
- var multiDepositTopicOptions = new TopicOptions { PubsubName = PubsubName, Name = "multideposit" };
-
- var bulkSubscribeTopicOptions = new BulkSubscribeTopicOptions
- {
- TopicName = "multideposit", MaxMessagesCount = 250, MaxAwaitDurationMs = 1000
- };
-
- endpoints.MapGet("{id}", Balance);
- endpoints.MapPost("deposit", Deposit).WithTopic(depositTopicOptions);
- endpoints.MapPost("multideposit", MultiDeposit).WithTopic(multiDepositTopicOptions).WithBulkSubscribe(bulkSubscribeTopicOptions);
- endpoints.MapPost("deadLetterTopicRoute", ViewErrorMessage).WithTopic(PubsubName, "amountDeadLetterTopic");
- endpoints.MapPost("withdraw", Withdraw).WithTopic(withdrawTopicOptions);
- });
-
- async Task Balance(HttpContext context)
- {
- logger.LogInformation("Enter Balance");
- var client = context.RequestServices.GetRequiredService();
-
- var id = (string)context.Request.RouteValues["id"];
- logger.LogInformation("id is {0}", id);
- var account = await client.GetStateAsync(StoreName, id);
- if (account == null)
- {
- logger.LogInformation("Account not found");
- context.Response.StatusCode = 404;
- return;
- }
-
- logger.LogInformation("Account balance is {0}", account.Balance);
-
- context.Response.ContentType = "application/json";
- await JsonSerializer.SerializeAsync(context.Response.Body, account, serializerOptions);
- }
-
- async Task Deposit(HttpContext context)
- {
- logger.LogInformation("Enter Deposit");
-
- var client = context.RequestServices.GetRequiredService();
- var transaction = await JsonSerializer.DeserializeAsync(context.Request.Body, serializerOptions);
-
- logger.LogInformation("Id is {0}, Amount is {1}", transaction.Id, transaction.Amount);
-
- var account = await client.GetStateAsync(StoreName, transaction.Id);
- if (account == null)
- {
- account = new Account() { Id = transaction.Id, };
- }
-
- if (transaction.Amount < 0m)
- {
- logger.LogInformation("Invalid amount");
- context.Response.StatusCode = 400;
- return;
- }
-
- account.Balance += transaction.Amount;
- await client.SaveStateAsync(StoreName, transaction.Id, account);
- logger.LogInformation("Balance is {0}", account.Balance);
-
- context.Response.ContentType = "application/json";
- await JsonSerializer.SerializeAsync(context.Response.Body, account, serializerOptions);
- }
-
- async Task MultiDeposit(HttpContext context)
- {
- logger.LogInformation("Enter bulk deposit");
-
- var client = context.RequestServices.GetRequiredService();
-
- var bulkMessage = await JsonSerializer.DeserializeAsync>>(
- context.Request.Body, serializerOptions);
-
- List entries = new List();
-
- if (bulkMessage != null)
- {
- foreach (var entry in bulkMessage.Entries)
- {
- try
- {
- var transaction = entry.Event.Data;
-
- var state = await client.GetStateEntryAsync(StoreName, transaction.Id);
- state.Value ??= new Account() { Id = transaction.Id, };
- logger.LogInformation("Id is {0}, the amount to be deposited is {1}",
- transaction.Id, transaction.Amount);
-
- if (transaction.Amount < 0m)
- {
- logger.LogInformation("Invalid amount");
- context.Response.StatusCode = 400;
- return;
- }
-
- state.Value.Balance += transaction.Amount;
- logger.LogInformation("Balance is {0}", state.Value.Balance);
- await state.SaveAsync();
- entries.Add(new BulkSubscribeAppResponseEntry(entry.EntryId,
- BulkSubscribeAppResponseStatus.SUCCESS));
- }
- catch (Exception e)
- {
- logger.LogError(e.Message);
- entries.Add(new BulkSubscribeAppResponseEntry(entry.EntryId,
- BulkSubscribeAppResponseStatus.RETRY));
- }
- }
- }
-
- await JsonSerializer.SerializeAsync(context.Response.Body,
- new BulkSubscribeAppResponse(entries), serializerOptions);
- }
-
- async Task ViewErrorMessage(HttpContext context)
- {
- var transaction = await JsonSerializer.DeserializeAsync(context.Request.Body, serializerOptions);
-
- logger.LogInformation("The amount cannot be negative: {0}", transaction.Amount);
-
+ logger.LogInformation("Account not found");
+ context.Response.StatusCode = 404;
return;
}
- async Task Withdraw(HttpContext context)
+ logger.LogInformation("Account balance is {0}", account.Balance);
+
+ context.Response.ContentType = "application/json";
+ await JsonSerializer.SerializeAsync(context.Response.Body, account, serializerOptions);
+ }
+
+ async Task Deposit(HttpContext context)
+ {
+ logger.LogInformation("Enter Deposit");
+
+ var client = context.RequestServices.GetRequiredService();
+ var transaction = await JsonSerializer.DeserializeAsync(context.Request.Body, serializerOptions);
+
+ logger.LogInformation("Id is {0}, Amount is {1}", transaction.Id, transaction.Amount);
+
+ var account = await client.GetStateAsync(StoreName, transaction.Id);
+ if (account == null)
{
- logger.LogInformation("Enter Withdraw");
-
- var client = context.RequestServices.GetRequiredService();
- var transaction = await JsonSerializer.DeserializeAsync(context.Request.Body, serializerOptions);
-
- logger.LogInformation("Id is {0}, Amount is {1}", transaction.Id, transaction.Amount);
-
- var account = await client.GetStateAsync(StoreName, transaction.Id);
- if (account == null)
- {
- logger.LogInformation("Account not found");
- context.Response.StatusCode = 404;
- return;
- }
-
- if (transaction.Amount < 0m)
- {
- logger.LogInformation("Invalid amount");
- context.Response.StatusCode = 400;
- return;
- }
-
- account.Balance -= transaction.Amount;
- await client.SaveStateAsync(StoreName, transaction.Id, account);
- logger.LogInformation("Balance is {0}", account.Balance);
-
- context.Response.ContentType = "application/json";
- await JsonSerializer.SerializeAsync(context.Response.Body, account, serializerOptions);
+ account = new Account() { Id = transaction.Id, };
}
+
+ if (transaction.Amount < 0m)
+ {
+ logger.LogInformation("Invalid amount");
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ account.Balance += transaction.Amount;
+ await client.SaveStateAsync(StoreName, transaction.Id, account);
+ logger.LogInformation("Balance is {0}", account.Balance);
+
+ context.Response.ContentType = "application/json";
+ await JsonSerializer.SerializeAsync(context.Response.Body, account, serializerOptions);
+ }
+
+ async Task MultiDeposit(HttpContext context)
+ {
+ logger.LogInformation("Enter bulk deposit");
+
+ var client = context.RequestServices.GetRequiredService();
+
+ var bulkMessage = await JsonSerializer.DeserializeAsync>>(
+ context.Request.Body, serializerOptions);
+
+ List entries = new List();
+
+ if (bulkMessage != null)
+ {
+ foreach (var entry in bulkMessage.Entries)
+ {
+ try
+ {
+ var transaction = entry.Event.Data;
+
+ var state = await client.GetStateEntryAsync(StoreName, transaction.Id);
+ state.Value ??= new Account() { Id = transaction.Id, };
+ logger.LogInformation("Id is {0}, the amount to be deposited is {1}",
+ transaction.Id, transaction.Amount);
+
+ if (transaction.Amount < 0m)
+ {
+ logger.LogInformation("Invalid amount");
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ state.Value.Balance += transaction.Amount;
+ logger.LogInformation("Balance is {0}", state.Value.Balance);
+ await state.SaveAsync();
+ entries.Add(new BulkSubscribeAppResponseEntry(entry.EntryId,
+ BulkSubscribeAppResponseStatus.SUCCESS));
+ }
+ catch (Exception e)
+ {
+ logger.LogError(e.Message);
+ entries.Add(new BulkSubscribeAppResponseEntry(entry.EntryId,
+ BulkSubscribeAppResponseStatus.RETRY));
+ }
+ }
+ }
+
+ await JsonSerializer.SerializeAsync(context.Response.Body,
+ new BulkSubscribeAppResponse(entries), serializerOptions);
+ }
+
+ async Task ViewErrorMessage(HttpContext context)
+ {
+ var transaction = await JsonSerializer.DeserializeAsync(context.Request.Body, serializerOptions);
+
+ logger.LogInformation("The amount cannot be negative: {0}", transaction.Amount);
+
+ return;
+ }
+
+ async Task Withdraw(HttpContext context)
+ {
+ logger.LogInformation("Enter Withdraw");
+
+ var client = context.RequestServices.GetRequiredService();
+ var transaction = await JsonSerializer.DeserializeAsync(context.Request.Body, serializerOptions);
+
+ logger.LogInformation("Id is {0}, Amount is {1}", transaction.Id, transaction.Amount);
+
+ var account = await client.GetStateAsync(StoreName, transaction.Id);
+ if (account == null)
+ {
+ logger.LogInformation("Account not found");
+ context.Response.StatusCode = 404;
+ return;
+ }
+
+ if (transaction.Amount < 0m)
+ {
+ logger.LogInformation("Invalid amount");
+ context.Response.StatusCode = 400;
+ return;
+ }
+
+ account.Balance -= transaction.Amount;
+ await client.SaveStateAsync(StoreName, transaction.Id, account);
+ logger.LogInformation("Balance is {0}", account.Balance);
+
+ context.Response.ContentType = "application/json";
+ await JsonSerializer.SerializeAsync(context.Response.Body, account, serializerOptions);
}
}
-}
+}
\ No newline at end of file
diff --git a/examples/AspNetCore/RoutingSample/Transaction.cs b/examples/AspNetCore/RoutingSample/Transaction.cs
index f37340f4..b6042e43 100644
--- a/examples/AspNetCore/RoutingSample/Transaction.cs
+++ b/examples/AspNetCore/RoutingSample/Transaction.cs
@@ -11,21 +11,20 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace RoutingSample
+namespace RoutingSample;
+
+///
+/// Represents a transaction used by sample code.
+///
+public class Transaction
{
///
- /// Represents a transaction used by sample code.
+ /// Gets or sets account id for the transaction.
///
- public class Transaction
- {
- ///
- /// Gets or sets account id for the transaction.
- ///
- public string Id { get; set; }
+ public string Id { get; set; }
- ///
- /// Gets or sets amount for the transaction.
- ///
- public decimal Amount { get; set; }
- }
+ ///
+ /// Gets or sets amount for the transaction.
+ ///
+ public decimal Amount { get; set; }
}
\ No newline at end of file
diff --git a/examples/AspNetCore/SecretStoreConfigurationProviderSample/Program.cs b/examples/AspNetCore/SecretStoreConfigurationProviderSample/Program.cs
index 658d6d16..fd4b31c8 100644
--- a/examples/AspNetCore/SecretStoreConfigurationProviderSample/Program.cs
+++ b/examples/AspNetCore/SecretStoreConfigurationProviderSample/Program.cs
@@ -11,64 +11,63 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace SecretStoreConfigurationProviderSample
+namespace SecretStoreConfigurationProviderSample;
+
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Hosting;
+using Dapr.Client;
+using Dapr.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+
+///
+/// Secret Store Configuration Provider Sample.
+///
+public class Program
{
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.Extensions.Hosting;
- using Dapr.Client;
- using Dapr.Extensions.Configuration;
- using Microsoft.Extensions.DependencyInjection;
- using System;
+ ///
+ /// Main for Secret Store Configuration Provider Sample.
+ ///
+ /// Arguments.
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
+ }
///
- /// Secret Store Configuration Provider Sample.
+ /// Creates WebHost Builder.
///
- public class Program
+ /// Arguments.
+ /// Returns IHostbuilder.
+ public static IHostBuilder CreateHostBuilder(string[] args)
{
- ///
- /// Main for Secret Store Configuration Provider Sample.
- ///
- /// Arguments.
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
+ // Create Dapr Client
+ var client = new DaprClientBuilder()
+ .Build();
- ///
- /// Creates WebHost Builder.
- ///
- /// Arguments.
- /// Returns IHostbuilder.
- public static IHostBuilder CreateHostBuilder(string[] args)
- {
- // Create Dapr Client
- var client = new DaprClientBuilder()
- .Build();
+ return Host.CreateDefaultBuilder(args)
+ .ConfigureServices((services) =>
+ {
+ // Add the DaprClient to DI.
+ services.AddSingleton(client);
+ })
+ .ConfigureAppConfiguration((configBuilder) =>
+ {
+ // To retrive specific secrets use secretDescriptors
+ // Create descriptors for the secrets you want to rerieve from the Dapr Secret Store.
+ // var secretDescriptors = new DaprSecretDescriptor[]
+ // {
+ // new DaprSecretDescriptor("super-secret")
+ // };
+ // configBuilder.AddDaprSecretStore("demosecrets", secretDescriptors, client);
- return Host.CreateDefaultBuilder(args)
- .ConfigureServices((services) =>
- {
- // Add the DaprClient to DI.
- services.AddSingleton(client);
- })
- .ConfigureAppConfiguration((configBuilder) =>
- {
- // To retrive specific secrets use secretDescriptors
- // Create descriptors for the secrets you want to rerieve from the Dapr Secret Store.
- // var secretDescriptors = new DaprSecretDescriptor[]
- // {
- // new DaprSecretDescriptor("super-secret")
- // };
- // configBuilder.AddDaprSecretStore("demosecrets", secretDescriptors, client);
-
- // Add the secret store Configuration Provider to the configuration builder.
- // Including a TimeSpan allows us to dictate how long we should wait for the Sidecar to start.
- configBuilder.AddDaprSecretStore("demosecrets", client, TimeSpan.FromSeconds(10));
- })
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
- }
+ // Add the secret store Configuration Provider to the configuration builder.
+ // Including a TimeSpan allows us to dictate how long we should wait for the Sidecar to start.
+ configBuilder.AddDaprSecretStore("demosecrets", client, TimeSpan.FromSeconds(10));
+ })
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
}
}
\ No newline at end of file
diff --git a/examples/AspNetCore/SecretStoreConfigurationProviderSample/README.md b/examples/AspNetCore/SecretStoreConfigurationProviderSample/README.md
index a5d60c2f..2eb9b73f 100644
--- a/examples/AspNetCore/SecretStoreConfigurationProviderSample/README.md
+++ b/examples/AspNetCore/SecretStoreConfigurationProviderSample/README.md
@@ -2,7 +2,7 @@
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/AspNetCore/SecretStoreConfigurationProviderSample/SecretStoreConfigurationProviderSample.csproj b/examples/AspNetCore/SecretStoreConfigurationProviderSample/SecretStoreConfigurationProviderSample.csproj
index 01fbc207..ce47841b 100644
--- a/examples/AspNetCore/SecretStoreConfigurationProviderSample/SecretStoreConfigurationProviderSample.csproj
+++ b/examples/AspNetCore/SecretStoreConfigurationProviderSample/SecretStoreConfigurationProviderSample.csproj
@@ -2,7 +2,6 @@
Exe
- net6
diff --git a/examples/AspNetCore/SecretStoreConfigurationProviderSample/Startup.cs b/examples/AspNetCore/SecretStoreConfigurationProviderSample/Startup.cs
index 6d2268d6..c89dcff8 100644
--- a/examples/AspNetCore/SecretStoreConfigurationProviderSample/Startup.cs
+++ b/examples/AspNetCore/SecretStoreConfigurationProviderSample/Startup.cs
@@ -11,72 +11,71 @@
// limitations under the License.
// ------------------------------------------------------------------------
-namespace SecretStoreConfigurationProviderSample
+namespace SecretStoreConfigurationProviderSample;
+
+using System.Text.Json;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.DependencyInjection;
+
+///
+/// Startup class.
+///
+public class Startup
{
- using System.Text.Json;
- using System.Threading.Tasks;
- using Microsoft.AspNetCore.Builder;
- using Microsoft.AspNetCore.Hosting;
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.Configuration;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.DependencyInjection;
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Configuration.
+ public Startup(IConfiguration configuration)
+ {
+ this.Configuration = configuration;
+ }
///
- /// Startup class.
+ /// Gets the configuration.
///
- public class Startup
+ public IConfiguration Configuration { get; }
+
+ ///
+ /// Configures Services.
+ ///
+ /// Service Collection.
+ public void ConfigureServices(IServiceCollection services)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// Configuration.
- public Startup(IConfiguration configuration)
+
+ }
+
+ ///
+ /// Configures Application Builder and WebHost environment.
+ ///
+ /// Application builder.
+ /// Webhost environment.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
{
- this.Configuration = configuration;
+ app.UseDeveloperExceptionPage();
}
- ///
- /// Gets the configuration.
- ///
- public IConfiguration Configuration { get; }
+ app.UseRouting();
- ///
- /// Configures Services.
- ///
- /// Service Collection.
- public void ConfigureServices(IServiceCollection services)
+ app.UseEndpoints(endpoints =>
{
+ endpoints.MapGet("secret", Secret);
+ });
- }
-
- ///
- /// Configures Application Builder and WebHost environment.
- ///
- /// Application builder.
- /// Webhost environment.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ async Task Secret(HttpContext context)
{
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
+ // Get secret from configuration!!!
+ var secretValue = Configuration["super-secret"];
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapGet("secret", Secret);
- });
-
- async Task Secret(HttpContext context)
- {
- // Get secret from configuration!!!
- var secretValue = Configuration["super-secret"];
-
- context.Response.ContentType = "application/json";
- await JsonSerializer.SerializeAsync(context.Response.Body, secretValue);
- }
+ context.Response.ContentType = "application/json";
+ await JsonSerializer.SerializeAsync(context.Response.Body, secretValue);
}
}
}
\ No newline at end of file
diff --git a/examples/Client/ConfigurationApi/ConfigurationApi.csproj b/examples/Client/ConfigurationApi/ConfigurationApi.csproj
index 761ebb38..d74bcdd5 100644
--- a/examples/Client/ConfigurationApi/ConfigurationApi.csproj
+++ b/examples/Client/ConfigurationApi/ConfigurationApi.csproj
@@ -1,10 +1,4 @@
-
-
- net6
-
-
-
diff --git a/examples/Client/ConfigurationApi/Controllers/ConfigurationController.cs b/examples/Client/ConfigurationApi/Controllers/ConfigurationController.cs
index 9ceb60c0..faad2407 100644
--- a/examples/Client/ConfigurationApi/Controllers/ConfigurationController.cs
+++ b/examples/Client/ConfigurationApi/Controllers/ConfigurationController.cs
@@ -7,81 +7,80 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
-namespace ConfigurationApi.Controllers
+namespace ConfigurationApi.Controllers;
+
+[ApiController]
+[Route("configuration")]
+public class ConfigurationController : ControllerBase
{
- [ApiController]
- [Route("configuration")]
- public class ConfigurationController : ControllerBase
+ private ILogger logger;
+ private IConfiguration configuration;
+ private DaprClient client;
+
+ public ConfigurationController(ILogger logger, IConfiguration configuration, [FromServices] DaprClient client)
{
- private ILogger logger;
- private IConfiguration configuration;
- private DaprClient client;
+ this.logger = logger;
+ this.configuration = configuration;
+ this.client = client;
+ }
- public ConfigurationController(ILogger logger, IConfiguration configuration, [FromServices] DaprClient client)
+ [HttpGet("get/{configStore}/{queryKey}")]
+ public async Task GetConfiguration([FromRoute] string configStore, [FromRoute] string queryKey)
+ {
+ logger.LogInformation($"Querying Configuration with key: {queryKey}");
+ var configItems = await client.GetConfiguration(configStore, new List() { queryKey });
+
+ if (configItems.Items.Count == 0)
{
- this.logger = logger;
- this.configuration = configuration;
- this.client = client;
+ logger.LogInformation($"No configuration item found for key: {queryKey}");
}
- [HttpGet("get/{configStore}/{queryKey}")]
- public async Task GetConfiguration([FromRoute] string configStore, [FromRoute] string queryKey)
+ foreach (var item in configItems.Items)
{
- logger.LogInformation($"Querying Configuration with key: {queryKey}");
- var configItems = await client.GetConfiguration(configStore, new List() { queryKey });
-
- if (configItems.Items.Count == 0)
- {
- logger.LogInformation($"No configuration item found for key: {queryKey}");
- }
-
- foreach (var item in configItems.Items)
- {
- logger.LogInformation($"Got configuration item:\nKey: {item.Key}\nValue: {item.Value.Value}\nVersion: {item.Value.Version}");
- }
+ logger.LogInformation($"Got configuration item:\nKey: {item.Key}\nValue: {item.Value.Value}\nVersion: {item.Value.Version}");
}
+ }
- [HttpGet("extension")]
- public Task SubscribeAndWatchConfiguration()
- {
- logger.LogInformation($"Getting values from Configuration Extension, watched values ['withdrawVersion', 'source'].");
+ [HttpGet("extension")]
+ public Task SubscribeAndWatchConfiguration()
+ {
+ logger.LogInformation($"Getting values from Configuration Extension, watched values ['withdrawVersion', 'source'].");
- logger.LogInformation($"'withdrawVersion' from extension: {configuration["withdrawVersion"]}");
- logger.LogInformation($"'source' from extension: {configuration["source"]}");
+ logger.LogInformation($"'withdrawVersion' from extension: {configuration["withdrawVersion"]}");
+ logger.LogInformation($"'source' from extension: {configuration["source"]}");
- return Task.CompletedTask;
- }
+ return Task.CompletedTask;
+ }
#nullable enable
- [HttpPost("withdraw")]
- public async Task> CreateAccountHandler(Transaction transaction)
+ [HttpPost("withdraw")]
+ public async Task> CreateAccountHandler(Transaction transaction)
+ {
+ // Check if the V2 method is enabled.
+ if (configuration["withdrawVersion"] == "v2")
{
- // Check if the V2 method is enabled.
- if (configuration["withdrawVersion"] == "v2")
+ var source = !string.IsNullOrEmpty(configuration["source"]) ? configuration["source"] : "local";
+ var transactionV2 = new TransactionV2
{
- var source = !string.IsNullOrEmpty(configuration["source"]) ? configuration["source"] : "local";
- var transactionV2 = new TransactionV2
- {
- Id = transaction.Id,
- Amount = transaction.Amount,
- Channel = source
- };
- logger.LogInformation($"Calling V2 Withdraw API - Id: {transactionV2.Id} Amount: {transactionV2.Amount} Channel: {transactionV2.Channel}");
- try
- {
- return await this.client.InvokeMethodAsync("controller", "withdraw.v2", transactionV2);
- }
- catch (DaprException ex)
- {
- logger.LogError($"Error executing withdrawal: {ex.Message}");
- return BadRequest();
- }
+ Id = transaction.Id,
+ Amount = transaction.Amount,
+ Channel = source
+ };
+ logger.LogInformation($"Calling V2 Withdraw API - Id: {transactionV2.Id} Amount: {transactionV2.Amount} Channel: {transactionV2.Channel}");
+ try
+ {
+ return await this.client.InvokeMethodAsync("controller", "withdraw.v2", transactionV2);
+ }
+ catch (DaprException ex)
+ {
+ logger.LogError($"Error executing withdrawal: {ex.Message}");
+ return BadRequest();
}
-
- // Default to the original method.
- logger.LogInformation($"Calling V1 Withdraw API: {transaction}");
- return await this.client.InvokeMethodAsync("controller", "withdraw", transaction);
}
-#nullable disable
+
+ // Default to the original method.
+ logger.LogInformation($"Calling V1 Withdraw API: {transaction}");
+ return await this.client.InvokeMethodAsync("controller", "withdraw", transaction);
}
-}
+#nullable disable
+}
\ No newline at end of file
diff --git a/examples/Client/ConfigurationApi/Program.cs b/examples/Client/ConfigurationApi/Program.cs
index 22f12cfa..832b0624 100644
--- a/examples/Client/ConfigurationApi/Program.cs
+++ b/examples/Client/ConfigurationApi/Program.cs
@@ -5,37 +5,36 @@ using Dapr.Client;
using Dapr.Extensions.Configuration;
using System.Collections.Generic;
-namespace ConfigurationApi
-{
- public class Program
- {
- public static void Main(string[] args)
- {
- Console.WriteLine("Starting application.");
- CreateHostBuilder(args).Build().Run();
- Console.WriteLine("Closing application.");
- }
+namespace ConfigurationApi;
- ///
- /// Creates WebHost Builder.
- ///
- /// Arguments.
- /// Returns IHostbuilder.
- public static IHostBuilder CreateHostBuilder(string[] args)
- {
- var client = new DaprClientBuilder().Build();
- return Host.CreateDefaultBuilder(args)
- .ConfigureAppConfiguration(config =>
- {
- // Get the initial value and continue to watch it for changes.
- config.AddDaprConfigurationStore("redisconfig", new List() { "withdrawVersion" }, client, TimeSpan.FromSeconds(20));
- config.AddStreamingDaprConfigurationStore("redisconfig", new List() { "withdrawVersion", "source" }, client, TimeSpan.FromSeconds(20));
-
- })
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
- }
+public class Program
+{
+ public static void Main(string[] args)
+ {
+ Console.WriteLine("Starting application.");
+ CreateHostBuilder(args).Build().Run();
+ Console.WriteLine("Closing application.");
}
-}
+
+ ///
+ /// Creates WebHost Builder.
+ ///
+ /// Arguments.
+ /// Returns IHostbuilder.
+ public static IHostBuilder CreateHostBuilder(string[] args)
+ {
+ var client = new DaprClientBuilder().Build();
+ return Host.CreateDefaultBuilder(args)
+ .ConfigureAppConfiguration(config =>
+ {
+ // Get the initial value and continue to watch it for changes.
+ config.AddDaprConfigurationStore("redisconfig", new List() { "withdrawVersion" }, client, TimeSpan.FromSeconds(20));
+ config.AddStreamingDaprConfigurationStore("redisconfig", new List() { "withdrawVersion", "source" }, client, TimeSpan.FromSeconds(20));
+
+ })
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup();
+ });
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/ConfigurationApi/README.md b/examples/Client/ConfigurationApi/README.md
index d73a29f9..bfc24dee 100644
--- a/examples/Client/ConfigurationApi/README.md
+++ b/examples/Client/ConfigurationApi/README.md
@@ -9,7 +9,7 @@ It demonstrates the following APIs:
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/Client/ConfigurationApi/Startup.cs b/examples/Client/ConfigurationApi/Startup.cs
index b858b810..6ab1f8cf 100644
--- a/examples/Client/ConfigurationApi/Startup.cs
+++ b/examples/Client/ConfigurationApi/Startup.cs
@@ -4,51 +4,50 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-namespace ConfigurationApi
+namespace ConfigurationApi;
+
+public class Startup
{
- public class Startup
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Configuration.
+ public Startup(IConfiguration configuration)
{
- ///
- /// Initializes a new instance of the class.
- ///
- /// Configuration.
- public Startup(IConfiguration configuration)
- {
- this.Configuration = configuration;
- }
-
- ///
- /// Gets the configuration.
- ///
- public IConfiguration Configuration { get; }
-
- ///
- /// Configures Services.
- ///
- /// Service Collection.
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddControllers().AddDapr();
- }
-
- ///
- /// Configures Application Builder and WebHost environment.
- ///
- /// Application builder.
- /// Webhost environment.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- });
- }
+ this.Configuration = configuration;
}
-}
+
+ ///
+ /// Gets the configuration.
+ ///
+ public IConfiguration Configuration { get; }
+
+ ///
+ /// Configures Services.
+ ///
+ /// Service Collection.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddControllers().AddDapr();
+ }
+
+ ///
+ /// Configures Application Builder and WebHost environment.
+ ///
+ /// Application builder.
+ /// Webhost environment.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseRouting();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/Cryptography/Examples/EncryptDecryptStringExample.cs b/examples/Client/Cryptography/Examples/EncryptDecryptStringExample.cs
deleted file mode 100644
index d29b24a6..00000000
--- a/examples/Client/Cryptography/Examples/EncryptDecryptStringExample.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-// ------------------------------------------------------------------------
-// Copyright 2023 The Dapr Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ------------------------------------------------------------------------
-
-using System.Text;
-using Dapr.Client;
-#pragma warning disable CS0618 // Type or member is obsolete
-
-namespace Cryptography.Examples
-{
- internal class EncryptDecryptStringExample(string componentName, string keyName) : Example
- {
- public override string DisplayName => "Using Cryptography to encrypt and decrypt a string";
-
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
-
- const string plaintextStr = "This is the value we're going to encrypt today";
- Console.WriteLine($"Original string value: '{plaintextStr}'");
-
- //Encrypt the string
- var plaintextBytes = Encoding.UTF8.GetBytes(plaintextStr);
- var encryptedBytesResult = await client.EncryptAsync(componentName, plaintextBytes, keyName, new EncryptionOptions(KeyWrapAlgorithm.Rsa),
- cancellationToken);
-
- Console.WriteLine($"Encrypted bytes: '{Convert.ToBase64String(encryptedBytesResult.Span)}'");
-
- //Decrypt the string
- var decryptedBytes = await client.DecryptAsync(componentName, encryptedBytesResult, keyName, cancellationToken);
- Console.WriteLine($"Decrypted string: '{Encoding.UTF8.GetString(decryptedBytes.ToArray())}'");
- }
- }
-}
diff --git a/examples/Client/Cryptography/Program.cs b/examples/Client/Cryptography/Program.cs
deleted file mode 100644
index 5c63d736..00000000
--- a/examples/Client/Cryptography/Program.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-// ------------------------------------------------------------------------
-// Copyright 2023 The Dapr Authors
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-// http://www.apache.org/licenses/LICENSE-2.0
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-// ------------------------------------------------------------------------
-
-using Cryptography.Examples;
-
-namespace Cryptography
-{
- class Program
- {
- private const string ComponentName = "localstorage";
- private const string KeyName = "rsa-private-key.pem"; //This should match the name of your generated key - this sample expects an RSA symmetrical key.
-
- private static readonly Example[] Examples = new Example[]
- {
- new EncryptDecryptStringExample(ComponentName, KeyName),
- new EncryptDecryptFileStreamExample(ComponentName, KeyName)
- };
-
- static async Task Main(string[] args)
- {
- if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
- {
- var cts = new CancellationTokenSource();
- Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
-
- await Examples[index].RunAsync(cts.Token);
- return 0;
- }
-
- Console.WriteLine("Hello, please choose a sample to run by passing your selection's number into the arguments, e.g. 'dotnet run 0':");
- for (var i = 0; i < Examples.Length; i++)
- {
- Console.WriteLine($"{i}: {Examples[i].DisplayName}");
- }
- Console.WriteLine();
- return 1;
- }
- }
-}
diff --git a/examples/Client/DistributedLock/Controllers/BindingController.cs b/examples/Client/DistributedLock/Controllers/BindingController.cs
index aa4dd1f5..64228df4 100644
--- a/examples/Client/DistributedLock/Controllers/BindingController.cs
+++ b/examples/Client/DistributedLock/Controllers/BindingController.cs
@@ -1,4 +1,5 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
@@ -8,100 +9,86 @@ using DistributedLock.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
-namespace DistributedLock.Controllers
+namespace DistributedLock.Controllers;
+
+[ApiController]
+[Experimental("DAPR_DISTRIBUTEDLOCK", UrlFormat = "https://docs.dapr.io/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview/")]
+public class BindingController(DaprClient client, ILogger logger) : ControllerBase
{
- [ApiController]
- public class BindingController : ControllerBase
+ private string appId = Environment.GetEnvironmentVariable("APP_ID");
+
+ [HttpPost("cronbinding")]
+ public async Task HandleBindingEvent()
{
- private DaprClient client;
- private ILogger logger;
- private string appId;
+ logger.LogInformation("Received binding event on {appId}, scanning for work.", appId);
- public BindingController(DaprClient client, ILogger logger)
+ var request = new BindingRequest("localstorage", "list");
+ var result = client.InvokeBindingAsync(request);
+
+ var rawData = result.Result.Data.ToArray();
+ var files = JsonSerializer.Deserialize(rawData);
+
+ if (files != null)
{
- this.client = client;
- this.logger = logger;
- this.appId = Environment.GetEnvironmentVariable("APP_ID");
- }
-
- [HttpPost("cronbinding")]
- [Obsolete]
- public async Task HandleBindingEvent()
- {
- logger.LogInformation($"Received binding event on {appId}, scanning for work.");
-
- var request = new BindingRequest("localstorage", "list");
- var result = client.InvokeBindingAsync(request);
-
- var rawData = result.Result.Data.ToArray();
- var files = JsonSerializer.Deserialize(rawData);
-
- if (files != null)
+ foreach (var file in files.Select(file => file.Split("/").Last()).OrderBy(file => file))
{
- foreach (var file in files.Select(file => file.Split("/").Last()).OrderBy(file => file))
- {
- await AttemptToProcessFile(file);
- }
+ await AttemptToProcessFile(file);
}
+ }
- return Ok();
- }
+ return Ok();
+ }
-
- [Obsolete]
- private async Task AttemptToProcessFile(string fileName)
+ private async Task AttemptToProcessFile(string fileName)
+ {
+ // Locks are Disposable and will automatically unlock at the end of a 'using' statement.
+ logger.LogInformation("Attempting to lock: {fileName}", fileName);
+ await using var fileLock = await client.Lock("redislock", fileName, appId, 60);
+ if (fileLock.Success)
{
- // Locks are Disposable and will automatically unlock at the end of a 'using' statement.
- logger.LogInformation($"Attempting to lock: {fileName}");
- await using (var fileLock = await client.Lock("redislock", fileName, appId, 60))
+ logger.LogInformation("Successfully locked file: {fileName}", fileName);
+
+ // Get the file after we've locked it, we're safe here because of the lock.
+ var fileState = await GetFile(fileName);
+
+ if (fileState == null)
{
- if (fileLock.Success)
- {
- logger.LogInformation($"Successfully locked file: {fileName}");
-
- // Get the file after we've locked it, we're safe here because of the lock.
- var fileState = await GetFile(fileName);
-
- if (fileState == null)
- {
- logger.LogWarning($"File {fileName} has already been processed!");
- return;
- }
-
- // "Analyze" the file before committing it to our remote storage.
- fileState.Analysis = fileState.Number > 50 ? "High" : "Low";
-
- // Save it to remote storage.
- await client.SaveStateAsync("redisstore", fileName, fileState);
-
- // Remove it from local storage.
- var bindingDeleteRequest = new BindingRequest("localstorage", "delete");
- bindingDeleteRequest.Metadata["fileName"] = fileName;
- await client.InvokeBindingAsync(bindingDeleteRequest);
-
- logger.LogInformation($"Done processing {fileName}");
- }
- else
- {
- logger.LogWarning($"Failed to lock {fileName}.");
- }
+ logger.LogWarning("File {fileName} has already been processed!", fileName);
+ return;
}
+
+ // "Analyze" the file before committing it to our remote storage.
+ fileState.Analysis = fileState.Number > 50 ? "High" : "Low";
+
+ // Save it to remote storage.
+ await client.SaveStateAsync("redisstore", fileName, fileState);
+
+ // Remove it from local storage.
+ var bindingDeleteRequest = new BindingRequest("localstorage", "delete");
+ bindingDeleteRequest.Metadata["fileName"] = fileName;
+ await client.InvokeBindingAsync(bindingDeleteRequest);
+
+ logger.LogInformation("Done processing {fileName}", fileName);
}
-
- private async Task GetFile(string fileName)
+ else
{
- try
- {
- var bindingGetRequest = new BindingRequest("localstorage", "get");
- bindingGetRequest.Metadata["fileName"] = fileName;
-
- var bindingResponse = await client.InvokeBindingAsync(bindingGetRequest);
- return JsonSerializer.Deserialize(bindingResponse.Data.ToArray());
- }
- catch (DaprException)
- {
- return null;
- }
+ logger.LogWarning("Failed to lock {fileName}.", fileName);
}
}
+
+ private async Task GetFile(string fileName)
+ {
+ try
+ {
+ var bindingGetRequest = new BindingRequest("localstorage", "get");
+ bindingGetRequest.Metadata["fileName"] = fileName;
+
+ var bindingResponse = await client.InvokeBindingAsync(bindingGetRequest);
+ return JsonSerializer.Deserialize(bindingResponse.Data.ToArray());
+ }
+ catch (DaprException)
+ {
+ return null;
+ }
+ }
}
diff --git a/examples/Client/DistributedLock/DistributedLock.csproj b/examples/Client/DistributedLock/DistributedLock.csproj
index 4c04fb90..6c001948 100644
--- a/examples/Client/DistributedLock/DistributedLock.csproj
+++ b/examples/Client/DistributedLock/DistributedLock.csproj
@@ -1,14 +1,7 @@
-
-
-
- net6
-
-
-
diff --git a/examples/Client/DistributedLock/Model/StateData.cs b/examples/Client/DistributedLock/Model/StateData.cs
index 0ad5d2fd..f5eeeb29 100644
--- a/examples/Client/DistributedLock/Model/StateData.cs
+++ b/examples/Client/DistributedLock/Model/StateData.cs
@@ -1,15 +1,13 @@
-namespace DistributedLock.Model
-{
+namespace DistributedLock.Model;
#nullable enable
- public class StateData
- {
- public int Number { get; }
- public string? Analysis { get; set; }
+public class StateData
+{
+ public int Number { get; }
+ public string? Analysis { get; set; }
- public StateData(int number, string? analysis = null)
- {
- Number = number;
- Analysis = analysis;
- }
+ public StateData(int number, string? analysis = null)
+ {
+ Number = number;
+ Analysis = analysis;
}
-}
+}
\ No newline at end of file
diff --git a/examples/Client/DistributedLock/Program.cs b/examples/Client/DistributedLock/Program.cs
index 3080b5b1..830fb5dc 100644
--- a/examples/Client/DistributedLock/Program.cs
+++ b/examples/Client/DistributedLock/Program.cs
@@ -2,22 +2,21 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
-namespace DistributedLock
-{
- public class Program
- {
- static string DEFAULT_APP_PORT = "22222";
- public static void Main(string[] args)
- {
- CreateHostBuilder(args).Build().Run();
- }
+namespace DistributedLock;
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup()
- .UseUrls($"http://localhost:{Environment.GetEnvironmentVariable("APP_PORT") ?? DEFAULT_APP_PORT}");
- });
+public class Program
+{
+ static string DEFAULT_APP_PORT = "22222";
+ public static void Main(string[] args)
+ {
+ CreateHostBuilder(args).Build().Run();
}
-}
+
+ public static IHostBuilder CreateHostBuilder(string[] args) =>
+ Host.CreateDefaultBuilder(args)
+ .ConfigureWebHostDefaults(webBuilder =>
+ {
+ webBuilder.UseStartup()
+ .UseUrls($"http://localhost:{Environment.GetEnvironmentVariable("APP_PORT") ?? DEFAULT_APP_PORT}");
+ });
+}
\ No newline at end of file
diff --git a/examples/Client/DistributedLock/README.md b/examples/Client/DistributedLock/README.md
index 6a1af3b3..26098335 100644
--- a/examples/Client/DistributedLock/README.md
+++ b/examples/Client/DistributedLock/README.md
@@ -2,13 +2,13 @@
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
## Distributed Lock API
-Dapr 1.8 introduces the Distributed Lock API. This API can be used to prevent multiple processes from accessing the same resource. In Dapr, locks are scoped to a specific App ID.
+Dapr 1.8 introduced the Distributed Lock API. This API can be used to prevent multiple processes from accessing the same resource. In Dapr, locks are scoped to a specific App ID.
For this example, we will be running multiple instances of the same application to demonstrate an event driven consumer pattern. This example also includes a simple generator that creates some data that can be processed.
diff --git a/examples/Client/DistributedLock/Services/GeneratorService.cs b/examples/Client/DistributedLock/Services/GeneratorService.cs
index aa59d9b7..4d5c0a3f 100644
--- a/examples/Client/DistributedLock/Services/GeneratorService.cs
+++ b/examples/Client/DistributedLock/Services/GeneratorService.cs
@@ -3,30 +3,29 @@ using System.Threading;
using Dapr.Client;
using DistributedLock.Model;
-namespace DistributedLock.Services
+namespace DistributedLock.Services;
+
+public class GeneratorService
{
- public class GeneratorService
+ Timer generateDataTimer;
+
+ public GeneratorService()
{
- Timer generateDataTimer;
-
- public GeneratorService()
+ // Generate some data every second.
+ if (Environment.GetEnvironmentVariable("APP_ID") == "generator")
{
- // Generate some data every second.
- if (Environment.GetEnvironmentVariable("APP_ID") == "generator")
- {
- generateDataTimer = new Timer(GenerateData, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10));
- }
- }
-
- public async void GenerateData(Object stateInfo)
- {
- using (var client = new DaprClientBuilder().Build())
- {
- var rand = new Random();
- var state = new StateData(rand.Next(100));
-
- await client.InvokeBindingAsync("localstorage", "create", state);
- }
+ generateDataTimer = new Timer(GenerateData, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(10));
}
}
-}
+
+ public async void GenerateData(Object stateInfo)
+ {
+ using (var client = new DaprClientBuilder().Build())
+ {
+ var rand = new Random();
+ var state = new StateData(rand.Next(100));
+
+ await client.InvokeBindingAsync("localstorage", "create", state);
+ }
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/DistributedLock/Startup.cs b/examples/Client/DistributedLock/Startup.cs
index 9f40e475..0e2e0df3 100644
--- a/examples/Client/DistributedLock/Startup.cs
+++ b/examples/Client/DistributedLock/Startup.cs
@@ -1,46 +1,45 @@
using Dapr.AspNetCore;
-using DistributedLock.Services;
+using DistributedLock.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
-namespace DistributedLock
+namespace DistributedLock;
+
+public class Startup
{
- public class Startup
+ public Startup(IConfiguration configuration)
{
- public Startup(IConfiguration configuration)
- {
- Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
- // This method gets called by the runtime. Use this method to add services to the container.
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddControllers().AddDapr();
- services.AddLogging();
- services.AddSingleton(new GeneratorService());
- }
-
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- {
- app.UseDeveloperExceptionPage();
- }
-
- app.UseRouting();
-
- app.UseAuthorization();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- });
- }
+ Configuration = configuration;
}
-}
+
+ public IConfiguration Configuration { get; }
+
+ // This method gets called by the runtime. Use this method to add services to the container.
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services.AddControllers().AddDapr();
+ services.AddLogging();
+ services.AddSingleton(new GeneratorService());
+ }
+
+ // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+ {
+ if (env.IsDevelopment())
+ {
+ app.UseDeveloperExceptionPage();
+ }
+
+ app.UseRouting();
+
+ app.UseAuthorization();
+
+ app.UseEndpoints(endpoints =>
+ {
+ endpoints.MapControllers();
+ });
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.cs b/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.cs
index 34361845..af1fc639 100644
--- a/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.cs
+++ b/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.cs
@@ -17,46 +17,45 @@ using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
-namespace Samples.Client
+namespace Samples.Client;
+
+public sealed class BulkPublishEventExample : Example
{
- public class BulkPublishEventExample : Example
- {
- private const string PubsubName = "pubsub";
- private const string TopicName = "deposit";
+ private const string PubsubName = "pubsub";
+ private const string TopicName = "deposit";
- IReadOnlyList BulkPublishData = new List() {
- new { Id = "17", Amount = 10m },
- new { Id = "18", Amount = 20m },
- new { Id = "19", Amount = 30m }
- };
+ IReadOnlyList BulkPublishData = new List() {
+ new { Id = "17", Amount = 10m },
+ new { Id = "18", Amount = 20m },
+ new { Id = "19", Amount = 30m }
+ };
- public override string DisplayName => "Bulk Publishing Events";
+ public override string DisplayName => "Bulk Publishing Events";
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
+ public override async Task RunAsync(CancellationToken cancellationToken)
+ {
+ using var client = new DaprClientBuilder().Build();
- var res = await client.BulkPublishEventAsync(PubsubName, TopicName,
- BulkPublishData);
+ var res = await client.BulkPublishEventAsync(PubsubName, TopicName,
+ BulkPublishData, cancellationToken: cancellationToken);
- if (res != null) {
- if (res.FailedEntries.Count > 0)
- {
- Console.WriteLine("Some events failed to be published!");
+ if (res != null) {
+ if (res.FailedEntries.Count > 0)
+ {
+ Console.WriteLine("Some events failed to be published!");
- foreach (var failedEntry in res.FailedEntries)
- {
- Console.WriteLine("EntryId : " + failedEntry.Entry.EntryId + " Error message : " +
- failedEntry.ErrorMessage);
- }
- }
- else
+ foreach (var failedEntry in res.FailedEntries)
{
- Console.WriteLine("Published multiple deposit events!");
+ Console.WriteLine("EntryId : " + failedEntry.Entry.EntryId + " Error message : " +
+ failedEntry.ErrorMessage);
}
- } else {
- throw new Exception("null response from dapr");
}
+ else
+ {
+ Console.WriteLine("Published multiple deposit events!");
+ }
+ } else {
+ throw new Exception("null response from dapr");
}
}
}
diff --git a/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.csproj b/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.csproj
index b1e7647c..bccce505 100644
--- a/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.csproj
+++ b/examples/Client/PublishSubscribe/BulkPublishEventExample/BulkPublishEventExample.csproj
@@ -2,7 +2,6 @@
Exe
- net6
Samples.Client
enable
diff --git a/examples/Client/PublishSubscribe/BulkPublishEventExample/Example.cs b/examples/Client/PublishSubscribe/BulkPublishEventExample/Example.cs
index e12e38d1..eb0b8c3d 100644
--- a/examples/Client/PublishSubscribe/BulkPublishEventExample/Example.cs
+++ b/examples/Client/PublishSubscribe/BulkPublishEventExample/Example.cs
@@ -14,12 +14,11 @@
using System.Threading;
using System.Threading.Tasks;
-namespace Samples.Client
-{
- public abstract class Example
- {
- public abstract string DisplayName { get; }
+namespace Samples.Client;
- public abstract Task RunAsync(CancellationToken cancellationToken);
- }
-}
+public abstract class Example
+{
+ public abstract string DisplayName { get; }
+
+ public abstract Task RunAsync(CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/examples/Client/PublishSubscribe/BulkPublishEventExample/Program.cs b/examples/Client/PublishSubscribe/BulkPublishEventExample/Program.cs
index 47698235..768f5ad4 100644
--- a/examples/Client/PublishSubscribe/BulkPublishEventExample/Program.cs
+++ b/examples/Client/PublishSubscribe/BulkPublishEventExample/Program.cs
@@ -13,35 +13,26 @@
using System;
using System.Threading;
-using System.Threading.Tasks;
+using Samples.Client;
-namespace Samples.Client
+Example[] Examples =
+[
+ new BulkPublishEventExample()
+];
+
+if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
{
- class Program
- {
- private static readonly Example[] Examples = new Example[]
- {
- new BulkPublishEventExample(),
- };
+ var cts = new CancellationTokenSource();
+ Console.CancelKeyPress += (_, _) => cts.Cancel();
- static async Task Main(string[] args)
- {
- if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
- {
- var cts = new CancellationTokenSource();
- Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
-
- await Examples[index].RunAsync(cts.Token);
- return 0;
- }
-
- Console.WriteLine("Hello, please choose a sample to run:");
- for (var i = 0; i < Examples.Length; i++)
- {
- Console.WriteLine($"{i}: {Examples[i].DisplayName}");
- }
- Console.WriteLine();
- return 0;
- }
- }
+ await Examples[index].RunAsync(cts.Token);
+ return 0;
}
+
+Console.WriteLine("Hello, please choose a sample to run:");
+for (var i = 0; i < Examples.Length; i++)
+{
+ Console.WriteLine($"{i}: {Examples[i].DisplayName}");
+}
+Console.WriteLine();
+return 0;
diff --git a/examples/Client/PublishSubscribe/BulkPublishEventExample/README.md b/examples/Client/PublishSubscribe/BulkPublishEventExample/README.md
index 39d206fa..652e59d0 100644
--- a/examples/Client/PublishSubscribe/BulkPublishEventExample/README.md
+++ b/examples/Client/PublishSubscribe/BulkPublishEventExample/README.md
@@ -2,7 +2,7 @@
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/Client/PublishSubscribe/PublishEventExample/Example.cs b/examples/Client/PublishSubscribe/PublishEventExample/Example.cs
index fbe78124..fe51b56f 100644
--- a/examples/Client/PublishSubscribe/PublishEventExample/Example.cs
+++ b/examples/Client/PublishSubscribe/PublishEventExample/Example.cs
@@ -14,14 +14,13 @@
using System.Threading;
using System.Threading.Tasks;
-namespace Samples.Client
+namespace Samples.Client;
+
+public abstract class Example
{
- public abstract class Example
- {
- protected static readonly string pubsubName = "pubsub";
+ protected static readonly string pubsubName = "pubsub";
- public abstract string DisplayName { get; }
+ public abstract string DisplayName { get; }
- public abstract Task RunAsync(CancellationToken cancellationToken);
- }
-}
+ public abstract Task RunAsync(CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/examples/Client/PublishSubscribe/PublishEventExample/Program.cs b/examples/Client/PublishSubscribe/PublishEventExample/Program.cs
index af74ad90..e1f5c95e 100644
--- a/examples/Client/PublishSubscribe/PublishEventExample/Program.cs
+++ b/examples/Client/PublishSubscribe/PublishEventExample/Program.cs
@@ -15,34 +15,33 @@ using System;
using System.Threading;
using System.Threading.Tasks;
-namespace Samples.Client
+namespace Samples.Client;
+
+class Program
{
- class Program
+ private static readonly Example[] Examples = new Example[]
{
- private static readonly Example[] Examples = new Example[]
+ new PublishEventExample(),
+ new PublishBytesExample(),
+ };
+
+ static async Task Main(string[] args)
+ {
+ if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
{
- new PublishEventExample(),
- new PublishBytesExample(),
- };
+ var cts = new CancellationTokenSource();
+ Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
- static async Task Main(string[] args)
- {
- if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
- {
- var cts = new CancellationTokenSource();
- Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
-
- await Examples[index].RunAsync(cts.Token);
- return 0;
- }
-
- Console.WriteLine("Hello, please choose a sample to run:");
- for (var i = 0; i < Examples.Length; i++)
- {
- Console.WriteLine($"{i}: {Examples[i].DisplayName}");
- }
- Console.WriteLine();
+ await Examples[index].RunAsync(cts.Token);
return 0;
}
+
+ Console.WriteLine("Hello, please choose a sample to run:");
+ for (var i = 0; i < Examples.Length; i++)
+ {
+ Console.WriteLine($"{i}: {Examples[i].DisplayName}");
+ }
+ Console.WriteLine();
+ return 0;
}
-}
+}
\ No newline at end of file
diff --git a/examples/Client/PublishSubscribe/PublishEventExample/PublishBytesExample.cs b/examples/Client/PublishSubscribe/PublishEventExample/PublishBytesExample.cs
index 3334421c..4834e80a 100644
--- a/examples/Client/PublishSubscribe/PublishEventExample/PublishBytesExample.cs
+++ b/examples/Client/PublishSubscribe/PublishEventExample/PublishBytesExample.cs
@@ -19,21 +19,20 @@ using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
-namespace Samples.Client
+namespace Samples.Client;
+
+public class PublishBytesExample : Example
{
- public class PublishBytesExample : Example
+ public override string DisplayName => "Publish Bytes";
+
+ public async override Task RunAsync(CancellationToken cancellationToken)
{
- public override string DisplayName => "Publish Bytes";
+ using var client = new DaprClientBuilder().Build();
- public async override Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
+ var transaction = new { Id = "17", Amount = 30m };
+ var content = JsonSerializer.SerializeToUtf8Bytes(transaction);
- var transaction = new { Id = "17", Amount = 30m };
- var content = JsonSerializer.SerializeToUtf8Bytes(transaction);
-
- await client.PublishByteEventAsync(pubsubName, "deposit", content.AsMemory(), MediaTypeNames.Application.Json, new Dictionary { }, cancellationToken);
- Console.WriteLine("Published deposit event!");
- }
+ await client.PublishByteEventAsync(pubsubName, "deposit", content.AsMemory(), MediaTypeNames.Application.Json, new Dictionary { }, cancellationToken);
+ Console.WriteLine("Published deposit event!");
}
-}
+}
\ No newline at end of file
diff --git a/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.cs b/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.cs
index 9d34ae50..e8b1e80e 100644
--- a/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.cs
+++ b/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.cs
@@ -16,19 +16,18 @@ using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
-namespace Samples.Client
+namespace Samples.Client;
+
+public class PublishEventExample : Example
{
- public class PublishEventExample : Example
+ public override string DisplayName => "Publishing Events";
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
{
- public override string DisplayName => "Publishing Events";
+ using var client = new DaprClientBuilder().Build();
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
-
- var eventData = new { Id = "17", Amount = 10m, };
- await client.PublishEventAsync(pubsubName, "deposit", eventData, cancellationToken);
- Console.WriteLine("Published deposit event!");
- }
+ var eventData = new { Id = "17", Amount = 10m, };
+ await client.PublishEventAsync(pubsubName, "deposit", eventData, cancellationToken);
+ Console.WriteLine("Published deposit event!");
}
-}
+}
\ No newline at end of file
diff --git a/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.csproj b/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.csproj
index 52b77a3e..93500fa1 100644
--- a/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.csproj
+++ b/examples/Client/PublishSubscribe/PublishEventExample/PublishEventExample.csproj
@@ -2,7 +2,6 @@
Exe
- net6
Samples.Client
enable
diff --git a/examples/Client/PublishSubscribe/PublishEventExample/README.md b/examples/Client/PublishSubscribe/PublishEventExample/README.md
index 9f3af565..efc93143 100644
--- a/examples/Client/PublishSubscribe/PublishEventExample/README.md
+++ b/examples/Client/PublishSubscribe/PublishEventExample/README.md
@@ -2,7 +2,7 @@
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/Client/ServiceInvocation/Example.cs b/examples/Client/ServiceInvocation/Example.cs
index d2c07bfe..507bdcfd 100644
--- a/examples/Client/ServiceInvocation/Example.cs
+++ b/examples/Client/ServiceInvocation/Example.cs
@@ -14,12 +14,11 @@
using System.Threading;
using System.Threading.Tasks;
-namespace Samples.Client
-{
- public abstract class Example
- {
- public abstract string DisplayName { get; }
+namespace Samples.Client;
- public abstract Task RunAsync(CancellationToken cancellationToken);
- }
-}
+public abstract class Example
+{
+ public abstract string DisplayName { get; }
+
+ public abstract Task RunAsync(CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/examples/Client/ServiceInvocation/InvokeServiceGrpcExample.cs b/examples/Client/ServiceInvocation/InvokeServiceGrpcExample.cs
index 564cf038..127d9003 100644
--- a/examples/Client/ServiceInvocation/InvokeServiceGrpcExample.cs
+++ b/examples/Client/ServiceInvocation/InvokeServiceGrpcExample.cs
@@ -17,32 +17,31 @@ using System.Threading.Tasks;
using Dapr.Client;
using GrpcServiceSample.Generated;
-namespace Samples.Client
+namespace Samples.Client;
+
+public class InvokeServiceGrpcExample : Example
{
- public class InvokeServiceGrpcExample : Example
+ public override string DisplayName => "Invoking a gRPC service with gRPC semantics and Protobuf with DaprClient";
+
+ // Note: the data types used in this sample are generated from data.proto in GrpcServiceSample
+ public override async Task RunAsync(CancellationToken cancellationToken)
{
- public override string DisplayName => "Invoking a gRPC service with gRPC semantics and Protobuf with DaprClient";
+ using var client = new DaprClientBuilder().Build();
- // Note: the data types used in this sample are generated from data.proto in GrpcServiceSample
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
+ Console.WriteLine("Invoking grpc deposit");
+ var deposit = new GrpcServiceSample.Generated.Transaction() { Id = "17", Amount = 99 };
+ var account = await client.InvokeMethodGrpcAsync("grpcsample", "deposit", deposit, cancellationToken);
+ Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
+ Console.WriteLine("Completed grpc deposit");
- Console.WriteLine("Invoking grpc deposit");
- var deposit = new GrpcServiceSample.Generated.Transaction() { Id = "17", Amount = 99 };
- var account = await client.InvokeMethodGrpcAsync("grpcsample", "deposit", deposit, cancellationToken);
- Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
- Console.WriteLine("Completed grpc deposit");
+ Console.WriteLine("Invoking grpc withdraw");
+ var withdraw = new GrpcServiceSample.Generated.Transaction() { Id = "17", Amount = 10, };
+ await client.InvokeMethodGrpcAsync("grpcsample", "withdraw", withdraw, cancellationToken);
+ Console.WriteLine("Completed grpc withdraw");
- Console.WriteLine("Invoking grpc withdraw");
- var withdraw = new GrpcServiceSample.Generated.Transaction() { Id = "17", Amount = 10, };
- await client.InvokeMethodGrpcAsync("grpcsample", "withdraw", withdraw, cancellationToken);
- Console.WriteLine("Completed grpc withdraw");
-
- Console.WriteLine("Invoking grpc balance");
- var request = new GetAccountRequest() { Id = "17", };
- account = await client.InvokeMethodGrpcAsync("grpcsample", "getaccount", request, cancellationToken);
- Console.WriteLine($"Received grpc balance {account.Balance}");
- }
+ Console.WriteLine("Invoking grpc balance");
+ var request = new GetAccountRequest() { Id = "17", };
+ account = await client.InvokeMethodGrpcAsync("grpcsample", "getaccount", request, cancellationToken);
+ Console.WriteLine($"Received grpc balance {account.Balance}");
}
-}
+}
\ No newline at end of file
diff --git a/examples/Client/ServiceInvocation/InvokeServiceHttpClientExample.cs b/examples/Client/ServiceInvocation/InvokeServiceHttpClientExample.cs
index 72d68096..415e984e 100644
--- a/examples/Client/ServiceInvocation/InvokeServiceHttpClientExample.cs
+++ b/examples/Client/ServiceInvocation/InvokeServiceHttpClientExample.cs
@@ -17,41 +17,40 @@ using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
-namespace Samples.Client
+namespace Samples.Client;
+
+public class InvokeServiceHttpClientExample : Example
{
- public class InvokeServiceHttpClientExample : Example
+ public override string DisplayName => "Invoking an HTTP service with HttpClient";
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
{
- public override string DisplayName => "Invoking an HTTP service with HttpClient";
+ var client = DaprClient.CreateInvokeHttpClient(appId: "routing");
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- var client = DaprClient.CreateInvokeHttpClient(appId: "routing");
+ var deposit = new Transaction { Id = "17", Amount = 99m };
+ var response = await client.PostAsJsonAsync("/deposit", deposit, cancellationToken);
+ var account = await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
+ Console.WriteLine("Returned: id:{0} | Balance:{1}", account?.Id, account?.Balance);
- var deposit = new Transaction { Id = "17", Amount = 99m };
- var response = await client.PostAsJsonAsync("/deposit", deposit, cancellationToken);
- var account = await response.Content.ReadFromJsonAsync(cancellationToken: cancellationToken);
- Console.WriteLine("Returned: id:{0} | Balance:{1}", account?.Id, account?.Balance);
+ var withdraw = new Transaction { Id = "17", Amount = 10m, };
+ response = await client.PostAsJsonAsync("/withdraw", withdraw, cancellationToken);
+ response.EnsureSuccessStatusCode();
- var withdraw = new Transaction { Id = "17", Amount = 10m, };
- response = await client.PostAsJsonAsync("/withdraw", withdraw, cancellationToken);
- response.EnsureSuccessStatusCode();
-
- account = await client.GetFromJsonAsync("/17", cancellationToken);
- Console.WriteLine($"Received balance {account?.Balance}");
- }
-
- internal class Transaction
- {
- public string? Id { get; set; }
-
- public decimal? Amount { get; set; }
- }
-
- internal class Account
- {
- public string? Id { get; set; }
-
- public decimal? Balance { get; set; }
- }
+ account = await client.GetFromJsonAsync("/17", cancellationToken);
+ Console.WriteLine($"Received balance {account?.Balance}");
}
-}
+
+ internal class Transaction
+ {
+ public string? Id { get; set; }
+
+ public decimal? Amount { get; set; }
+ }
+
+ internal class Account
+ {
+ public string? Id { get; set; }
+
+ public decimal? Balance { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/ServiceInvocation/InvokeServiceHttpExample.cs b/examples/Client/ServiceInvocation/InvokeServiceHttpExample.cs
index 74235c13..5595ae26 100644
--- a/examples/Client/ServiceInvocation/InvokeServiceHttpExample.cs
+++ b/examples/Client/ServiceInvocation/InvokeServiceHttpExample.cs
@@ -17,46 +17,45 @@ using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
-namespace Samples.Client
+namespace Samples.Client;
+
+public class InvokeServiceHttpExample : Example
{
- public class InvokeServiceHttpExample : Example
+ public override string DisplayName => "Invoking an HTTP service with DaprClient";
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
{
- public override string DisplayName => "Invoking an HTTP service with DaprClient";
+ using var client = new DaprClientBuilder().Build();
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
+ // Invokes a POST method named "deposit" that takes input of type "Transaction" as define in the RoutingSample.
+ Console.WriteLine("Invoking deposit");
+ var data = new { id = "17", amount = 99m };
+ var account = await client.InvokeMethodAsync("routing", "deposit", data, cancellationToken);
+ Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
- // Invokes a POST method named "deposit" that takes input of type "Transaction" as define in the RoutingSample.
- Console.WriteLine("Invoking deposit");
- var data = new { id = "17", amount = 99m };
- var account = await client.InvokeMethodAsync("routing", "deposit", data, cancellationToken);
- Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
+ // Invokes a POST method named "Withdraw" that takes input of type "Transaction" as define in the RoutingSample.
+ Console.WriteLine("Invoking withdraw");
+ data = new { id = "17", amount = 10m, };
+ await client.InvokeMethodAsync("routing", "Withdraw", data, cancellationToken);
+ Console.WriteLine("Completed");
- // Invokes a POST method named "Withdraw" that takes input of type "Transaction" as define in the RoutingSample.
- Console.WriteLine("Invoking withdraw");
- data = new { id = "17", amount = 10m, };
- await client.InvokeMethodAsync("routing", "Withdraw", data, cancellationToken);
- Console.WriteLine("Completed");
-
- // Invokes a GET method named "hello" that takes input of type "MyData" and returns a string.
- Console.WriteLine("Invoking balance");
- account = await client.InvokeMethodAsync(HttpMethod.Get, "routing", "17", cancellationToken);
- Console.WriteLine($"Received balance {account.Balance}");
- }
-
- internal class Transaction
- {
- public string? Id { get; set; }
-
- public decimal? Amount { get; set; }
- }
-
- internal class Account
- {
- public string? Id { get; set; }
-
- public decimal? Balance { get; set; }
- }
+ // Invokes a GET method named "hello" that takes input of type "MyData" and returns a string.
+ Console.WriteLine("Invoking balance");
+ account = await client.InvokeMethodAsync(HttpMethod.Get, "routing", "17", cancellationToken);
+ Console.WriteLine($"Received balance {account.Balance}");
}
-}
+
+ internal class Transaction
+ {
+ public string? Id { get; set; }
+
+ public decimal? Amount { get; set; }
+ }
+
+ internal class Account
+ {
+ public string? Id { get; set; }
+
+ public decimal? Balance { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/ServiceInvocation/InvokeServiceHttpNonDaprEndpointExample.cs b/examples/Client/ServiceInvocation/InvokeServiceHttpNonDaprEndpointExample.cs
index bc0d7c59..2647ac9d 100644
--- a/examples/Client/ServiceInvocation/InvokeServiceHttpNonDaprEndpointExample.cs
+++ b/examples/Client/ServiceInvocation/InvokeServiceHttpNonDaprEndpointExample.cs
@@ -17,48 +17,45 @@ using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
-namespace Samples.Client
+namespace Samples.Client;
+
+public class InvokeServiceHttpNonDaprEndpointExample : Example
{
- public class InvokeServiceHttpNonDaprEndpointExample : Example
+ public override string DisplayName => "Invoke a non Dapr endpoint using DaprClient";
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
{
- public override string DisplayName => "Invoke a non Dapr endpoint using DaprClient";
-
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
+ using var client = new DaprClientBuilder().Build();
- // Invoke a POST method named "deposit" that takes input of type "Transaction" as defined in the RoutingSample.
- Console.WriteLine("Invoking deposit using non Dapr endpoint.");
- var data = new { id = "17", amount = 99m };
- var account = await client.InvokeMethodAsync("http://localhost:5000", "deposit", data, cancellationToken);
- Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
+ // Invoke a POST method named "deposit" that takes input of type "Transaction" as defined in the RoutingSample.
+ Console.WriteLine("Invoking deposit using non Dapr endpoint.");
+ var data = new { id = "17", amount = 99m };
+ var account = await client.InvokeMethodAsync("http://localhost:5000", "deposit", data, cancellationToken);
+ Console.WriteLine("Returned: id:{0} | Balance:{1}", account.Id, account.Balance);
- // Invokes a POST method named "Withdraw" that takes input of type "Transaction" as defined in the RoutingSample.
- Console.WriteLine("Invoking withdraw using non Dapr endpoint.");
- data = new { id = "17", amount = 10m, };
- await client.InvokeMethodAsync("http://localhost:5000", "withdraw", data, cancellationToken);
- Console.WriteLine("Completed");
+ // Invokes a POST method named "Withdraw" that takes input of type "Transaction" as defined in the RoutingSample.
+ Console.WriteLine("Invoking withdraw using non Dapr endpoint.");
+ data = new { id = "17", amount = 10m, };
+ await client.InvokeMethodAsync("http://localhost:5000", "withdraw", data, cancellationToken);
+ Console.WriteLine("Completed");
- // Invokes a GET method named "hello" that takes input of type "MyData" and returns a string.
- Console.WriteLine("Invoking balance using non Dapr endpoint.");
- account = await client.InvokeMethodAsync(HttpMethod.Get, "http://localhost:5000", "17", cancellationToken);
- Console.WriteLine($"Received balance {account.Balance}");
- }
-
- internal class Transaction
- {
- public string? Id { get; set; }
-
- public decimal Amount { get; set; }
- }
-
- internal class Account
- {
- public string? Id { get; set; }
-
- public decimal Balance { get; set; }
- }
+ // Invokes a GET method named "hello" that takes input of type "MyData" and returns a string.
+ Console.WriteLine("Invoking balance using non Dapr endpoint.");
+ account = await client.InvokeMethodAsync(HttpMethod.Get, "http://localhost:5000", "17", cancellationToken);
+ Console.WriteLine($"Received balance {account.Balance}");
}
-}
-
+ internal class Transaction
+ {
+ public string? Id { get; set; }
+
+ public decimal Amount { get; set; }
+ }
+
+ internal class Account
+ {
+ public string? Id { get; set; }
+
+ public decimal Balance { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/ServiceInvocation/Program.cs b/examples/Client/ServiceInvocation/Program.cs
index 08eda806..829789b1 100644
--- a/examples/Client/ServiceInvocation/Program.cs
+++ b/examples/Client/ServiceInvocation/Program.cs
@@ -15,36 +15,35 @@ using System;
using System.Threading;
using System.Threading.Tasks;
-namespace Samples.Client
+namespace Samples.Client;
+
+class Program
{
- class Program
+ private static readonly Example[] Examples =
+ [
+ new InvokeServiceGrpcExample(),
+ new InvokeServiceHttpExample(),
+ new InvokeServiceHttpClientExample(),
+ new InvokeServiceHttpNonDaprEndpointExample()
+ ];
+
+ static async Task Main(string[] args)
{
- private static readonly Example[] Examples = new Example[]
+ if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
{
- new InvokeServiceGrpcExample(),
- new InvokeServiceHttpExample(),
- new InvokeServiceHttpClientExample(),
- new InvokeServiceHttpNonDaprEndpointExample()
- };
+ var cts = new CancellationTokenSource();
+ Console.CancelKeyPress += (sender, e) => cts.Cancel();
- static async Task Main(string[] args)
- {
- if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
- {
- var cts = new CancellationTokenSource();
- Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
-
- await Examples[index].RunAsync(cts.Token);
- return 0;
- }
-
- Console.WriteLine("Hello, please choose a sample to run:");
- for (var i = 0; i < Examples.Length; i++)
- {
- Console.WriteLine($"{i}: {Examples[i].DisplayName}");
- }
- Console.WriteLine();
- return 1;
+ await Examples[index].RunAsync(cts.Token);
+ return 0;
}
+
+ Console.WriteLine("Hello, please choose a sample to run:");
+ for (var i = 0; i < Examples.Length; i++)
+ {
+ Console.WriteLine($"{i}: {Examples[i].DisplayName}");
+ }
+ Console.WriteLine();
+ return 1;
}
}
diff --git a/examples/Client/ServiceInvocation/README.md b/examples/Client/ServiceInvocation/README.md
index 1c83f8ff..60d7ca13 100644
--- a/examples/Client/ServiceInvocation/README.md
+++ b/examples/Client/ServiceInvocation/README.md
@@ -2,7 +2,7 @@
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/Client/ServiceInvocation/ServiceInvocation.csproj b/examples/Client/ServiceInvocation/ServiceInvocation.csproj
index 7b165835..e292e4ae 100644
--- a/examples/Client/ServiceInvocation/ServiceInvocation.csproj
+++ b/examples/Client/ServiceInvocation/ServiceInvocation.csproj
@@ -2,7 +2,6 @@
Exe
- net6
Samples.Client
enable
diff --git a/examples/Client/StateManagement/BulkStateExample.cs b/examples/Client/StateManagement/BulkStateExample.cs
index 250c69ce..da25b157 100644
--- a/examples/Client/StateManagement/BulkStateExample.cs
+++ b/examples/Client/StateManagement/BulkStateExample.cs
@@ -4,51 +4,50 @@ using System.Threading;
using System.Threading.Tasks;
using Dapr.Client;
-namespace Samples.Client
+namespace Samples.Client;
+
+public class BulkStateExample : Example
{
- public class BulkStateExample : Example
+ private static readonly string firstKey = "testKey1";
+ private static readonly string secondKey = "testKey2";
+ private static readonly string firstEtag = "123";
+ private static readonly string secondEtag = "456";
+ private static readonly string storeName = "statestore";
+
+ public override string DisplayName => "Using the State Store";
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
{
- private static readonly string firstKey = "testKey1";
- private static readonly string secondKey = "testKey2";
- private static readonly string firstEtag = "123";
- private static readonly string secondEtag = "456";
- private static readonly string storeName = "statestore";
+ using var client = new DaprClientBuilder().Build();
- public override string DisplayName => "Using the State Store";
-
- public override async Task RunAsync(CancellationToken cancellationToken)
- {
- using var client = new DaprClientBuilder().Build();
-
- var state1 = new Widget() { Size = "small", Color = "yellow", };
- var state2 = new Widget() { Size = "big", Color = "green", };
+ var state1 = new Widget() { Size = "small", Color = "yellow", };
+ var state2 = new Widget() { Size = "big", Color = "green", };
- var stateItem1 = new SaveStateItem(firstKey, state1, firstEtag);
- var stateItem2 = new SaveStateItem(secondKey, state2, secondEtag);
+ var stateItem1 = new SaveStateItem(firstKey, state1, firstEtag);
+ var stateItem2 = new SaveStateItem(secondKey, state2, secondEtag);
- await client.SaveBulkStateAsync(storeName, new List>() { stateItem1, stateItem2});
+ await client.SaveBulkStateAsync(storeName, new List>() { stateItem1, stateItem2});
- Console.WriteLine("Saved 2 States!");
+ Console.WriteLine("Saved 2 States!");
- await Task.Delay(2000);
+ await Task.Delay(2000);
- IReadOnlyList states = await client.GetBulkStateAsync(storeName,
- new List(){firstKey, secondKey}, null);
+ IReadOnlyList states = await client.GetBulkStateAsync(storeName,
+ new List(){firstKey, secondKey}, null);
- Console.WriteLine($"Got {states.Count} States: ");
+ Console.WriteLine($"Got {states.Count} States: ");
- var deleteBulkStateItem1 = new BulkDeleteStateItem(states[0].Key, states[0].ETag);
- var deleteBulkStateItem2 = new BulkDeleteStateItem(states[1].Key, states[1].ETag);
+ var deleteBulkStateItem1 = new BulkDeleteStateItem(states[0].Key, states[0].ETag);
+ var deleteBulkStateItem2 = new BulkDeleteStateItem(states[1].Key, states[1].ETag);
- await client.DeleteBulkStateAsync(storeName, new List() { deleteBulkStateItem1, deleteBulkStateItem2 });
+ await client.DeleteBulkStateAsync(storeName, new List() { deleteBulkStateItem1, deleteBulkStateItem2 });
- Console.WriteLine("Deleted States!");
- }
-
- private class Widget
- {
- public string? Size { get; set; }
- public string? Color { get; set; }
- }
+ Console.WriteLine("Deleted States!");
}
-}
+
+ private class Widget
+ {
+ public string? Size { get; set; }
+ public string? Color { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/examples/Client/StateManagement/Example.cs b/examples/Client/StateManagement/Example.cs
index d2c07bfe..507bdcfd 100644
--- a/examples/Client/StateManagement/Example.cs
+++ b/examples/Client/StateManagement/Example.cs
@@ -14,12 +14,11 @@
using System.Threading;
using System.Threading.Tasks;
-namespace Samples.Client
-{
- public abstract class Example
- {
- public abstract string DisplayName { get; }
+namespace Samples.Client;
- public abstract Task RunAsync(CancellationToken cancellationToken);
- }
-}
+public abstract class Example
+{
+ public abstract string DisplayName { get; }
+
+ public abstract Task RunAsync(CancellationToken cancellationToken);
+}
\ No newline at end of file
diff --git a/examples/Client/StateManagement/Program.cs b/examples/Client/StateManagement/Program.cs
index e9ef3697..006a0224 100644
--- a/examples/Client/StateManagement/Program.cs
+++ b/examples/Client/StateManagement/Program.cs
@@ -15,37 +15,36 @@ using System;
using System.Threading;
using System.Threading.Tasks;
-namespace Samples.Client
+namespace Samples.Client;
+
+class Program
{
- class Program
+ private static readonly Example[] Examples = new Example[]
{
- private static readonly Example[] Examples = new Example[]
+ new StateStoreExample(),
+ new StateStoreTransactionsExample(),
+ new StateStoreETagsExample(),
+ new BulkStateExample(),
+ new StateStoreBinaryExample()
+ };
+
+ static async Task Main(string[] args)
+ {
+ if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
{
- new StateStoreExample(),
- new StateStoreTransactionsExample(),
- new StateStoreETagsExample(),
- new BulkStateExample(),
- new StateStoreBinaryExample()
- };
+ var cts = new CancellationTokenSource();
+ Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
- static async Task Main(string[] args)
- {
- if (args.Length > 0 && int.TryParse(args[0], out var index) && index >= 0 && index < Examples.Length)
- {
- var cts = new CancellationTokenSource();
- Console.CancelKeyPress += (object? sender, ConsoleCancelEventArgs e) => cts.Cancel();
-
- await Examples[index].RunAsync(cts.Token);
- return 0;
- }
-
- Console.WriteLine("Hello, please choose a sample to run:");
- for (var i = 0; i < Examples.Length; i++)
- {
- Console.WriteLine($"{i}: {Examples[i].DisplayName}");
- }
- Console.WriteLine();
- return 1;
+ await Examples[index].RunAsync(cts.Token);
+ return 0;
}
+
+ Console.WriteLine("Hello, please choose a sample to run:");
+ for (var i = 0; i < Examples.Length; i++)
+ {
+ Console.WriteLine($"{i}: {Examples[i].DisplayName}");
+ }
+ Console.WriteLine();
+ return 1;
}
-}
+}
\ No newline at end of file
diff --git a/examples/Client/StateManagement/README.md b/examples/Client/StateManagement/README.md
index fb266a24..3344e43e 100644
--- a/examples/Client/StateManagement/README.md
+++ b/examples/Client/StateManagement/README.md
@@ -2,7 +2,7 @@
## Prerequisites
-- [.NET 6+](https://dotnet.microsoft.com/download) installed
+- [.NET 8+](https://dotnet.microsoft.com/download) installed
- [Dapr CLI](https://docs.dapr.io/getting-started/install-dapr-cli/)
- [Initialized Dapr environment](https://docs.dapr.io/getting-started/install-dapr-selfhost/)
- [Dapr .NET SDK](https://docs.dapr.io/developing-applications/sdks/dotnet/)
diff --git a/examples/Client/StateManagement/StateManagement.csproj b/examples/Client/StateManagement/StateManagement.csproj
index 7b165835..e292e4ae 100644
--- a/examples/Client/StateManagement/StateManagement.csproj
+++ b/examples/Client/StateManagement/StateManagement.csproj
@@ -2,7 +2,6 @@