<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marc Duiker</title>
    <description>The latest articles on DEV Community by Marc Duiker (@marcduiker).</description>
    <link>https://dev.to/marcduiker</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F220922%2Fb486eebe-5f4a-4d1d-8239-693aababb16a.png</url>
      <title>DEV Community: Marc Duiker</title>
      <link>https://dev.to/marcduiker</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marcduiker"/>
    <language>en</language>
    <item>
      <title>A free, open-source Dev Dashboard for local Dapr development</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Mon, 20 Jul 2026 15:25:25 +0000</pubDate>
      <link>https://dev.to/diagrid/a-free-open-source-dev-dashboard-for-local-dapr-development-11ip</link>
      <guid>https://dev.to/diagrid/a-free-open-source-dev-dashboard-for-local-dapr-development-11ip</guid>
      <description>&lt;p&gt;Developing Dapr applications means you're dealing with multiple apps and sidecars, looking at several terminals for log output and component files. There is now a free, open-source Dev Dashboard that brings it together in one live view. It runs as a single binary and auto-discovers apps started with dapr run, .NET Aspire, Docker Compose, or Testcontainers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F56mtaqemtqyxfe14x534.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F56mtaqemtqyxfe14x534.png" alt="Application overview" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  See everything Dapr at a glance
&lt;/h2&gt;

&lt;p&gt;The dashboard shows your running apps with health, ports, and process IDs, plus their loaded components, actor types, and pub/sub subscriptions. You can also tail sidecar and application logs in the same window, with level coloring and keyword highlighting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Debug workflows without guesswork
&lt;/h2&gt;

&lt;p&gt;For Dapr Workflows you can list executions across your apps, inspect event history and input/output per step, and terminate or purge instances. The data is read straight from your local state store, so you see the real state rather than a copy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffp4svcpzbevs2dp3dr04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffp4svcpzbevs2dp3dr04.png" alt="Workflow overview" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqrzbh8f2qz0r4ak2erpc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqrzbh8f2qz0r4ak2erpc.png" alt="Workflow detail" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build components and policies in a UI
&lt;/h2&gt;

&lt;p&gt;Two guided builders generate Dapr component and resiliency YAML from the full catalog, so you can skip hand-editing files.&lt;/p&gt;

&lt;h2&gt;
  
  
  Download &amp;amp; Install
&lt;/h2&gt;

&lt;p&gt;You can view the project on GitHub: &lt;a href="https://github.com/diagridio/dev-dashboard" rel="noopener noreferrer"&gt;https://github.com/diagridio/dev-dashboard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can install the dashboard directly via the terminal:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Install (macOS / Linux)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/diagridio/dev-dashboard/main/scripts/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Install (Windows, PowerShell)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;iwr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-useb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://raw.githubusercontent.com/diagridio/dev-dashboard/main/scripts/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Give it a try when you're developing and testing your Dapr applications. Once you have it running, come share how it works for you in the &lt;a href="https://diagrid.ws/dapr-discord" rel="noopener noreferrer"&gt;Dapr Discord&lt;/a&gt;. If you hit a bug or have an idea to make it better, open an issue on the &lt;a href="https://github.com/diagridio/dev-dashboard/issues" rel="noopener noreferrer"&gt;dev-dashboard repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>dapr</category>
    </item>
    <item>
      <title>Making Microsoft Agent Framework agents durable with Dapr Workflow</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Tue, 07 Jul 2026 15:48:50 +0000</pubDate>
      <link>https://dev.to/diagrid/making-microsoft-agent-framework-agents-durable-with-dapr-workflow-48j0</link>
      <guid>https://dev.to/diagrid/making-microsoft-agent-framework-agents-durable-with-dapr-workflow-48j0</guid>
      <description>&lt;p&gt;LLM calls are slow, costly, and non-deterministic, so a multi-agent app that crashes halfway through wastes time and money re-running everything. Dapr Workflow turns a set of MAF agents into a durable, fault-tolerant app that resumes from saved state and replays completed agent calls instead of hitting the LLM again.&lt;/p&gt;

&lt;p&gt;There's a new free Dapr University track uses &lt;code&gt;PrDigest&lt;/code&gt;, a .NET Aspire app that triages open Dapr PRs. You'll inspect the AppHost configuration, MAF agent registration, and the agent orchestration.&lt;/p&gt;

&lt;p&gt;Try the track &lt;a href="https://www.diagrid.io/university/ai-agents-maf?utm_source=dev-to&amp;amp;utm_medium=social&amp;amp;utm_campaign=agents" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dapr</category>
      <category>ai</category>
      <category>maf</category>
    </item>
    <item>
      <title>Keep your Dapr Agent's answers current with a Tavily web search tool</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Tue, 16 Jun 2026 13:46:15 +0000</pubDate>
      <link>https://dev.to/diagrid/keep-your-dapr-agents-answers-current-with-a-tavily-web-search-tool-30d0</link>
      <guid>https://dev.to/diagrid/keep-your-dapr-agents-answers-current-with-a-tavily-web-search-tool-30d0</guid>
      <description>&lt;p&gt;LLMs are frozen at training time, so they return confident answers that may already be out of date. &lt;a href="https://www.diagrid.io/university/dapr-agents-web-context?utm_source=dev-to&amp;amp;utm_medium=social&amp;amp;utm_campaign=agents" rel="noopener noreferrer"&gt;This free, self-paced Dapr University track&lt;/a&gt; shows you how to close that gap in Python by giving an agent access to the live web.&lt;/p&gt;

&lt;p&gt;You'll build an expert agent with Dapr Agents that calls a Tavily search tool to fetch current information, then reasons over those results through the provider-agnostic Dapr Conversation API. Combining tool calls with agent reasoning keeps answers grounded in today's data.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This university track requires an OpenAI API key and a free Tavily key.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Start the free &lt;a href="https://www.diagrid.io/university/dapr-agents-web-context?utm_source=dev-to&amp;amp;utm_medium=social&amp;amp;utm_campaign=agents" rel="noopener noreferrer"&gt;track here&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>dapr</category>
    </item>
    <item>
      <title>New Dapr University track for Dapr Workflows in .NET with Aspire</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Tue, 19 May 2026 08:46:28 +0000</pubDate>
      <link>https://dev.to/marcduiker/new-dapr-university-track-for-dapr-workflows-in-net-with-aspire-2cn7</link>
      <guid>https://dev.to/marcduiker/new-dapr-university-track-for-dapr-workflows-in-net-with-aspire-2cn7</guid>
      <description>&lt;p&gt;A free, self-paced track that walks through Dapr Workflow in a .NET Aspire solution. Runs in your browser and connects to a cloud-based sandbox, so there's nothing to install locally.&lt;/p&gt;

&lt;p&gt;The new learning track covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scaffolding an Aspire solution and adding the Dapr Workflow NuGet packages&lt;/li&gt;
&lt;li&gt;Fan-out / fan-in workflow with parallel activities and a conditional follow-up&lt;/li&gt;
&lt;li&gt;Dapr state store components for durable workflow state&lt;/li&gt;
&lt;li&gt;Triggering workflows via HTTP and inspecting them in the Diagrid Dev Dashboard&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start the track at &lt;a href="https://www.diagrid.io/dapr-university/dapr-workflows-dotnet-aspire?utm_source=dev-to&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;Dapr University&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>aspire</category>
      <category>microservices</category>
    </item>
    <item>
      <title>State of Dapr 2026 report is out</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Thu, 30 Apr 2026 09:18:52 +0000</pubDate>
      <link>https://dev.to/diagrid/state-of-dapr-2026-report-is-out-2f13</link>
      <guid>https://dev.to/diagrid/state-of-dapr-2026-report-is-out-2f13</guid>
      <description>&lt;p&gt;The 2026 State of Dapr report is out. Workflow API usage doubled year over year. 34% of developers are building AI agents on Dapr, 28% already in production. Durable workflows and reliable agents on one runtime.&lt;/p&gt;

&lt;p&gt;Download the report now to get all the insights: &lt;a href="https://www.diagrid.io/reports-and-ebooks/state-of-dapr-2026?utm_source=dev-to&amp;amp;utm_medium=social" rel="noopener noreferrer"&gt;https://www.diagrid.io/reports-and-ebooks/state-of-dapr-2026?utm_source=dev-to&amp;amp;utm_medium=social&lt;/a&gt;&lt;/p&gt;

</description>
      <category>microservices</category>
      <category>dapr</category>
      <category>opensource</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Webinar: Build Reliable Agentic Apps with Aspire, MAF, and Catalyst</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Tue, 28 Apr 2026 16:23:18 +0000</pubDate>
      <link>https://dev.to/diagrid/webinar-build-reliable-agentic-apps-with-aspire-maf-and-catalyst-5hn3</link>
      <guid>https://dev.to/diagrid/webinar-build-reliable-agentic-apps-with-aspire-maf-and-catalyst-5hn3</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;a href="https://www.diagrid.io/webinars/webinar-build-reliable-agentic-apps-aspire-maf-catalyst?utm_source=dev-to&amp;amp;utm_medium=social&amp;amp;utm_campaign=webinars" rel="noopener noreferrer"&gt;Register here&lt;/a&gt; for the webinar on May 7th.&lt;/p&gt;

&lt;p&gt;Join Marc Duiker and Whit Waldo for a live webinar on building reliable agentic applications in .NET.&lt;/p&gt;

&lt;p&gt;Agentic apps look impressive in a demo, but most struggle the moment a tool call fails or a long-running task needs to survive a restart. The Microsoft Agent Framework by itself does not solve this. In this session you will see how three tools work together to close that gap: Aspire for local orchestration and observability, the Microsoft Agent Framework for building agents, and Diagrid Catalyst for durable execution and state.&lt;/p&gt;

&lt;p&gt;If you are a .NET developer exploring agentic AI, this webinar will give you a clear picture of the moving parts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📅 May 7th&lt;/li&gt;
&lt;li&gt;🕑 8:00 AM PDT / 17:00 CEST&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://www.diagrid.io/webinars/webinar-build-reliable-agentic-apps-aspire-maf-catalyst?utm_source=dev-to&amp;amp;utm_medium=social&amp;amp;utm_campaign=webinars" rel="noopener noreferrer"&gt;&lt;strong&gt;Register here&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who should attend&lt;/strong&gt;&lt;br&gt;
This session is for .NET developers who are building or planning to build agentic applications and want to take them beyond the demo stage. No prior experience with Aspire, MAF, or Catalyst is required.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What you will learn&lt;/strong&gt;&lt;br&gt;
By the end of the session you will understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where reliability tends to break in agentic apps, including failed tool calls, timeouts, and long-running tasks that need to survive restarts&lt;/li&gt;
&lt;li&gt;How Aspire improves local development and observability for distributed .NET apps&lt;/li&gt;
&lt;li&gt;How the Microsoft Agent Framework helps you define and compose agents in .NET&lt;/li&gt;
&lt;li&gt;How Diagrid Catalyst adds durable execution so your agents keep running through crashes, retries, and deployments&lt;/li&gt;
&lt;li&gt;How the three fit together in a single project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Registration is free. Everyone who signs up will receive the recording after the event.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>dotnet</category>
      <category>microsoft</category>
    </item>
    <item>
      <title>Join the Diagrid Catalyst AWS Hackathon!</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Mon, 29 Apr 2024 08:13:50 +0000</pubDate>
      <link>https://dev.to/diagrid/join-the-diagrid-catalyst-aws-hackathon-4849</link>
      <guid>https://dev.to/diagrid/join-the-diagrid-catalyst-aws-hackathon-4849</guid>
      <description>&lt;p&gt;We are excited to invite you to the Diagrid Catalyst AWS Hackathon—a four-week, virtual event where you can unleash your creativity and showcase your coding skills by building or modernizing a cutting-edge application using the powerful Diagrid Catalyst platform. Get ready to collaborate, compete, and win cash prizes! &lt;a href="http://pages.diagrid.io/catalyst-hackathon"&gt;Register now&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Diagrid Catalyst?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.diagrid.io/catalyst"&gt;Diagrid Catalyst&lt;/a&gt; is a Developer API platform providing a brand-new approach to distributed application development. Using the Catalyst APIs, powered by the &lt;a href="https://dapr.io/"&gt;Dapr&lt;/a&gt; open source project, developers can overcome the complexity of rewriting common software patterns and achieve higher productivity by offloading infrastructure concerns from their code to Catalyst.&lt;/p&gt;

&lt;p&gt;Say hello to making API calls from any platform, in any language to build modern, cloud-applications with ease. This hackathon is your chance to explore the potential of Diagrid Catalyst while bringing your solution ideas to life! For more on Catalyst, watch our most recent &lt;a href="https://youtu.be/mLpIfX3hcwg?list=PLdl4NkEiMsJscq00RLRrN4ip_VpzvuwUC"&gt;webinar&lt;/a&gt; for a platform overview and API deep dive.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Participate?
&lt;/h2&gt;

&lt;p&gt;Join the Diagrid Catalyst Hackathon to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Innovate with an Emerging Product:&lt;/strong&gt; Explore the ways Diagrid Catalyst can expedite your development process by building an application to solve real-world challenges.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collaborate with Peers:&lt;/strong&gt; Connect with fellow developers, designers, and entrepreneurs. Collaborate, share ideas, and learn from each other's experiences.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhance Your Skills:&lt;/strong&gt; Sharpen your application development and architecture skills using the coding languages of your choice and deploying your solution on Amazon Web Services.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Win Prizes:&lt;/strong&gt; Compete for impressive cash prizes! We have rewards lined up for the most exceptional projects and for providing product feedback.
‍
All participation is evaluated based on the criteria in the Hackathon &lt;a href="https://22146261.fs1.hubspotusercontent-na1.net/hubfs/22146261/Catalyst%20Hackathon/Diagrid%20Catalyst%20AWS%20Hackathon%20Rules.docx.pdf"&gt;Rules, Terms &amp;amp; Conditions&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zUbCl5_OHOU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What to Build?
&lt;/h2&gt;

&lt;p&gt;Build or update an open-source microservice-based software solution utilizing at least two Diagrid Catalyst APIs. The solution should be composed of multiple application services and either be newly written or significantly enhanced to utilize Diagrid Catalyst. The solution should be architected using AWS infrastructure and hosting services. The solution must align with one of the areas below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Polyglot compute/ Cross-platform service discovery:&lt;/strong&gt; Application services are deployed to different AWS hosting platforms, which interact via the Catalyst APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stateful business process orchestration:&lt;/strong&gt; Application services are instrumented as part of a Dapr Workflow using the Dapr Workflow authoring SDK paired with the Catalyst Workflow API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless architecture:&lt;/strong&gt; Application services are optimized to run on AWS PaaS/SaaS services, which abstracts infrastructure concerns and enables high-scalability.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hackathon Timeline
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Registration Open:&lt;/strong&gt; April 19th 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project Submissions Open:&lt;/strong&gt; May 10th 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback Submissions Open:&lt;/strong&gt; May 24th 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Registration Closes:&lt;/strong&gt; May 17th 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Project Submissions Deadline:&lt;/strong&gt; June 7th 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback Submissions Deadline:&lt;/strong&gt; June 14th 2024&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Location:&lt;/strong&gt; Virtual Only&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Catalyst Reference Apps
&lt;/h2&gt;

&lt;p&gt;Looking for inspiration? See below for a couple of sample projects we’ve built using Diagrid Catalyst. More samples, including an AWS-specific reference, will be available to participants on the Hackathon site.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tetris Game
&lt;/h3&gt;

&lt;p&gt;The classic “blocks falling from the sky” game! The &lt;a href="https://github.com/diagrid-labs/catalyst-tetris"&gt;solution&lt;/a&gt; consists of two services:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Python Flask &lt;em&gt;user&lt;/em&gt; service which serves the JavaScript/HTML front-end for the user sign up and leaderboard and handles user state management and leaderboard updates.&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;game&lt;/em&gt; service written in Go, which serves the JavaScript/HTML frontend for the game itself and manages the game session lifecycle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These two services need to manage state and communicate to ensure games are started with the appropriate users, and user profiles are updated with the game results. The service interaction and data storage is all implemented using the APIs provided by Catalyst. Read the &lt;a href="https://www.diagrid.io/blog/build-multiplayer-tetris-in-the-browser-using-python-and-go"&gt;blog post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/VS036hE6cvg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Pizza Store Management System
&lt;/h3&gt;

&lt;p&gt;A distributed pizza store with Catalyst APIs. The solution comprises two .NET microservices, two serverless JavaScript functions and a Vue front-end. The applications depend on Diagrid Catalyst as the serverless API layer to connect to the underlying data and messaging infrastructure. Read the blog.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/SVEXCUUlqsk"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Participate?
&lt;/h2&gt;

&lt;p&gt;Participation is straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Register:&lt;/strong&gt; Submit a registration request form for the hackathon. Eligible participants will receive a direct invite to the Hackathon site, hosted on Devpost. Accept your invitation to Devpost and click the blue “Register” button on the Hackathon landing page to register.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create a project:&lt;/strong&gt; Create a project to frame out your hackathon solution ideas for others to see and potentially join in to help execute. You have a few options when it comes to projects:

&lt;ol&gt;
&lt;li&gt;Create a closed project to participate as an individual.&lt;/li&gt;
&lt;li&gt;Create an open project to enable other Hackathon participants to join you in your mission. You can even choose to invite people to participate in your project.&lt;/li&gt;
&lt;li&gt;Join an existing, open project if one is available and intrigues you.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learn:&lt;/strong&gt; Join our ongoing &lt;a href="https://pages.diagrid.io/diagrid-webinar-registration-catalyst"&gt;Catalyst webinar series&lt;/a&gt; or &lt;a href="https://www.youtube.com/playlist?list=PLdl4NkEiMsJscq00RLRrN4ip_VpzvuwUC"&gt;watch on-demand&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Build:&lt;/strong&gt; Develop your application using Diagrid Catalyst. Let your creativity shine, and don't forget to integrate innovative features.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submit:&lt;/strong&gt; Submit your project with the required deliverables by the deadline, June 7&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For more information on resource access, project requirements and judging criteria, view the Hackathon &lt;a href="https://22146261.fs1.hubspotusercontent-na1.net/hubfs/22146261/Catalyst%20Hackathon/Diagrid%20Catalyst%20AWS%20Hackathon%20Rules.docx.pdf"&gt;Rules, Terms &amp;amp; Conditions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prizes
&lt;/h2&gt;

&lt;p&gt;We have exciting cash prizes up for grabs! Prizes range from a Grand Prize of $2000 to Runner-up Prizes of $1000 each and Bonus Prizes from $250-$500! Get swag for participating &amp;amp; provide valuable product feedback for the chance to win another $100.&lt;/p&gt;

&lt;p&gt;If you participate in the hackathon, you are also eligible for a $100 referral bonus for spreading the word! Share the Hackathon details with your friends and encourage them to sign up. The participant with the most referrals wins!&lt;/p&gt;

&lt;h2&gt;
  
  
  Get Ready to Hack
&lt;/h2&gt;

&lt;p&gt;Don’t miss this unique opportunity to explore Diagrid Catalyst, build innovative apps, and compete for cash prizes. Whether you're a seasoned developer or a curious beginner, the Diagrid Catalyst Hackathon is your time to shine.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://pages.diagrid.io/catalyst-hackathon"&gt;Sign up&lt;/a&gt; to participate today.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>programming</category>
      <category>hackathon</category>
    </item>
    <item>
      <title>Building a distributed pizza store in .NET with serverless Dapr APIs</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Thu, 01 Feb 2024 10:57:11 +0000</pubDate>
      <link>https://dev.to/diagrid/building-a-distributed-pizza-store-in-net-with-serverless-dapr-apis-j1j</link>
      <guid>https://dev.to/diagrid/building-a-distributed-pizza-store-in-net-with-serverless-dapr-apis-j1j</guid>
      <description>&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;When developers build distributed systems, they need to think about cross-cutting concerns such as security, observability, and resiliency. Developers also write a lot of glue code to orchestrate services, create long-running and durable workflows, and connect to external resources, such as message brokers and state stores. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dapr.io/" rel="noopener noreferrer"&gt;Dapr&lt;/a&gt;, the Distributed Application Runtime, is ideal for building distributed systems since it has built-in support for cross-cutting concerns, and it offers a suite of APIs for communication, state and workflow, that make developers more efficient.  According to the &lt;a href="https://www.diagrid.io/blog/the-state-of-dapr-2023-report" rel="noopener noreferrer"&gt;State of Dapr Report&lt;/a&gt;, 95% of Dapr developers claim that Dapr saves time, and 55% of the developers surveyed claimed it saved them more than 30% of development time.&lt;/p&gt;

&lt;p&gt;The usage of Dapr is also increasing thanks to a growing number of platforms that support the Dapr APIs. Dapr is no longer limited to running as a sidecar in Kubernetes, as is described in &lt;a href="https://www.diagrid.io/blog/dapr-deployment-models" rel="noopener noreferrer"&gt;Dapr Deployment Models&lt;/a&gt;. In this article, &lt;a href="https://www.diagrid.io/catalyst" rel="noopener noreferrer"&gt;Diagrid Catalyst&lt;/a&gt;, a suite of serverless Dapr APIs, is used to orchestrate services with &lt;a href="https://docs.dapr.io/developing-applications/building-blocks/workflow/workflow-overview/" rel="noopener noreferrer"&gt;Dapr workflow&lt;/a&gt;, and interact with message brokers and key-value stores.&lt;/p&gt;

&lt;p&gt;Throughout this article, you’ll be using the following to configure a distributed system:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two Dapr services (.NET)&lt;/li&gt;
&lt;li&gt;Two serverless functions (JavaScript)&lt;/li&gt;
&lt;li&gt;A front-end (Vue)&lt;/li&gt;
&lt;li&gt;A key value state store&lt;/li&gt;
&lt;li&gt;A pub/sub message broker&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.diagrid.io/catalyst" rel="noopener noreferrer"&gt;Diagrid Catalyst&lt;/a&gt; as the serverless API layer to connect everything&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;TLDR:&lt;/strong&gt; Check the code on &lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and join the &lt;a href="https://pages.diagrid.io/catalyst-early-access-waitlist" rel="noopener noreferrer"&gt;Catalyst early access program&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagrid Pizza Store
&lt;/h2&gt;

&lt;p&gt;The demo that is used in this article revolves around an online pizza store, where the user selects pizzas, orders them, and follows the progress of the order in realtime. It’s a simplified example where the durable workflow focuses on the inventory of ingredients, and communicating with the kitchen. The source code is &lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7abjviwgbse7hnhc36g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm7abjviwgbse7hnhc36g.gif" alt="Pizza store front-end" width="1200" height="1019"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;

&lt;p&gt;The solution includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Two&amp;nbsp;&lt;a href="http://dapr.io/" rel="noopener noreferrer"&gt;Dapr&lt;/a&gt;&amp;nbsp;web services written in .NET,&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt;&amp;nbsp;and&amp;nbsp;&lt;em&gt;KitchenService&lt;/em&gt;. In this demo, they’re running locally, but these can be hosted in any cloud that supports ASP.NET services.&lt;/li&gt;
&lt;li&gt;The website (based on Vue) and two serverless functions written in JavaScript, &lt;em&gt;getAblyToken&lt;/em&gt; and &lt;em&gt;placeOrder&lt;/em&gt;. These are hosted on &lt;a href="https://vercel.com/" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ably.com/" rel="noopener noreferrer"&gt;Ably&lt;/a&gt; as the realtime communication component between the&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt;&amp;nbsp;and the website.&lt;/li&gt;
&lt;li&gt;A key/value store to manage inventory (managed by Diagrid).&lt;/li&gt;
&lt;li&gt;A pub/sub message broker to communicate between the&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt;&amp;nbsp;and the&amp;nbsp;&lt;em&gt;KitchenService&lt;/em&gt;&amp;nbsp;(managed by Diagrid).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.diagrid.io/catalyst" rel="noopener noreferrer"&gt;Diagrid Catalyst&lt;/a&gt; that offers serverless APIs for communication, state, and workflow powered by Dapr.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1ornquwh30esbeu2k8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1ornquwh30esbeu2k8d.png" alt="Pizza store architecture" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Workflow
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;PizzaOrderService&lt;/em&gt; contains a Dapr workflow that orchestrates the activities for checking the inventory and communicating with the &lt;em&gt;KitchenService.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1gdgcp6n4hiq9plzxrm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1gdgcp6n4hiq9plzxrm.png" alt="Pizza store workflow" width="800" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The workflow also contains activities for sending realtime messages to the website, these have been omitted from the workflow diagram to keep it concise.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the Pizza Store locally
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;The following services, tools, and frameworks are required for this demo:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.diagrid.io/catalyst" rel="noopener noreferrer"&gt;Diagrid Catalyst account&lt;/a&gt;&amp;nbsp;(&lt;a href="https://pages.diagrid.io/catalyst-early-access-waitlist" rel="noopener noreferrer"&gt;sign up&lt;/a&gt; for early access) and the&amp;nbsp;&lt;a href="https://docs.diagrid.io/catalyst/references/cli-reference/intro" rel="noopener noreferrer"&gt;Diagrid CLI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vercel.com/signup" rel="noopener noreferrer"&gt;Vercel account (hobby)&lt;/a&gt;&amp;nbsp;and the&amp;nbsp;&lt;a href="https://vercel.com/docs/cli" rel="noopener noreferrer"&gt;Vercel CLI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ably.com/signup" rel="noopener noreferrer"&gt;Ably account (free)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet/8.0" rel="noopener noreferrer"&gt;.NET 8 SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodejs.org/en/download/" rel="noopener noreferrer"&gt;Node 18&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All the code for the website, serverless functions, and back-end services is available in the &lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo" rel="noopener noreferrer"&gt;catalyst-pizza-demo&lt;/a&gt; GitHub repository.  This repository contains a devcontainer configuration that has the following preinstalled: .NET 8, Node LTS, Vercel CLI, Diagrid CLI. &lt;/p&gt;

&lt;p&gt;You can use this devcontainer&amp;nbsp;&lt;a href="https://code.visualstudio.com/docs/devcontainers/containers" rel="noopener noreferrer"&gt;locally in VSCode&lt;/a&gt;&amp;nbsp;(requires&amp;nbsp;&lt;a href="https://www.docker.com/products/docker-desktop/" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt;) or directly in&amp;nbsp;&lt;a href="https://github.com/features/codespaces" rel="noopener noreferrer"&gt;GitHub Codespaces&lt;/a&gt;. The&amp;nbsp;&lt;em&gt;npm install&lt;/em&gt;&amp;nbsp;and&amp;nbsp;&lt;em&gt;dotnet build&lt;/em&gt;&amp;nbsp;commands described in this article can be skipped if the devcontainer is used.&lt;/p&gt;

&lt;h3&gt;
  
  
  GitHub
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo/fork" rel="noopener noreferrer"&gt;Fork&lt;/a&gt;&amp;nbsp;the &lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo" rel="noopener noreferrer"&gt;catalyst-pizza-demo&lt;/a&gt; and clone it locally, or use GitHub Codespaces (recommended).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Ably
&lt;/h3&gt;

&lt;p&gt;Ably is used as the serverless realtime messaging component. There is a default Ably app when you sign up for an account that can be used for this demo. Alternatively, you can create a new Ably app.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log into the&amp;nbsp;&lt;a href="https://ably.com/accounts/" rel="noopener noreferrer"&gt;Ably portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using the Ably portal: copy the&amp;nbsp;&lt;a href="https://ably.com/docs/ids-and-keys#api-key" rel="noopener noreferrer"&gt;Root API key&lt;/a&gt;&amp;nbsp;from the Ably app. This will be copied later as an environment variable for both Vercel and Diagrid.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Vercel
&lt;/h3&gt;

&lt;p&gt;The Vue-based&amp;nbsp;&lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo/tree/main/front-end/src" rel="noopener noreferrer"&gt;front-end&lt;/a&gt;&amp;nbsp;and two&amp;nbsp;&lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo/tree/main/front-end/api" rel="noopener noreferrer"&gt;JavaScript functions&lt;/a&gt;&amp;nbsp;are hosted on Vercel. The &lt;a href="https://vercel.com/docs/cli" rel="noopener noreferrer"&gt;Vercel CLI&lt;/a&gt; is used to configure and run these resources locally.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open a terminal in the root of the repository and login with the Vercel CLI:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vercel login
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to the&amp;nbsp;&lt;em&gt;front-end&lt;/em&gt;&amp;nbsp;folder and run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go back to the root of the repository and set up the Vercel project by running:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vercel
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Follow the CLI prompts, and select the following options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup and deploy:&amp;nbsp;&lt;code&gt;Y&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Scope:&amp;nbsp;&lt;code&gt;&amp;lt;account name&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Link to existing project:&amp;nbsp;&lt;code&gt;N&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;What's your project's name?&amp;nbsp;&lt;code&gt;catalyst-pizza-project&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;In which directory is your code located?&amp;nbsp;&lt;code&gt;./front-end&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Want to modify these settings? [y/N]&amp;nbsp;&lt;code&gt;n&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Wait for the deployment to complete.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An environment variable is used in the&amp;nbsp;&lt;em&gt;getAblyToken&lt;/em&gt;&amp;nbsp;function to generate a token for the website to communicate with the Ably realtime service. Add the&amp;nbsp;&lt;em&gt;Ably API token&lt;/em&gt;&amp;nbsp;variable by running&amp;nbsp;&lt;code&gt;vercel env add&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variable name:&amp;nbsp;&lt;code&gt;ABLY_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Variable value:&amp;nbsp;&lt;em&gt;Use the Ably API key obtained from the Ably portal earlier&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Select&amp;nbsp;&lt;code&gt;Development&lt;/code&gt;&amp;nbsp;as the environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Another environment variable is used in the&amp;nbsp;&lt;em&gt;placeOrder&lt;/em&gt;&amp;nbsp;function to send a request to the&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt; that will start the workflow. Add the&amp;nbsp;&lt;em&gt;WORKFLOW_URL&lt;/em&gt;&amp;nbsp;variable by running&amp;nbsp;&lt;code&gt;vercel env add&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Variable name:&amp;nbsp;&lt;code&gt;WORKFLOW_URL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Variable value:&amp;nbsp;&lt;code&gt;http://localhost:5064/workflow/orderReceived&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Select&amp;nbsp;&lt;code&gt;Development&lt;/code&gt;&amp;nbsp;as the environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run&amp;nbsp;&lt;code&gt;vercel pull&lt;/code&gt;&amp;nbsp;to pull the configuration from Vercel to your local environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run&amp;nbsp;&lt;code&gt;vercel build&lt;/code&gt;&amp;nbsp;to build the website and the serverless functions to ensure there are no errors.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Diagrid &lt;strong&gt;Catalyst&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Diagrid Catalyst provides serverless Dapr APIs that enables developers to quickly build distributed applications with workflow, pub/sub messaging, service invocation, and state management capabilities. Diagrid also provides managed infrastructure for storing data in a key/value store, pub/sub messaging, and workflow, which are all used in this solution.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.diagrid.io/catalyst/references/cli-reference/intro" rel="noopener noreferrer"&gt;Diagrid CLI&lt;/a&gt; is used to configure the resources and run the .NET services locally.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open another terminal in the root of the repository and use the Diagrid CLI to log in to Diagrid:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid login
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new Catalyst project named&amp;nbsp;&lt;em&gt;catalyst-pizza-project&lt;/em&gt;&amp;nbsp;and use the Diagrid managed pub/sub broker &amp;amp; KV store, and enable the managed workflow API:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid project create catalyst-pizza-project &lt;span class="nt"&gt;--deploy-managed-pubsub&lt;/span&gt; &lt;span class="nt"&gt;--deploy-managed-kv&lt;/span&gt; &lt;span class="nt"&gt;--enable-managed-workflow&lt;/span&gt; &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To set this project as the default in the CLI run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid project use catalyst-pizza-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new App ID for the&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid appid create pizzaorderservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new App ID for the&amp;nbsp;&lt;em&gt;KitchenService&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid appid create kitchenservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Before continuing, check the App ID status to make sure they are ready:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid appid list
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a pub/sub subscription for the&amp;nbsp;&lt;em&gt;KitchenService&lt;/em&gt;&amp;nbsp;to receive messages from the&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid subscription create pizzaorderssub &lt;span class="nt"&gt;--connection&lt;/span&gt; pubsub &lt;span class="nt"&gt;--topic&lt;/span&gt; pizza-orders &lt;span class="nt"&gt;--route&lt;/span&gt; /prepare &lt;span class="nt"&gt;--scopes&lt;/span&gt; kitchenservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a pub/sub subscription for the&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt;&amp;nbsp;to receive messages from the&amp;nbsp;&lt;em&gt;KitchenService&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid subscription create preparedorderssub &lt;span class="nt"&gt;--connection&lt;/span&gt; pubsub &lt;span class="nt"&gt;--topic&lt;/span&gt; prepared-orders &lt;span class="nt"&gt;--route&lt;/span&gt; /workflow/orderPrepared &lt;span class="nt"&gt;--scopes&lt;/span&gt; pizzaorderservice
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that creation of the subscriptions is completed:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid subscription list
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run&amp;nbsp;&lt;code&gt;diagrid dev scaffold&lt;/code&gt;&amp;nbsp;to create a new local dev environment file. This creates a yaml file, named&amp;nbsp;&lt;em&gt;dev-.yaml&lt;/em&gt;&amp;nbsp;with the following content:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;project&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;catalyst-pizza-project&lt;/span&gt;
&lt;span class="na"&gt;apps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kitchenservice&lt;/span&gt;
&lt;span class="na"&gt;appPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_API_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;diagrid://&amp;lt;dapr_api_token&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_APP_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kitchenservice&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_GRPC_ENDPOINT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://&amp;lt;grpc_endpoint&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_HTTP_ENDPOINT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://&amp;lt;http_endpoint&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;workDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kitchenservice&lt;/span&gt;
&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;appId&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pizzaorderservice&lt;/span&gt;
&lt;span class="na"&gt;appPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_API_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;diagrid://&amp;lt;dapr_api_token&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_APP_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pizzaorderservice&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_GRPC_ENDPOINT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://&amp;lt;grpc_endpoint&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;DAPR_HTTP_ENDPOINT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://&amp;lt;http_endpoint&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;workDir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pizzaorderservice&lt;/span&gt;
&lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;span class="na"&gt;appLogDestination&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This file is gitignored since it contains secrets from Diagrid Catalyst. The &lt;em&gt;appPort&lt;/em&gt;, &lt;em&gt;command&lt;/em&gt;, and &lt;em&gt;workDir&lt;/em&gt; attributes still need to be updated as follows: &lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Update the&amp;nbsp;&lt;em&gt;appPort&lt;/em&gt;&amp;nbsp;for the&amp;nbsp;&lt;em&gt;kitchenservice&lt;/em&gt;&amp;nbsp;to&amp;nbsp;&lt;code&gt;5066&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Update the&amp;nbsp;&lt;em&gt;appPort&lt;/em&gt;&amp;nbsp;for the&amp;nbsp;&lt;em&gt;pizzaorderservice&lt;/em&gt;&amp;nbsp;to&amp;nbsp;&lt;code&gt;5064&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Update the&amp;nbsp;&lt;em&gt;command&lt;/em&gt;&amp;nbsp;arguments to&amp;nbsp;&lt;code&gt;["dotnet", "run"]&lt;/code&gt;&amp;nbsp;for both apps.&lt;/li&gt;
&lt;li&gt;Update the&amp;nbsp;&lt;em&gt;workDir&lt;/em&gt;&amp;nbsp;argument to point to&amp;nbsp;&lt;code&gt;back-end/KitchenService&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;back-end/PizzaOrderService&lt;/code&gt;&amp;nbsp;respectively.&lt;/li&gt;
&lt;li&gt;Update the&amp;nbsp;&lt;em&gt;appLogDestination&lt;/em&gt;&amp;nbsp;to&amp;nbsp;&lt;code&gt;console&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add an&amp;nbsp;&lt;code&gt;ABLY_API_KEY&lt;/code&gt;&amp;nbsp;environment variable for the&amp;nbsp;&lt;em&gt;pizzaorderservice&lt;/em&gt;&amp;nbsp;appId and set the value to the Ably API key obtained from the Ably portal.&lt;/li&gt;
&lt;li&gt;Save the changes to the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Update the key/value store to allow shared state&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The two .NET services share the same state in the key/value store to manage inventory and orders. Since this is not the default usage of state stores and services when using Dapr, an attribute needs to be set to enable this. The default behavior is that a key is prefixed with the app ID of the service that is using it. In this case, however, the&amp;nbsp;&lt;em&gt;keyPrefix&lt;/em&gt;&amp;nbsp;is set to&amp;nbsp;&lt;em&gt;name&lt;/em&gt;&amp;nbsp;to make sure both services use the same keys.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Run the following command to update the managed key/value store:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;diagrid connection apply &lt;span class="nt"&gt;-f&lt;/span&gt; ./infra/kv.yml
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This will upload the&amp;nbsp;&lt;em&gt;kv.yml&lt;/em&gt;&amp;nbsp;file to Diagrid and update the configuration of the&amp;nbsp;&lt;em&gt;kvstore&lt;/em&gt;&amp;nbsp;connection so&amp;nbsp;&lt;em&gt;keyPrefix&lt;/em&gt;&amp;nbsp;is set to&amp;nbsp;&lt;em&gt;name&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Inspect the DaprClient configuration
&lt;/h3&gt;

&lt;p&gt;The two .NET services use the Dapr .NET client SDK for workflow, state management and pub/sub messaging. The&amp;nbsp;&lt;em&gt;DaprClient&lt;/em&gt;&amp;nbsp;is configured to use the endpoints provided by Diagrid Catalyst in the&amp;nbsp;&lt;em&gt;&lt;a href="https://github.com/diagrid-labs/catalyst-pizza-demo/blob/main/back-end/PizzaOrderService/Program.cs" rel="noopener noreferrer"&gt;Program.cs&lt;/a&gt;&lt;/em&gt;&amp;nbsp;file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DAPR_API_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;grpcEndpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DAPR_GRPC_ENDPOINT"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;httpEndpoint&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DAPR_HTTP_ENDPOINT"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddDaprClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseDaprApiToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseGrpcEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcEndpoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHttpEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpEndpoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use service invocation with the HTTP API, the&amp;nbsp;&lt;em&gt;HttpClient&lt;/em&gt;&amp;nbsp;is configured with the&amp;nbsp;&lt;em&gt;DAPR_APP_ID&lt;/em&gt;&amp;nbsp;and&amp;nbsp;&lt;em&gt;DAPR_API_TOKEN&lt;/em&gt;&amp;nbsp;environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;appId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DAPR_APP_ID"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;apiToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DAPR_API_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddHttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"daprEndpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BaseAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;httpEndpoint&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultRequestHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MediaTypeWithQualityHeaderValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultRequestHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dapr-app-id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DefaultRequestHeaders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dapr-api-token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;apiToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Running &amp;amp; testing the solution
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal in the root of the repository.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To restore and build the .NET projects run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet build ./back-end/PizzaOrderService
dotnet build ./back-end/KitchenService
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Run&amp;nbsp;&lt;code&gt;diagrid dev start&lt;/code&gt;&amp;nbsp;to start the&amp;nbsp;&lt;em&gt;PizzaOrderService&lt;/em&gt;&amp;nbsp;and the&amp;nbsp;&lt;em&gt;KitchenService&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using another terminal in the root of the repository, run&amp;nbsp;&lt;code&gt;vercel dev&lt;/code&gt;&amp;nbsp;to start the website and the serverless functions locally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Navigate to the URL provided by the Vercel CLI to view the website.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Select some pizzas, place an order, and watch the progress of the workflow in realtime.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Using the Catalyst API explorer&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can use the API explorer in the Catalyst web UI to interact with the APIs. If you want to retrieve the order item from the key/value store that has just been processed, follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the developer tools console of the browser that is running the demo (a pizza order must be started or completed).&lt;/li&gt;
&lt;li&gt;The order is logged to the console as a JSON object. Copy the&amp;nbsp;&lt;em&gt;OrderId&lt;/em&gt;&amp;nbsp;property value.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F82q8tifruveh69ym3ek1.png" alt="Console order" width="800" height="199"&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to the&amp;nbsp;&lt;a href="https://catalyst.diagrid.io/" rel="noopener noreferrer"&gt;Catalyst web UI&lt;/a&gt;. Ensure you're in the&amp;nbsp;&lt;em&gt;catalyst-pizza-project&lt;/em&gt;&amp;nbsp;project.
&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg58vyhxqrhxj63rntjp0.png" alt="Catalyst API explorer" width="800" height="557"&gt;
&lt;/li&gt;
&lt;li&gt;Select&amp;nbsp;&lt;em&gt;App IDs&lt;/em&gt;&amp;nbsp;in and click on the&amp;nbsp;&lt;em&gt;&lt;a href="https://catalyst.diagrid.io/app-ids/api-explorer/state-api/" rel="noopener noreferrer"&gt;API explorer&lt;/a&gt;&lt;/em&gt;&amp;nbsp;tab.

&lt;ul&gt;
&lt;li&gt;Select the&amp;nbsp;&lt;em&gt;State API&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Select the&amp;nbsp;&lt;em&gt;pizzaorderservice&lt;/em&gt;&amp;nbsp;as the app ID.&lt;/li&gt;
&lt;li&gt;Select&amp;nbsp;&lt;em&gt;GET&lt;/em&gt;&amp;nbsp;as the API operation.&lt;/li&gt;
&lt;li&gt;Select&amp;nbsp;&lt;em&gt;kvstore&lt;/em&gt;&amp;nbsp;as the state connection.&lt;/li&gt;
&lt;li&gt;Enter&amp;nbsp;&lt;em&gt;Order-&lt;/em&gt;&amp;nbsp;as the key, where &lt;em&gt;&lt;/em&gt;&amp;nbsp;is substituted with the value copied from the developer tools console.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click&amp;nbsp;&lt;em&gt;Send&lt;/em&gt;. The response should show the state of the order item.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;Congratulations! You’ve now used the Diagrid Catalyst serverless Dapr APIs for workflow, pub/sub messaging, service invocation, and state management. The ability to use these APIs from anywhere, without the overhead of managing Kubernetes clusters, brings great flexibility to developers on any platform to build distributed applications. The Dapr applications used in this demo can be hosted on any cloud. The demo uses the Diagrid managed infrastructure for key/value storage and pub/sub messaging, but these can be swapped out for other cloud-based resources, similarly to switching open-source Dapr components. You can extend this demo with an alternative pub/sub broker or state store by configuring other &lt;a href="https://docs.diagrid.io/catalyst/concepts/connections" rel="noopener noreferrer"&gt;infrastructure connections&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Any questions or comments about this demo? Join the&amp;nbsp;&lt;a href="https://bit.ly/dapr-discord" rel="noopener noreferrer"&gt;Dapr Discord&lt;/a&gt; and drop us a message in the #diagrid channel!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>dapr</category>
      <category>tutorial</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Dapr v1.11 Release Highlights</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Mon, 19 Jun 2023 12:27:24 +0000</pubDate>
      <link>https://dev.to/diagrid/dapr-v111-release-highlights-46b</link>
      <guid>https://dev.to/diagrid/dapr-v111-release-highlights-46b</guid>
      <description>&lt;p&gt;The Dapr maintainers released a new version of&amp;nbsp;&lt;strong&gt;&lt;a href="https://dapr.io/"&gt;Dapr, the distributed application runtime&lt;/a&gt;&lt;/strong&gt;, last week. This post highlights the major new features and changes for the APIs and components in release 1.11.&lt;/p&gt;

&lt;h2&gt;
  
  
  APIs
&lt;/h2&gt;

&lt;p&gt;Dapr provides a common set of APIs for building microservices quickly and reliably. The new building block APIs, and major upgrades to existing APIs, are described in this section.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration API stable
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VdpW4zpr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy7r8v52ctan8ncjfopp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VdpW4zpr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dy7r8v52ctan8ncjfopp.png" alt="Dapr Configuration API" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.dapr.io/developing-applications/building-blocks/configuration/configuration-api-overview/"&gt;Configuration building block&lt;/a&gt; allows developers to easily consume application configuration values as key/value pairs. Use this API to retrieve values that are likely to change over time but are coupled to the service. For instance, this API can be used to get App IDs, which are used when invoking other Dapr services. Or to get a component name of a state store when using the State Management API.&lt;/p&gt;

&lt;p&gt;Applications can subscribe to changes of these configuration values, so the apps always use the latest value. The Configuration API was introduced in Dapr v1.5, and it’s great to see it now stable in v1.11.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get a configuration value&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;GET http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0/configuration/&lt;span class="nt"&gt;&amp;lt;storeName&amp;gt;&lt;/span&gt;?key=&lt;span class="nt"&gt;&amp;lt;keyName&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Subscribe to configuration changes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;GET http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0/configuration/&lt;span class="nt"&gt;&amp;lt;storeName&amp;gt;&lt;/span&gt;/subscribe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Service Invocation for non-Dapr endpoints 🆕
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SdrKIgp7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odkcnl3ywq1xawm8k1gb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SdrKIgp7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/odkcnl3ywq1xawm8k1gb.png" alt="Non-Dapr service invocation" width="800" height="240"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An exciting new preview feature is the ability to invoke &lt;a href="https://docs.dapr.io/developing-applications/building-blocks/service-invocation/howto-invoke-non-dapr-endpoints/"&gt;non-Dapr endpoints&lt;/a&gt;. This feature enables developers to apply resiliency policies, access control via scoping, header authentication, and middleware to any endpoint. This gives you nearly all the benefits of service invocation when calling any HTTP API. Invoking non-Dapr endpoints can also be very useful when working on existing code bases where Dapr can be introduced incrementally.&lt;/p&gt;

&lt;p&gt;Non-Dapr endpoints can be invoked in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Using an &lt;code&gt;HTTPEndpoint&lt;/code&gt; resource type.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;GET http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0/invoke/&lt;span class="nt"&gt;&amp;lt;HTTPEndpoint-name&amp;gt;&lt;/span&gt;/method/&lt;span class="nt"&gt;&amp;lt;my-method&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;a href="https://docs.dapr.io/reference/resource-specs/httpendpoints-reference/"&gt;HTTPEndpoint resource&lt;/a&gt; is specified in a yaml file:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dapr.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HTTPEndpoint&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;NAME&amp;gt;&lt;/span&gt;  
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1alpha1&lt;/span&gt;
  &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-BASEURL&amp;gt;&lt;/span&gt; &lt;span class="c1"&gt;# Required. Use "http://" or "https://" prefix.&lt;/span&gt;
  &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Optional&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-A-HEADER-NAME&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-A-HEADER-VALUE&amp;gt;&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-A-HEADER-NAME&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-SECRET-NAME&amp;gt;&lt;/span&gt;
      &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-SECRET-KEY&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;scopes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Optional&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-SCOPED-APPIDS&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;auth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;# Optional&lt;/span&gt;
  &lt;span class="na"&gt;secretStore&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;REPLACE-WITH-SECRETSTORE&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using the Fully Qualified Domain Name (FQDN) of the endpoint.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;GET http://localhost:&amp;lt;daprPort&amp;gt;/v1.0/invoke/&amp;lt;FQDN_URL&amp;gt;/method/&amp;lt;my-method&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Workflow updates
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s5E7Kd7v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o95i0pkp765rbwkuoere.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s5E7Kd7v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o95i0pkp765rbwkuoere.png" alt="Dapr Workflow management API" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Dapr Workflow management API has been updated to allow workflows to be paused, resumed, and purged. Purging workflows means the workflow state will be deleted. Once a workflow has been completed, it’s a good practice to purge the workflow state to keep the storage requirements to a minimum.  In addition, workflows can now wait for external events. This is particularly useful for business processes that involve human interaction, such as approval workflows, or waiting for callbacks from other long-running processes. &lt;/p&gt;

&lt;p&gt;These are the current Workflow management HTTP API methods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;POST http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0-alpha1/workflows/dapr/&lt;span class="nt"&gt;&amp;lt;instanceID&amp;gt;&lt;/span&gt;/start
POST http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0-alpha1/workflows/dapr/&lt;span class="nt"&gt;&amp;lt;instanceID&amp;gt;&lt;/span&gt;/terminate
POST http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0-alpha1/workflows/dapr/&lt;span class="nt"&gt;&amp;lt;instanceID&amp;gt;&lt;/span&gt;/pause
POST http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0-alpha1/workflows/dapr/&lt;span class="nt"&gt;&amp;lt;instanceID&amp;gt;&lt;/span&gt;/resume
POST http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0-alpha1/workflows/dapr/&lt;span class="nt"&gt;&amp;lt;instanceID&amp;gt;&lt;/span&gt;/purge
POST http://localhost:&lt;span class="nt"&gt;&amp;lt;daprPort&amp;gt;&lt;/span&gt;/v1.0-alpha1/workflows/dapr/&lt;span class="nt"&gt;&amp;lt;instanceID&amp;gt;&lt;/span&gt;/raiseEvent/&lt;span class="nt"&gt;&amp;lt;eventName&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the Workflow management API, which is still in preview, has breaking changes compared to v1.10. The changes are outlined in this &lt;a href="https://github.com/dapr/dapr/pull/6218"&gt;GitHub issue&lt;/a&gt;. Another breaking change is the ability to support multiple workflow apps in a single cluster, as mentioned in this &lt;a href="https://github.com/dapr/dapr/issues/6013"&gt;GitHub issue&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Dapr Python SDK has been upgraded to allow &lt;a href="https://docs.dapr.io/developing-applications/sdks/python/python-workflow/"&gt;authoring of workflows&lt;/a&gt;, so now workflow applications can be written in either C# or Python.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cryptography API 🆕
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gHNzyqDz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/344mt6chof11exh2qu80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gHNzyqDz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/344mt6chof11exh2qu80.png" alt="Dapr cryptography API" width="800" height="318"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.dapr.io/developing-applications/building-blocks/cryptography/cryptography-overview/"&gt;Cryptography API&lt;/a&gt; is a new preview building block that enables developers to encrypt/decrypt data in a safe and consistent way. Cryptography can be used within key vaults or the Dapr sidecar without exposing cryptographic keys to the application. With this new API, a set of new Cryptography components is made available that is listed in the &lt;em&gt;New Components&lt;/em&gt; section.&lt;/p&gt;

&lt;p&gt;These examples show how data can be encrypted and decrypted with the Cryptography API using the Dapr JavaScript SDK:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Encryption&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// When passing data (a buffer or string), `encrypt` returns a Buffer with the encrypted message&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ciphertext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;encrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plaintext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Name of the Dapr component (required)&lt;/span&gt;
    &lt;span class="na"&gt;componentName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mycryptocomponent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Name of the key stored in the component (required)&lt;/span&gt;
    &lt;span class="na"&gt;keyName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mykey&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;// Algorithm used for wrapping the key, which must be supported by the key named above.&lt;/span&gt;
    &lt;span class="c1"&gt;// Options include: "RSA", "AES"&lt;/span&gt;
    &lt;span class="na"&gt;keyWrapAlgorithm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;RSA&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Decryption&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// When passing data as a buffer, `decrypt` returns a Buffer with the decrypted message&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;plaintext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;decrypt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ciphertext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Only required option is the component name&lt;/span&gt;
    &lt;span class="na"&gt;componentName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mycryptocomponent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For more info on how to use the Cryptography API, see the &lt;a href="https://docs.dapr.io/developing-applications/building-blocks/cryptography/howto-cryptography/"&gt;Dapr docs&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;Dapr decouples the functionality of the common set of APIs with their underlying implementations via &lt;a href="https://docs.dapr.io/concepts/components-concept/"&gt;components&lt;/a&gt;. Components of the same type are interchangeable since they implement the same interface. Release 1.11 contains both new components as improvements to existing components.&lt;/p&gt;

&lt;h3&gt;
  
  
  New components
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Bindings&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-bindings/wasm/"&gt;WASM&lt;/a&gt;: allows invoking applications compiled to &lt;a href="https://developer.mozilla.org/en-US/docs/WebAssembly"&gt;WebAssembly&lt;/a&gt; and run in modern browsers.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-bindings/kitex/"&gt;Kitex&lt;/a&gt;: allows invoking Generic Calls in &lt;a href="https://www.cloudwego.io/docs/kitex/overview/"&gt;Kitex&lt;/a&gt;, a high-performance and strong-extensibility Golang RPC framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;State Stores&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-etcd/"&gt;etcd&lt;/a&gt;: enables state store functionality using &lt;a href="https://etcd.io/"&gt;etcd&lt;/a&gt;, a distributed, reliable key-value store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cryptography&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-cryptography/azure-key-vault/"&gt;Azure Key Vault&lt;/a&gt;: enables cryptography functionality using &lt;a href="https://azure.microsoft.com/en-us/products/key-vault/"&gt;Azure Key Vault&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-cryptography/local-storage/"&gt;Local storage&lt;/a&gt;: enables cryptography functionality using local files. Supported file formats are PEM, JSON Web Key, and raw key data for symmetric keys.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-cryptography/json-web-key-sets/"&gt;JWKS&lt;/a&gt;: enables cryptography functionality using &lt;a href="https://www.rfc-editor.org/rfc/rfc7517"&gt;JSON Web Key&lt;/a&gt; Sets (JWKS).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-cryptography/kubernetes-secrets/"&gt;Kubernetes Secrets&lt;/a&gt;: enables cryptography functionality using &lt;a href="https://kubernetes.io/docs/concepts/configuration/secret/"&gt;Kubernetes secrets&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Component improvements
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9Ug1fGiK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/btnok059nh0go6vvnzi3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9Ug1fGiK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/btnok059nh0go6vvnzi3.png" alt="Dapr component lifecycle" width="800" height="237"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With 1.11 many components have graduated to the&amp;nbsp;&lt;em&gt;Stable&lt;/em&gt;&amp;nbsp;certification level, which means these can be used in production confidently. All components have a certification level as mentioned in the&amp;nbsp;&lt;strong&gt;&lt;a href="https://docs.dapr.io/operations/components/certification-lifecycle/"&gt;Certification Lifecycle&lt;/a&gt;&lt;/strong&gt;. The&amp;nbsp;&lt;em&gt;Stable&lt;/em&gt;&amp;nbsp;level means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The component must have component&amp;nbsp;&lt;strong&gt;&lt;a href="https://docs.dapr.io/operations/components/certification-lifecycle/#certification-tests"&gt;certification tests&lt;/a&gt;&lt;/strong&gt;&amp;nbsp;validating functionality and resiliency.&lt;/li&gt;
&lt;li&gt;The component is maintained by Dapr maintainers and supported by the community.&lt;/li&gt;
&lt;li&gt;The component is well documented and tested.&lt;/li&gt;
&lt;li&gt;The component has been available as Alpha or Beta for at least 1 minor version release of Dapr runtime prior.&lt;/li&gt;
&lt;li&gt;A maintainer will address component security, core functionality and test issues according to the Dapr support policy and issue a patch release that includes the patched stable component.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following components have progressed to&amp;nbsp;&lt;em&gt;Stable&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bindings&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-bindings/s3/"&gt;AWS S3&lt;/a&gt;: output binding to store data in AWS S3 buckets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Middleware&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-middleware/middleware-rate-limit/"&gt;Rate limit&lt;/a&gt;: restricts the maximum allowed HTTP requests per second.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-middleware/middleware-bearer/"&gt;OpenID Connect&lt;/a&gt;: verifies a bearer token using &lt;a href="https://openid.net/connect/"&gt;OpenID Connect&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pub/Sub&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-pubsub/setup-gcp-pubsub/"&gt;GCP Pub/Sub&lt;/a&gt;: enables pub/sub messaging using Google Cloud Platform &lt;a href="https://cloud.google.com/pubsub/"&gt;Pub/Sub&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;State stores&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-firestore/"&gt;GCP Firestore&lt;/a&gt;: enables state store functionality using Google Cloud Platform &lt;a href="https://cloud.google.com/firestore/"&gt;Firestore&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-sqlite/"&gt;SQLite&lt;/a&gt;: enables state store functionality using &lt;a href="https://www.sqlite.org/index.html"&gt;SQLite 3&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Configuration stores&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-configuration-stores/postgresql-configuration-store/"&gt;PostgreSQL&lt;/a&gt;: enables configuration store functionality using &lt;a href="https://www.postgresql.org/"&gt;PostgreSQL&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.dapr.io/reference/components-reference/supported-configuration-stores/redis-configuration-store/"&gt;Redis&lt;/a&gt;: enables configuration store functionality using &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're using any of these components and have a demo to show, drop a link in the&amp;nbsp;&lt;em&gt;#show-and-tell&lt;/em&gt;&amp;nbsp;channel on the&amp;nbsp;&lt;strong&gt;&lt;a href="http://bit.ly/dapr-discord"&gt;Dapr Discord&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;*&lt;strong&gt;&lt;em&gt;Azure components authentication improvements&lt;/em&gt;&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Azure AD authentication has been added to the &lt;a href="https://docs.dapr.io/reference/components-reference/supported-bindings/storagequeues/"&gt;Azure Storage Queues binding&lt;/a&gt; and the &lt;a href="https://docs.dapr.io/reference/components-reference/supported-state-stores/setup-sqlserver/"&gt;SQL Server state store&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All Azure components that support Azure AD now support authentication using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview"&gt;Azure AD Workload Identity&lt;/a&gt; on Kubernetes&lt;/li&gt;
&lt;li&gt;Azure CLI &lt;a href="https://learn.microsoft.com/en-us/cli/azure/authenticate-azure-cli"&gt;credentials&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What is next?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This post is not a complete list of features and changes released in version 1.11. Read the official&amp;nbsp;&lt;strong&gt;&lt;a href="https://blog.dapr.io/posts/2023/06/12/dapr-v1.11-is-now-available/"&gt;Dapr release notes&lt;/a&gt;&lt;/strong&gt;&amp;nbsp;for more information. The release notes also contain information on how to upgrade to this latest version.&lt;/p&gt;

&lt;p&gt;Excited about these features and want to learn more? I'll cover the new features in more detail in future posts. Until then, join the&amp;nbsp;&lt;strong&gt;&lt;a href="http://bit.ly/dapr-discord"&gt;Dapr Discord&lt;/a&gt;&lt;/strong&gt;&amp;nbsp;to connect with thousands of Dapr users.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>cloudnative</category>
      <category>cloud</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Creating a Dapr pluggable component for Supabase</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Tue, 25 Apr 2023 14:56:41 +0000</pubDate>
      <link>https://dev.to/diagrid/creating-a-dapr-pluggable-component-for-supabase-32kj</link>
      <guid>https://dev.to/diagrid/creating-a-dapr-pluggable-component-for-supabase-32kj</guid>
      <description>&lt;p&gt;In this post, you’ll learn how to use the Dapr pluggable component .NET SDK and the Supabase C# library to build a pluggable state store component that uses Supabase tables.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you prefer watching a video instead of reading this blog post, head over to YouTube and watch this:&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/L0RRnWfGCzo"&gt;
&lt;/iframe&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dapr, the open-source, portable, event-driven runtime for building distributed applications, comes with over &lt;a href="https://docs.dapr.io/concepts/components-concept/"&gt;100 built-in components&lt;/a&gt; which can be used to integrate resources across many clouds or on-premise systems. If those components are not enough, or you want to create something custom for your specific needs, you can create a &lt;a href="https://docs.dapr.io/operations/components/pluggable-components/pluggable-components-overview/"&gt;pluggable component&lt;/a&gt;. The Dapr building block APIs that are pluggable are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State management&lt;/li&gt;
&lt;li&gt;Publish and subscribe&lt;/li&gt;
&lt;li&gt;Input and output bindings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since Dapr &lt;a href="https://www.diagrid.io/blog/dapr-1-10-release-highlights"&gt;release 1.10&lt;/a&gt; there are &lt;a href="https://docs.dapr.io/developing-applications/develop-components/pluggable-components/pluggable-components-sdks/pluggable-components-dotnet/"&gt;pluggable component SDKs&lt;/a&gt; available that make it easier to create them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://supabase.com/"&gt;Supabase&lt;/a&gt; is a popular, open-source, Firebase alternative that offers Postgres databases, authentication, Edge functions, real-time messaging and file storage. The Supabase community has released a &lt;a href="https://github.com/supabase-community/supabase-csharp"&gt;C#/.NET library&lt;/a&gt; that developers can use to integrate their .NET apps with the Supabase platform. For managing Postgres databases, the library uses the &lt;a href="https://github.com/supabase-community/postgrest-csharp"&gt;postgrest-csharp&lt;/a&gt; library that allows developers to use strongly typed models and LINQ queries.&lt;/p&gt;

&lt;p&gt;This post describes the steps required to make a proof of concept Dapr pluggable component using .NET 7 that combines both the Dapr pluggable component .NET SDK and the Supabase C# library. The result is an ASP.NET application, that is run locally, and tested by making HTTP requests to interact with the state stored in a Supabase table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Z3XLZdzX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/089owyntaiwxeiunwhtz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Z3XLZdzX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/089owyntaiwxeiunwhtz.png" alt="Image description" width="800" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Prerequisites
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dotnet.microsoft.com/download/dotnet/7.0"&gt;.NET 7 SDK&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.dapr.io/getting-started/install-dapr-cli/"&gt;Dapr CLI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A Supabase account, you can &lt;a href="https://app.supabase.com/sign-up"&gt;sign up&lt;/a&gt; for free.&lt;/li&gt;
&lt;li&gt;Supported OS: macOS, Linux,&amp;nbsp;&lt;a href="https://learn.microsoft.com/en-us/windows/wsl/install"&gt;WSL&lt;/a&gt;&amp;nbsp;on Windows.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Creating the DaprPluggableSupabase .NET project
&lt;/h2&gt;

&lt;p&gt;If you’re more interested in using the pluggable component instead of creating it from scratch, continue with section &lt;strong&gt;3. Supabase Setup&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone &lt;a href="https://github.com/diagrid-labs/dapr-pluggable-component-supabase"&gt;this repo&lt;/a&gt;, open a terminal and navigate to the &lt;code&gt;src&lt;/code&gt; folder. &lt;/p&gt;

&lt;p&gt;The cloned repository already contains an &lt;a href="http://ASP.NET"&gt;ASP.NET&lt;/a&gt; app in the &lt;code&gt;DaprPluggableSupabase&lt;/code&gt; folder that is the pluggable component. You can use this as a reference. &lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new .NET web project, and make sure to use a different name than &lt;code&gt;DaprPluggableSupabase&lt;/code&gt; (e.g. &lt;code&gt;MyDaprPluggableSupabase&lt;/code&gt;):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet new web --name MyDaprPluggableSupabase&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change to the &lt;code&gt;MyDaprPluggableSupabase&lt;/code&gt; folder and add the &lt;code&gt;Dapr.PluggableComponents.AspNetCore&lt;/code&gt; and &lt;code&gt;supabase-csharp&lt;/code&gt; NuGet packages:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd MyDaprPluggableSupabase&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet add package Dapr.PluggableComponents.AspNetCore&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet add package supabase-csharp&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Create a new class file in the &lt;code&gt;MyDaprPluggableSupabase&lt;/code&gt; folder named &lt;code&gt;KeyValue.cs&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the following content to this new class:&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Postgrest.Attributes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Postgrest.Models&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DaprPluggableSupabase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dapr_state_store"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;KeyValue&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;PrimaryKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;KeyValue&lt;/code&gt; class defines the data type that will be stored in the Supabase table. It inherits from &lt;code&gt;BaseModel&lt;/code&gt;, which is part of the Supabase postgrest-csharp library. This library uses attributes that can be used to decorate the class and properties, which makes it easier for developers to use strongly typed models when interacting with the database table. Dapr state stores are key/value stores and Postgres databases are object-relational data stores. Since this is not a perfect match, the Dapr key/value-based state management API is mapped to this &lt;code&gt;KeyValue&lt;/code&gt; model to fit the Postgres schema.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new class file in the &lt;code&gt;MyDaprPluggableSupabase&lt;/code&gt; folder named &lt;code&gt;SupabaseStateStore.cs&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add the following content to this new class:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Dapr.PluggableComponents.Components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Dapr.PluggableComponents.Components.StateStore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DaprPluggableSupabase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SupabaseStateStore&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IStateStore&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="n"&gt;disable&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt; &lt;span class="n"&gt;_supabaseClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="n"&gt;enable&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;PROJECT_APIKEY_KEYWORD&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"projectApiKey"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;PROJECT_URL_KEYWORD&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"projectUrl"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;DeleteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StateStoreDeleteRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_supabaseClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;From&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StateStoreGetResponse&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StateStoreGetRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetKV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kv&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;valueAsBytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StateStoreGetResponse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Data&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valueAsBytes&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StateStoreGetResponse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;InitAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MetadataRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROJECT_URL_KEYWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;projectUrl&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Missing required property \"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PROJECT_URL_KEYWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\" in component file."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Properties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PROJECT_APIKEY_KEYWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;projectApiKey&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Missing required property \"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;PROJECT_APIKEY_KEYWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\" in component file."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;_supabaseClient&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Supabase&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;projectUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;projectApiKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_supabaseClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;InitializeAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StateStoreSetRequest&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;newKV&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;KeyValue&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;CreatedAt&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UtcNow&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Encoding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTF8&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Span&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="n"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;existingKV&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetKV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;existingKV&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;newKV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;existingKV&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_supabaseClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;From&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newKV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_supabaseClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;From&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="nf"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newKV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetKV&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_supabaseClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;From&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;KeyValue&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="n"&gt;disable&lt;/span&gt;
                            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;nullable&lt;/span&gt; &lt;span class="n"&gt;enable&lt;/span&gt;
                            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Key&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that the class inherits from &lt;code&gt;IStateStore&lt;/code&gt;, this is the interface that all Dapr state store components implement. The interface contains three methods that require implementing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DeleteAsync&lt;/code&gt;, this will delete a value from the store.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GetAsync&lt;/code&gt;, this will retrieve a value from the store.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SetAsync&lt;/code&gt;, this will insert/update a value to the store.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All methods use the Supabase C# client to manage the data via the &lt;code&gt;KeyValue&lt;/code&gt; model.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;IStateStore&lt;/code&gt; interface inherits the &lt;code&gt;IPluggableComponent&lt;/code&gt; interface that contains only one method, &lt;code&gt;InitAsync&lt;/code&gt;, and this method used to initialize the state store. In this case, it is used to create an instance of the &lt;code&gt;Supabase.Client&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update the existing &lt;code&gt;Program.cs&lt;/code&gt; file with the following content:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Dapr.PluggableComponents&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;DaprPluggableSupabase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DaprPluggableComponentsApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RegisterService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"supabase"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;serviceBuilder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;serviceBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterStateStore&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SupabaseStateStore&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class defines the application as a &lt;code&gt;DaprPluggableComponentApplication&lt;/code&gt; and registers the &lt;code&gt;SupabaseStateStore&lt;/code&gt; as a new state store that will communicate with Dapr applications via a Unix domain socket named &lt;code&gt;supabase&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Build the application to make sure there are no compilation errors:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet build&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  3. &lt;strong&gt;Supabase Setup&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The pluggable component will interact with a Supabase Postgres table. This section describes how to create the table using the Supabase dashboard and where to find the project URL and API key required in the next section.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Login to Supabase and create a new project.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a new database table with the following specifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Name:&amp;nbsp;&lt;code&gt;dapr_state_store&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Primary Key:&amp;nbsp;&lt;code&gt;id&lt;/code&gt;, (int8, not null)&lt;/li&gt;
&lt;li&gt;Columns:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;created_at&lt;/code&gt;&amp;nbsp;(timestamptz, not null)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;key&lt;/code&gt;&amp;nbsp;(text, not null)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;value&lt;/code&gt;&amp;nbsp;(text, null)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RLS (Row Level Security) is disabled&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that for production use,&amp;nbsp;&lt;a href="https://supabase.com/docs/guides/auth/row-level-security"&gt;Row Level Security (RLS)&lt;/a&gt;&amp;nbsp;should be enabled, and access policies should be added to the table.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Table definition:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;table&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dapr_state_store&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="nb"&gt;bigint&lt;/span&gt; &lt;span class="k"&gt;generated&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="k"&gt;identity&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="nb"&gt;timestamp&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nb"&gt;time&lt;/span&gt; &lt;span class="k"&gt;zone&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;not&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;constraint&lt;/span&gt; &lt;span class="n"&gt;dapr_state_store_pkey&lt;/span&gt; &lt;span class="k"&gt;primary&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="k"&gt;constraint&lt;/span&gt; &lt;span class="n"&gt;dapr_state_store_id_key&lt;/span&gt; &lt;span class="k"&gt;unique&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;tablespace&lt;/span&gt; &lt;span class="n"&gt;pg_default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You'll need the Supabase project URL and public API key to configure the Dapr component file in the next section. This information is found in the Supabase dashboard in the project&amp;nbsp;&lt;code&gt;Settings &amp;gt; API&lt;/code&gt;&amp;nbsp;tab.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. &lt;strong&gt;Update the Dapr pluggable Supabase component file&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Dapr uses a modular design where functionality is delivered as a &lt;a href="https://docs.dapr.io/concepts/components-concept/"&gt;component&lt;/a&gt;. A component file contains the specification of a component, including the name, the component type, and related metadata that is specific to connecting with the underlying resource. The component file for the Supabase state store looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dapr.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Component&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pluggable-supabase&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;state.supabase&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;projectUrl&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;projectApiKey&lt;/span&gt;
    &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value of the &lt;code&gt;spec.type&lt;/code&gt; field, &lt;code&gt;state.supabase&lt;/code&gt;, consists of two parts: the component type (&lt;code&gt;state&lt;/code&gt;), and the socket name (&lt;code&gt;supabase&lt;/code&gt;). The socket name needs to match with the socket name argument provided in the &lt;code&gt;RegisterService&lt;/code&gt; method in the &lt;code&gt;Program.cs&lt;/code&gt; class of section 2. A template of this component file is available in the repository, follow these steps to update the file, so it can be used locally.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the&amp;nbsp;&lt;code&gt;resources&lt;/code&gt;&amp;nbsp;folder in this repository.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rename the&amp;nbsp;&lt;code&gt;resources\pluggableSupabase.yml.template&lt;/code&gt;&amp;nbsp;file to&amp;nbsp;&lt;code&gt;resources\pluggableSupabase.yml&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The&amp;nbsp;pluggableSupabase.yml&amp;nbsp;file is added to .gitignore, so it won't be accidentally committed to source control for this demo app. For production use, the yaml files&amp;nbsp;should&amp;nbsp;be checked into source control and&amp;nbsp;&lt;a href="https://docs.dapr.io/operations/components/component-secrets/"&gt;secret store references&lt;/a&gt;&amp;nbsp;should be used, instead of plain text values.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Open the&amp;nbsp;&lt;code&gt;pluggableSupabase.yml&lt;/code&gt;&amp;nbsp;file and update the values for&amp;nbsp;&lt;code&gt;projectUrl&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;projectApiKey&lt;/code&gt; obtained in the previous section.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Save the file and copy it to the user's Dapr components folder:&amp;nbsp;&lt;code&gt;~/.dapr/components&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;When the Dapr CLI is run, all the component files in this folder will be loaded, so the pluggable Supabase component should be available.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  5. &lt;strong&gt;Run the DaprPluggableSupabase application&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Regular Dapr components are part of the Dapr runtime and don't require additional processes to run. Pluggable components, however, are not part of the Dapr runtime and need to be run separately, which is done in this section.&lt;/p&gt;

&lt;p&gt;The&amp;nbsp;&lt;code&gt;DaprPluggableSupabase&lt;/code&gt;&amp;nbsp;project in this repo implements the Dapr state store interface and uses the&amp;nbsp;&lt;a href="https://github.com/supabase-community/supabase-csharp"&gt;Supabase C# library&lt;/a&gt;&amp;nbsp;to access a Supabase table. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open a terminal and navigate to the&amp;nbsp;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;src/DaprPluggableSupabase&lt;/code&gt;&amp;nbsp;folder to use the included pluggable component project 
&lt;em&gt;or&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;src/MyDaprPluggableSupabase&lt;/code&gt;&amp;nbsp;folder to use the pluggable component project you’ve just created yourself.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Build the project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet build&lt;/code&gt;&lt;/p&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Run the project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet run&lt;/code&gt;&lt;/p&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  6. &lt;strong&gt;Run the Dapr process and test the Supabase state store&lt;/strong&gt;
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open a new terminal and use the Dapr CLI to run the Dapr process&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dapr run --app-id myapp --dapr-http-port 3500&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Expected output:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The output should contain an INFO message that the pluggable-supabase component is loaded:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;INFO[0000] component loaded. name: pluggable-supabase, type: state.supabase/v1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The log should end with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ℹ️  Dapr sidecar is up and running.&lt;br&gt;
✅  You're up and running! Dapr logs will appear here.&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set a new state by making a POST request to the state management endpoint:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl --request POST --url http://localhost:3500/v1.0/state/pluggable-supabase --header 'content-type: application/json' --data '[{"key": "key1","value": "This is stored in Supabase!"}]'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Expected output:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HTTP 204 No Content&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retrieve the new state using a GET request:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl --request GET --url http://localhost:3500/v1.0/state/pluggable-supabase/key1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Expected output:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HTTP 200 OK&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"This is stored in Supabase!"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or have a look at the Supabase dashboard to see the new state record in the table.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You've now successfully created and used the Dapr pluggable Supabase state store component.&amp;nbsp;🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;This proof of concept implementation of a pluggable component demonstrates how the Dapr pluggable component .NET SDK makes it easier for developers to create their custom components. You can use &lt;a href="https://github.com/diagrid-labs/dapr-pluggable-component-supabase"&gt;this solution&lt;/a&gt; as a starting point, and expand it with additional state management API features, such as entity tag (ETag), metadata, and options, as described in the &lt;a href="https://docs.dapr.io/reference/api/state_api"&gt;specification&lt;/a&gt;. A requirement for using this pluggable component in a real project is to &lt;a href="https://docs.dapr.io/operations/hosting/"&gt;deploy it&lt;/a&gt; to a (managed) Kubernetes environment or use it in a self-hosted mode.&lt;/p&gt;

&lt;p&gt;The Supabase platform offers a great variety of useful back-end features, and with the set of client libraries it’s very accessible to a diverse group of developers. Take a look at &lt;a href="https://supabase.com/launch-week"&gt;Supabase Launch Week&lt;/a&gt; to read about their latest feature announcements.&lt;/p&gt;

&lt;p&gt;From my perspective, I’d like to explore further how Dapr can integrate with other Supabase features. It would also be great to see a Supabase state store as a built-in component that’s available in the Dapr runtime without the need of running the pluggable component separately. I also hope the proposed &lt;a href="https://github.com/dapr/dapr/issues/5146"&gt;DocumentStore building block&lt;/a&gt; will get some traction this year, since this will pair up very nicely with Supabase and other PostgreSQL stores. &lt;/p&gt;

&lt;p&gt;Do you have any questions or comments about this blog post or the code? Join the&amp;nbsp;&lt;strong&gt;&lt;a href="https://bit.ly/dapr-discord"&gt;Dapr discord&lt;/a&gt;&lt;/strong&gt; and post a message in the&amp;nbsp;&lt;code&gt;#pluggable-components&lt;/code&gt;&amp;nbsp;channel. Have you made something with Dapr? Post a message in the&amp;nbsp;&lt;code&gt;#show-and-tell&lt;/code&gt;&amp;nbsp;channel, we love to see your creations!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>cloud</category>
      <category>tutorial</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Create event-driven applications with Cloudflare queues and Dapr</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Thu, 09 Mar 2023 14:20:59 +0000</pubDate>
      <link>https://dev.to/diagrid/create-event-driven-applications-with-cloudflare-queues-and-dapr-3an8</link>
      <guid>https://dev.to/diagrid/create-event-driven-applications-with-cloudflare-queues-and-dapr-3an8</guid>
      <description>&lt;p&gt;In this post, you’ll learn how to build a cloud to edge event-driven application with Dapr and Cloudflare. You’ll learn how to create:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Cloudflare queue.&lt;/li&gt;
&lt;li&gt;A consumer Cloudflare worker (in TypeScript) that reads messages from the queue.&lt;/li&gt;
&lt;li&gt;A producer Dapr app (in TypeScript) that uses the Cloudflare Queue binding to publish messages to the queue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hNKtXXn0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4co04m0zqy3cis62o3m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hNKtXXn0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o4co04m0zqy3cis62o3m.png" alt="Sending messages from a Dapr app to Cloudflare Queues" width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Event-driven applications FTW 🚀
&lt;/h2&gt;

&lt;p&gt;Event-driven applications are becoming increasingly popular. The decoupling of event producers and event consumers makes applications more resilient and flexible, since they allow independent implementation and scaling of the applications. &lt;/p&gt;

&lt;p&gt;Cloudflare recently announced &lt;a href="https://developers.cloudflare.com/queues/"&gt;Queues&lt;/a&gt;, allowing developers to send and receive messages with guaranteed delivery and integrating with Cloudflare Workers, a fast edge computing platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dapr.io/"&gt;Dapr&lt;/a&gt;, the open-source distributed application runtime, is often used in event-driven applications. Dapr provides a set of standardized API building blocks that simplify microservice development. By using the &lt;a href="https://docs.dapr.io/developing-applications/building-blocks/bindings/bindings-overview/"&gt;Bindings building block&lt;/a&gt;, developers can use input, and output bindings, and either trigger their apps or invoke other resources without having to learn resource-specific SDKs for these resources. With &lt;a href="https://www.diagrid.io/blog/dapr-1-10-release-highlights"&gt;Dapr release 1.10&lt;/a&gt;, a &lt;a href="https://docs.dapr.io/reference/components-reference/supported-bindings/cloudflare-queues/"&gt;new binding&lt;/a&gt; is provided that allows developers to publish messages to Cloudflare Queues. Because of the common set of APIs that Dapr offers, developers from any background can use the binding to publish messages to Cloudflare Queues without needing to know the Cloudflare SDKs or adding that dependency to their codebase.&lt;/p&gt;

&lt;p&gt;Let’s start building an event-driven app and see the binding in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;The following is required to run this sample:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clone &lt;a href="https://github.com/diagrid-labs/dapr-cloudflare-queues"&gt;this repository&lt;/a&gt; to your local machine.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install&amp;nbsp;&lt;a href="https://docs.dapr.io/getting-started/install-dapr-cli/"&gt;Dapr CLI&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use the Dapr CLI to install the &lt;a href="https://docs.dapr.io/getting-started/install-dapr-selfhost/"&gt;Dapr runtime locally&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dapr init&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install&amp;nbsp;&lt;a href="https://nodejs.org/en/download/"&gt;Node.js&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install&amp;nbsp;&lt;a href="https://developers.cloudflare.com/workers/wrangler/install-and-update/"&gt;Cloudflare Wrangler&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensure you're on a Cloudflare paid plan, since that is required to use Cloudflare queues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Enable Queues in the Cloudflare dashboard.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dashboard &amp;gt; Workers &amp;gt; Queues&lt;/li&gt;
&lt;li&gt;Enable Queues Beta&lt;/li&gt;
&lt;li&gt;You should see a confirmation in the dashboard that queues are enabled.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t7U2fY_3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gum1sg2hv31xt9xn1jc9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t7U2fY_3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gum1sg2hv31xt9xn1jc9.png" alt="Enabled Cloudflare Queues" width="800" height="189"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the applications
&lt;/h2&gt;

&lt;p&gt;The solution consists of three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A Cloudflare queue&lt;/li&gt;
&lt;li&gt;A&amp;nbsp;&lt;em&gt;consumer&lt;/em&gt;&amp;nbsp;Cloudflare worker that reads messages from the queue.&lt;/li&gt;
&lt;li&gt;A&amp;nbsp;&lt;em&gt;producer&lt;/em&gt;&amp;nbsp;Dapr app that will publish messages to the queue.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  1. Create a Cloudflare queue
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Open a terminal and use the wrangler CLI to login to Cloudflare:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wrangler login&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Follow the instructions in the browser to login to Cloudflare.&lt;/p&gt;

&lt;p&gt;The response in the terminal should end with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Successfully logged in.&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create the Cloudflare queue using the wrangler CLI:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wrangler queues create dapr-messages&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The response in the terminal should end with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Created queue dapr-messages.&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  2. Create a consumer Cloudflare worker
&lt;/h2&gt;

&lt;p&gt;You can either create a new&amp;nbsp;&lt;em&gt;consumer&lt;/em&gt;&amp;nbsp;worker by following steps 1-3, or use the &lt;a href="https://github.com/diagrid-labs/dapr-cloudflare-queues/tree/main/consumer"&gt;existing&amp;nbsp;&lt;em&gt;consumer&lt;/em&gt;&amp;nbsp;worker&lt;/a&gt; in this repository and continue from step 4.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;In the root folder, create a worker to consume messages:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wrangler init consumer&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create package.json:&amp;nbsp;&lt;code&gt;Y&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use TypeScript:&amp;nbsp;&lt;code&gt;Y&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create worker:&amp;nbsp;&lt;code&gt;Fetch handler&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Write tests:&amp;nbsp;&lt;code&gt;N&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A new folder named&amp;nbsp;&lt;em&gt;consumer&lt;/em&gt;&amp;nbsp;will be created which contains the worker.&lt;/p&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Update the&amp;nbsp;&lt;em&gt;consumer/src/index.ts&lt;/em&gt;&amp;nbsp;file to:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="na"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MessageBatch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;
  &lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Add the following lines to the&amp;nbsp;&lt;em&gt;consumer/wrangler.toml&lt;/em&gt;&amp;nbsp;file:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[queues.consumers]]&lt;/span&gt;
&lt;span class="py"&gt;queue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dapr-messages"&lt;/span&gt;
&lt;span class="py"&gt;max_batch_size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Ensure that you're in the&amp;nbsp;&lt;em&gt;consumer&lt;/em&gt;&amp;nbsp;folder and install the dependencies:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd consumer&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Publish the&amp;nbsp;&lt;em&gt;consumer&lt;/em&gt;&amp;nbsp;worker:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wrangler publish&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The response in the terminal should end with:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight shell"&gt;&lt;code&gt;Published consumer &lt;span class="o"&gt;(&lt;/span&gt;... sec&lt;span class="o"&gt;)&lt;/span&gt;
  https://consumer.&amp;lt;SUBDOMAIN&amp;gt;.workers.dev
  Consumer &lt;span class="k"&gt;for &lt;/span&gt;dapr-messages
Current Deployment ID: &amp;lt;DEPLOYMENT_ID&amp;gt;
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;Start a tail to read the log of the consumer worker:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;wrangler tail&lt;/code&gt;&lt;/p&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  3. Configure the producer Dapr app
&lt;/h2&gt;

&lt;p&gt;The Cloudflare Dapr binding uses a Cloudflare worker to publish messages, since only Cloudflare workers can access the queue.&lt;/p&gt;

&lt;p&gt;There are two options for this worker:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Dapr provisions the worker.&lt;/li&gt;
&lt;li&gt;You use a pre-provisioned Cloudflare worker.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This sample uses option 1. Read the&amp;nbsp;&lt;a href="https://v1-10.docs.dapr.io/reference/components-reference/supported-bindings/cloudflare-queues/#configuring-the-worker"&gt;Cloudflare Queues binding spec&lt;/a&gt;&amp;nbsp;and choose&amp;nbsp;&lt;em&gt;Manually provision the Worker script&lt;/em&gt;&amp;nbsp;if you want to go for option 2.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a binding file
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Rename the &lt;code&gt;producer/resources/binding.yaml.template&lt;/code&gt; to &lt;code&gt;producer/resources/binding.yaml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the&amp;nbsp;&lt;code&gt;binding.yaml&lt;/code&gt;&amp;nbsp;file and inspect its content.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dapr.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Component&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloudflare-queues&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bindings.cloudflare.queues&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="c1"&gt;# Increase the initTimeout if Dapr is managing the Worker for youinitTimeout: "120s"&lt;/span&gt;
  &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="c1"&gt;# Name of the existing Cloudflare Queue (required)- name: queueName&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dapr-messages"&lt;/span&gt;
&lt;span class="c1"&gt;# Name of the Worker (required)- name: workerName&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dapr-message-worker"&lt;/span&gt;
&lt;span class="c1"&gt;# PEM-encoded private Ed25519 key (required)- name: key&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;-----BEGIN PRIVATE KEY-----&lt;/span&gt;
        &lt;span class="s"&gt;MC4CAQ...&lt;/span&gt;
        &lt;span class="s"&gt;-----END PRIVATE KEY-----&lt;/span&gt;
&lt;span class="c1"&gt;# Cloudflare account ID (required to have Dapr manage the Worker)- name: cfAccountID&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="c1"&gt;# API token for Cloudflare (required to have Dapr manage the Worker)- name: cfAPIToken&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="c1"&gt;# URL of the Worker (required if the Worker has been pre-created outside of Dapr)- name: workerUrl&lt;/span&gt;
      &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The&amp;nbsp;&lt;code&gt;metadata.name&lt;/code&gt;,&amp;nbsp;&lt;code&gt;spec.metadata.queueName&lt;/code&gt;&amp;nbsp;and&amp;nbsp;&lt;code&gt;spec.metadata.workerName&lt;/code&gt;&amp;nbsp;values have already been set. Ensure that the&amp;nbsp;&lt;code&gt;queueName&lt;/code&gt;&amp;nbsp;matches the&amp;nbsp;&lt;code&gt;queue&lt;/code&gt;&amp;nbsp;setting in the&amp;nbsp;&lt;em&gt;consumer&lt;/em&gt;&amp;nbsp;worker&amp;nbsp;&lt;code&gt;wrangler.toml&lt;/code&gt;&amp;nbsp;file.&lt;/p&gt;

&lt;p&gt;Values for&amp;nbsp;&lt;code&gt;spec.metadata.key&lt;/code&gt;,&amp;nbsp;&lt;code&gt;spec.metadata.cfAccountID&lt;/code&gt;, and&amp;nbsp;&lt;code&gt;spec.metadata.cfAPIToken&lt;/code&gt;&amp;nbsp;still need to be provided.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Follow&amp;nbsp;&lt;a href="https://v1-10.docs.dapr.io/reference/components-reference/supported-bindings/cloudflare-queues/#generate-an-ed25519-key-pair"&gt;these instructions&lt;/a&gt;&amp;nbsp;in the Dapr docs to set the value for&amp;nbsp;&lt;code&gt;spec.metadata.key&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The Cloudflare account ID should go in the&amp;nbsp;&lt;code&gt;spec.metadata.cfAccountID&lt;/code&gt;&amp;nbsp;field. You can find the account ID in the Cloudflare dashboard URL:&amp;nbsp;&lt;code&gt;https://dash.cloudflare.com/&amp;lt;ACCOUNT_ID&amp;gt;/workers/overview&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A Cloudflare API token should go in the&amp;nbsp;&lt;code&gt;spec.metadata.cfAPIToken&lt;/code&gt;&amp;nbsp;field. It can be generated as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In the Cloudflare dashboard, go to the Workers page.&lt;/li&gt;
&lt;li&gt;Click the&amp;nbsp;&lt;em&gt;API tokens&lt;/em&gt;&amp;nbsp;link&lt;/li&gt;
&lt;li&gt;Click the&amp;nbsp;&lt;em&gt;Create token&lt;/em&gt;&amp;nbsp;button&lt;/li&gt;
&lt;li&gt;Click the&amp;nbsp;&lt;em&gt;Use template&lt;/em&gt;&amp;nbsp;button for Edit Cloudflare Workers&lt;/li&gt;
&lt;li&gt;Update the permissions to only contain:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Account&lt;/em&gt;&amp;nbsp;|&amp;nbsp;&lt;em&gt;Worker Scripts&lt;/em&gt;&amp;nbsp;|&amp;nbsp;&lt;em&gt;Edit&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Update the Account Resources to only contain:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Include&lt;/em&gt;&amp;nbsp;|&amp;nbsp;&lt;em&gt;&amp;lt;YOUR ACCOUNT&amp;gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Set a time to live (TTL) for the token, the shorter, the better, if you're just testing.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now the binding file is complete. The file is gitignored, so the secrets won't be committed to the repository.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inspect the Node app
&lt;/h3&gt;

&lt;p&gt;Let's have a look at the Dapr app that will send messages to the Cloudflare queue.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Inspect the&amp;nbsp;&lt;code&gt;producer/index.ts&lt;/code&gt;&amp;nbsp;file.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DaprClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@dapr/dapr&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Common settingsconst daprHost = "http://localhost";&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;daprPort&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DAPR_HTTP_PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;3500&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Starting...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bindingName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;cloudflare-queues&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bindingOperation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;publish&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;DaprClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;daprHost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;daprPort&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello World &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bindingName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;bindingOperation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Completed.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ms&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note that the&amp;nbsp;&lt;code&gt;bindingName&lt;/code&gt;&amp;nbsp;is set to&amp;nbsp;&lt;code&gt;cloudflare-queues&lt;/code&gt;&amp;nbsp;and matches the value of the &lt;code&gt;metadata.name&lt;/code&gt; in the&amp;nbsp;&lt;code&gt;binding.yaml&lt;/code&gt;. The&amp;nbsp;&lt;code&gt;bindingOperation&lt;/code&gt;&amp;nbsp;is set to&amp;nbsp;&lt;code&gt;publish&lt;/code&gt;&amp;nbsp;(&lt;code&gt;create&lt;/code&gt;&amp;nbsp;could be used as an alias).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Run the producer app
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Open a new terminal window and navigate to the&amp;nbsp;&lt;code&gt;producer&lt;/code&gt;&amp;nbsp;folder.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the dependencies:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Run the following command to start the producer app:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr run &lt;span class="nt"&gt;--app-id&lt;/span&gt; producer &lt;span class="nt"&gt;--resources-path&lt;/span&gt; ./resources &lt;span class="nt"&gt;--&lt;/span&gt; npm run start
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The terminal that logs the tail of the consumer app should show a log statement for each of the ten messages sent:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Unknown Event - Ok @ 17/02/2023, 11:22:50
  &lt;span class="o"&gt;(&lt;/span&gt;log&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[{&lt;/span&gt;&lt;span class="s2"&gt;"body"&lt;/span&gt;:&lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;data&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Hello World 1&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;,&lt;span class="s2"&gt;"timestamp"&lt;/span&gt;:&lt;span class="s2"&gt;"2023-02-17T10:22:50.556Z"&lt;/span&gt;,&lt;span class="s2"&gt;"id"&lt;/span&gt;:&lt;span class="s2"&gt;"8f6293d9d04001e3f2a12be5c47acde2"&lt;/span&gt;&lt;span class="o"&gt;}]&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jM08LsYc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0sjnrtrncscu92dmqc4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jM08LsYc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0sjnrtrncscu92dmqc4.gif" alt="wrangler log tail of the consumer" width="800" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You’ve now sent messages from a Dapr app to a Cloudflare Queue (&amp;amp; Worker) via the Cloudflare Queues binding! 🎉 Hungry for more Dapr bindings? Have a look at the long list of &lt;a href="https://docs.dapr.io/reference/components-reference/supported-bindings/"&gt;supported bindings&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Any questions or comments about this blog post or the code? Join the&amp;nbsp;&lt;a href="https://aka.ms/dapr-discord"&gt;Dapr discord&lt;/a&gt;&amp;nbsp;and post a message in the&amp;nbsp;&lt;code&gt;#components-contrib&lt;/code&gt;&amp;nbsp;channel. Have you made something with Cloudflare and Dapr? Post a message in the&amp;nbsp;&lt;code&gt;#show-and-tell&lt;/code&gt;&amp;nbsp;channel, we love to see your creations!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>cloud</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to upgrade your local Dapr runtime and CLI</title>
      <dc:creator>Marc Duiker</dc:creator>
      <pubDate>Wed, 22 Feb 2023 08:51:26 +0000</pubDate>
      <link>https://dev.to/marcduiker/how-to-upgrade-your-local-dapr-runtime-and-cli-4c02</link>
      <guid>https://dev.to/marcduiker/how-to-upgrade-your-local-dapr-runtime-and-cli-4c02</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;EDIT: updated for the Dapr 1.15 release :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've recently upgraded my local Dapr runtime and the Dapr CLI due to the &lt;a href="https://blog.dapr.io/posts/2025/02/27/dapr-v1.15-is-now-available/" rel="noopener noreferrer"&gt;new 1.15 release being available&lt;/a&gt;. Since I'll be upgrading to new releases on a regular basis, and use both Mac and a Windows machines, I might as well help my future self and write this down since I forget these things after a week 😅.&lt;/p&gt;

&lt;p&gt;Upgrading the self-hosted environment (which I call the runtime) is described in detail in the &lt;a href="https://docs.dapr.io/operations/hosting/self-hosted/self-hosted-upgrade/" rel="noopener noreferrer"&gt;official docs&lt;/a&gt;, but here I'm writing a slimmed down version, useful if you're either running Windows with winget, or macOS with Homebrew.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Uninstall the old Dapr runtime:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr uninstall
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;If you also want to remove the Redis and Zipkin images run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr uninstall &lt;span class="nt"&gt;--all&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install the new Dapr runtime:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr init
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Upgrade the Dapr CLI:&lt;/p&gt;

&lt;p&gt;Using Windows and winget:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;winget upgrade Dapr.CLI
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Using macOS and brew:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew upgrade dapr-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Verify that everything is upgraded:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dapr &lt;span class="nt"&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The response should list the new versions:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CLI version: 1.15.0
Runtime version: 1.15.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;
`&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  🚨 Bleeding edge 🚨
&lt;/h3&gt;

&lt;p&gt;If you need the very latest, (bleeding) edge bits of Dapr, you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pull the runtime images from the &lt;a href="https://github.com/dapr/dapr/pkgs/container/dapr" rel="noopener noreferrer"&gt;Dapr GitHub container registry&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Download the Dapr CLI release candidates from the &lt;a href="https://github.com/dapr/cli/releases" rel="noopener noreferrer"&gt;Dapr CLI GitHub release page&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy the latest Dapr release!&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqolqp3a6wulpbw5udgp9.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqolqp3a6wulpbw5udgp9.gif" alt="Dappy" width="960" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vibecoding</category>
    </item>
  </channel>
</rss>
