<?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: Olcay Bayram</title>
    <description>The latest articles on DEV Community by Olcay Bayram (@olcay).</description>
    <link>https://dev.to/olcay</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F327686%2F9cb25666-3441-4ba6-900b-964e5e45d5a0.jpeg</url>
      <title>DEV Community: Olcay Bayram</title>
      <link>https://dev.to/olcay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olcay"/>
    <language>en</language>
    <item>
      <title>Architect Azure API Management service</title>
      <dc:creator>Olcay Bayram</dc:creator>
      <pubDate>Fri, 31 Jan 2020 14:12:11 +0000</pubDate>
      <link>https://dev.to/olcay/architect-azure-api-management-service-24hd</link>
      <guid>https://dev.to/olcay/architect-azure-api-management-service-24hd</guid>
      <description>&lt;p&gt;Let's setup an API gateway using the Azure API Management service with a nice architecture.&lt;/p&gt;

&lt;p&gt;An API gateway is positioned between your APIs and the Internet. You can control how the APIs are exposed or limit the usage per subscription through the Azure portal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why would I use the Azure API Management service?
&lt;/h2&gt;

&lt;p&gt;It is a native Azure SaaS (software as a service) which brings nice pros;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API documentation&lt;/li&gt;
&lt;li&gt;Rate limiting access&lt;/li&gt;
&lt;li&gt;Health monitoring&lt;/li&gt;
&lt;li&gt;Modern formats like JSON&lt;/li&gt;
&lt;li&gt;Connections to any API&lt;/li&gt;
&lt;li&gt;Analytics&lt;/li&gt;
&lt;li&gt;Security&lt;/li&gt;
&lt;li&gt;Built-in caching&lt;/li&gt;
&lt;li&gt;Network tracing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is there any trade-off?
&lt;/h2&gt;

&lt;p&gt;Yes, &lt;a href="https://feedback.azure.com/forums/248703-api-management/suggestions/15527100-circuit-breaker-policy"&gt;the circuit breaker policy&lt;/a&gt; is not implemented yet. You can build your own API gateway with a circuit breaker using third-party libraries like &lt;a href="https://github.com/ThreeMammals/Ocelot"&gt;Ocelot&lt;/a&gt; and &lt;a href="https://github.com/App-vNext/Polly"&gt;Polly&lt;/a&gt; with &lt;a href="https://ocelot.readthedocs.io/en/latest/features/qualityofservice.html"&gt;Quality of Service&lt;/a&gt; configured but does it worth to go down to a PaaS (platform as a service) instead of a SaaS?&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup an API Management service
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign into the &lt;a href="https://portal.azure.com/#create/hub"&gt;Azure portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Create a resource through &lt;strong&gt;Integration&lt;/strong&gt;, and then &lt;strong&gt;API Management&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Give a globally unique name to your resource.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Consumption (99.9SLA, %)&lt;/strong&gt; as the pricing tier because this serverless plan is much faster to create for an ad-hoc testing.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Deployment will start and it may take several minutes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When the deployment is complete you will get a notification email to the address you provided as an administrator. Once it is deployed we import our first API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Import an API
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Sign into the &lt;a href="https://portal.azure.com/"&gt;Azure portal&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;All Resources&lt;/strong&gt;, and then select your API gateway.&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;API Management&lt;/strong&gt;, click &lt;strong&gt;APIs&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Choose your specification. If you are using &lt;a href="https://github.com/domaindrivendev/Swashbuckle.AspNetCore"&gt;Swashbuckle&lt;/a&gt; library in your API that means you already have &lt;a href="https://swagger.io/specification/"&gt;OpenAPI specification&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;On the &lt;strong&gt;Create from OpenAPI specification&lt;/strong&gt; page, paste the swagger JSON URL of your API. The other fields will be populated according to your API.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, you can test the gateway through the &lt;strong&gt;Test&lt;/strong&gt; tab on the API details page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Subscriptions
&lt;/h1&gt;

&lt;p&gt;A subscription is like authenticating a client with a public key which can be transferred through in the headers or in the query string. The subscription can be scoped to All APIs, a single API or a group of APIs (called a product).&lt;/p&gt;

&lt;p&gt;The unique subscription keys can be regenerated at any time. Every subscription has two keys, a primary and a secondary to avoid downtime.&lt;/p&gt;

&lt;p&gt;The default header name is &lt;code&gt;Ocp-Apim-Subscription-Key&lt;/code&gt;, and the default query string is &lt;code&gt;subscription-key&lt;/code&gt;. If the key is not passed in the header, or as a query string in the URL, you'll get a &lt;strong&gt;401 Access Denied&lt;/strong&gt; response from the API gateway.&lt;/p&gt;

&lt;h1&gt;
  
  
  Policies
&lt;/h1&gt;

&lt;p&gt;In Azure API Management, administrators can use policies to alter the behavior of APIs through configuration. Policies execute at four different times:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inbound&lt;/strong&gt;: These policies execute when a request is received from a client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: These policies execute before a request is forwarded to a managed API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outbound&lt;/strong&gt;: These policies execute before a response is sent to a client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;On-Error&lt;/strong&gt;: These policies execute when an exception is raised.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is one more scope in addition to subscription scopes for policies and it is operation policy scope. We can determine order of the policies. If we place &lt;code&gt;&amp;lt;base /&amp;gt;&lt;/code&gt; tag before a policy that means higher policies will be applied first and vice versa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Commonly used policies
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Check HTTP header&lt;/li&gt;
&lt;li&gt;Limit call rate by subscription&lt;/li&gt;
&lt;li&gt;Restrict caller IP's&lt;/li&gt;
&lt;li&gt;Authenticate&lt;/li&gt;
&lt;li&gt;CORS&lt;/li&gt;
&lt;li&gt;JSONP&lt;/li&gt;
&lt;li&gt;Convert XML to JSON&lt;/li&gt;
&lt;li&gt;Rewrite URL&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cache policy
&lt;/h2&gt;

&lt;p&gt;By caching the compiled responses we can reduce processing time in our APIs and respond faster. We can add an outbound policy to cache the responses and an inbound policy to check if there is a cached response for the current request. You can see these two policies in the example below which is using a &lt;code&gt;vary-by-query-parameter&lt;/code&gt; tag to store separate responses per id in a query string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;policies&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;inbound&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;cache-lookup&lt;/span&gt; &lt;span class="na"&gt;vary-by-developer=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt; &lt;span class="na"&gt;vary-by-developer-groups=&lt;/span&gt;&lt;span class="s"&gt;"false"&lt;/span&gt;
        &lt;span class="na"&gt;downstream-caching-type=&lt;/span&gt;&lt;span class="s"&gt;"none"&lt;/span&gt;
        &lt;span class="na"&gt;must-revalidate=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt; &lt;span class="na"&gt;caching-type=&lt;/span&gt;&lt;span class="s"&gt;"internal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;vary-by-query-parameter&amp;gt;&lt;/span&gt;id&lt;span class="nt"&gt;&amp;lt;/vary-by-query-parameter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/cache-lookup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/inbound&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;backend&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/backend&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;outbound&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;cache-store&lt;/span&gt; &lt;span class="na"&gt;duration=&lt;/span&gt;&lt;span class="s"&gt;"60"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/outbound&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/on-error&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/on-error&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/policies&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;vary-by-developer&lt;/code&gt; attribute is separating responses according to the subscription key.&lt;/p&gt;

&lt;p&gt;As you can already notice, the caching type for this example is internal. We can use an external caching service as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add an external cache
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Create an Azure Cache for Redis resource.&lt;/li&gt;
&lt;li&gt;Go to your API Management service and click &lt;strong&gt;External cache&lt;/strong&gt; under &lt;strong&gt;Settings&lt;/strong&gt; and then click &lt;strong&gt;+ Add&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Choose your Redis cache instance and a location to use from. The other fields will be populated.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;APIs&lt;/strong&gt; under &lt;strong&gt;API Management&lt;/strong&gt; an then select the API and click the pencil next to the &lt;strong&gt;cache-lookup&lt;/strong&gt; to edit the policy.&lt;/li&gt;
&lt;li&gt;Change caching type from &lt;strong&gt;Internal&lt;/strong&gt; to &lt;strong&gt;External&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can test your API in the &lt;strong&gt;Test&lt;/strong&gt; tab to see if it is giving unchanged results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Remove unnecessary info from response header
&lt;/h2&gt;

&lt;p&gt;ASP.NET add a &lt;code&gt;X-Powered-By: ASP.NET&lt;/code&gt; header to our APIs by default but this could allow a malicious user to attempt to exploit any bugs known for the technology stack. We can remove this header from a response by adding &lt;code&gt;set-header&lt;/code&gt; policy to outbound as in the example below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;outbound&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;set-header&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"X-Powered-By"&lt;/span&gt; &lt;span class="na"&gt;exists-action=&lt;/span&gt;&lt;span class="s"&gt;"delete"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/outbound&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Replace content with a transformation policy
&lt;/h2&gt;

&lt;p&gt;If we build an API with the &lt;a href="https://restfulapi.net/hateoas/"&gt;HATEOAS&lt;/a&gt; constraint, that means we have links in the responses. Since the gateway is overriding the URLs, we may need to replace the links in the response body. We can do it by adding &lt;code&gt;&amp;lt;redirect-content-urls /&amp;gt;&lt;/code&gt; tag to the &lt;code&gt;&amp;lt;outbound&amp;gt;&lt;/code&gt; element as below;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;outbound&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;set-header&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"X-Powered-By"&lt;/span&gt; &lt;span class="na"&gt;exists-action=&lt;/span&gt;&lt;span class="s"&gt;"delete"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;redirect-content-urls&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/outbound&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Limit call rate by subscription
&lt;/h2&gt;

&lt;p&gt;If we place the &lt;code&gt;rate-limit-by-key&lt;/code&gt; tag inside the &lt;code&gt;inbound&lt;/code&gt; element, it will limit the call rate by subscription. A subscription can call this API 10 times in 60 seconds and only the successful responses are counted.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;inbound&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;rate-limit-by-key&lt;/span&gt; &lt;span class="na"&gt;calls=&lt;/span&gt;&lt;span class="s"&gt;"10"&lt;/span&gt;
              &lt;span class="na"&gt;renewal-period=&lt;/span&gt;&lt;span class="s"&gt;"60"&lt;/span&gt;
              &lt;span class="na"&gt;increment-condition=&lt;/span&gt;&lt;span class="s"&gt;"@(context.Response.StatusCode == 200)"&lt;/span&gt;
              &lt;span class="na"&gt;counter-key=&lt;/span&gt;&lt;span class="s"&gt;"@(context.Subscription.Id)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/inbound&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Validate a certificate to allow requests
&lt;/h2&gt;

&lt;p&gt;If we want to use certificate authentication in our API gateway, we can validate it by an inbound policy.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Under &lt;strong&gt;Settings&lt;/strong&gt;, click &lt;strong&gt;Custom domains&lt;/strong&gt; in your API Management service.&lt;/li&gt;
&lt;li&gt;Toggle &lt;strong&gt;Yes&lt;/strong&gt; for the &lt;strong&gt;Request client certificate&lt;/strong&gt; option, and then click &lt;strong&gt;Save&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Replace the &lt;code&gt;&amp;lt;inbound&amp;gt;&lt;/code&gt; node of the policy file with the following XML, while replacing &lt;code&gt;desired-thumbprint&lt;/code&gt; part with your certificate thumbprint;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;inbound&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;choose&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;when&lt;/span&gt; &lt;span class="na"&gt;condition=&lt;/span&gt;&lt;span class="s"&gt;"@(context.Request.Certificate == null || 
        context.Request.Certificate.Thumbprint != "&lt;/span&gt;&lt;span class="err"&gt;desired-thumbprint")"&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;return-response&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;set-status&lt;/span&gt; &lt;span class="na"&gt;code=&lt;/span&gt;&lt;span class="s"&gt;"403"&lt;/span&gt; &lt;span class="na"&gt;reason=&lt;/span&gt;&lt;span class="s"&gt;"Invalid client certificate"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/return-response&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/when&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/choose&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;base&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/inbound&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Please, write the policies that you find useful in the comments.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>serverless</category>
      <category>devops</category>
      <category>apigateway</category>
    </item>
    <item>
      <title>Azure Durable Functions</title>
      <dc:creator>Olcay Bayram</dc:creator>
      <pubDate>Fri, 31 Jan 2020 10:56:27 +0000</pubDate>
      <link>https://dev.to/olcay/azure-durable-functions-ipm</link>
      <guid>https://dev.to/olcay/azure-durable-functions-ipm</guid>
      <description>&lt;p&gt;Durable Functions is an extension of Azure Functions that enables you to perform long-lasting, stateful operations in Azure. Azure provides the infrastructure for maintaining state information. You can use Durable Functions to orchestrate a long-running workflow. Using this approach, you get all the benefits of a serverless hosting model, while letting the Durable Functions framework take care of activity monitoring, synchronization, and runtime concerns.&lt;/p&gt;

&lt;p&gt;Suppose your e-commerce company has a warehouse and there is a staff to ship products. We want to automate the process, but still involve humans. We can implement &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-phone-verification"&gt;human interaction&lt;/a&gt; pattern by using an orchestrator function. The orchestrator uses a &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-timers?tabs=csharp"&gt;durable timer&lt;/a&gt; to request approval. The orchestrator escalates if timeout occurs. The orchestrator waits for an &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-external-events?tabs=csharp"&gt;external event&lt;/a&gt;, such as a notification that's generated by a human interaction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dm1vPgTU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3o8xgyehgzfxirn62696.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dm1vPgTU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/3o8xgyehgzfxirn62696.png" alt="Azure Durable Functions Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a function app project
&lt;/h2&gt;

&lt;p&gt;If you did not create a function app on Visual Studio before, please follow the steps on &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-create-first-csharp"&gt;Create your first durable function in C#&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Copy the code below to your &lt;em&gt;function.cs&lt;/em&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="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&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;System.Collections.Generic&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;System.Net.Http&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;System.Threading&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;System.Threading.Tasks&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;Microsoft.Azure.WebJobs&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;Microsoft.Azure.WebJobs.Extensions.Http&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;Microsoft.Extensions.Logging&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;OlcayFunctionAppSample&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;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DurableFunction&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DurableFunction_Orchestrator"&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;static&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;RunOrchestrator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrchestrationTrigger&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;DurableOrchestrationContext&lt;/span&gt; &lt;span class="n"&gt;context&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;outputs&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;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

            &lt;span class="k"&gt;using&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;timeoutCts&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;CancellationTokenSource&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;expiration&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CurrentUtcDateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSeconds&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;timeoutTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateTimer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expiration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeoutCts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;shipTask&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitForExternalEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Event_Ship"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Wait until one of the tasks is completed&lt;/span&gt;
                &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="n"&gt;winner&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;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAny&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shipTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeoutTask&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;winner&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;shipTask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Event raised&lt;/span&gt;
                    &lt;span class="n"&gt;outputs&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;await&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallActivityAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"DurableFunction_Ship"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"shipped"&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="c1"&gt;// Timeout expired&lt;/span&gt;
                    &lt;span class="n"&gt;outputs&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;await&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallActivityAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;"DurableFunction_Escalate"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Head of department"&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;timeoutTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsCompleted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// All pending timers must be complete or canceled before the function exits.&lt;/span&gt;
                    &lt;span class="n"&gt;timeoutCts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Cancel&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;return&lt;/span&gt; &lt;span class="n"&gt;outputs&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;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DurableFunction_Ship"&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;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Ship&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;ActivityTrigger&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;activityInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"The order is &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;activityInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;$"The order is &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;activityInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DurableFunction_Escalate"&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;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;Escalate&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;ActivityTrigger&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;activityInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"The order is escalated to &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;activityInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;$"The order is escalated to &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;activityInput&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&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;span class="nf"&gt;FunctionName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DurableFunction_HttpStart"&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;static&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;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;HttpStart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpTrigger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AuthorizationLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Anonymous&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"post"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
            &lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;OrchestrationClient&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;DurableOrchestrationClient&lt;/span&gt; &lt;span class="n"&gt;starter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;)&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;instanceId&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;starter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNewAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"DurableFunction_Orchestrator"&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="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogInformation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Started orchestration with ID = '&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;instanceId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;'."&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;starter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateCheckStatusResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instanceId&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;h2&gt;
  
  
  Test the function locally
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Press &lt;strong&gt;F5&lt;/strong&gt; to start debugging.&lt;/li&gt;
&lt;li&gt;Copy the URL of your function from the Azure Functions runtime output.
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Wbsdx9Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/4r4p9hlarbqjh52zrp98.png" alt="Azure Functions Debugging"&gt;
&lt;/li&gt;
&lt;li&gt;Paste the URL &lt;code&gt;http://localhost:7071/api/DurableFunction_HttpStart&lt;/code&gt; into your browser's address bar and execute the request.&lt;/li&gt;
&lt;li&gt;Copy the URL value for &lt;code&gt;statusQueryGetUri&lt;/code&gt; and paste it in the browser's address bar and execute the request. If you do it on time, you will see &lt;em&gt;Pending&lt;/em&gt; or &lt;em&gt;Running&lt;/em&gt; as &lt;code&gt;runtimeStatus&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you wait enough to expire timeout task and refresh, the &lt;code&gt;runtimeStatus&lt;/code&gt; would be &lt;em&gt;Completed&lt;/em&gt; and an output message would be displayed as &lt;em&gt;The order is escalated to Head of department!&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;If you raise &lt;em&gt;ship&lt;/em&gt; event before the timeout expires, the &lt;code&gt;runtimeStatus&lt;/code&gt; would be &lt;em&gt;Completed&lt;/em&gt; and an output message would be displayed as &lt;em&gt;The order is shipped!&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Raising an event
&lt;/h3&gt;

&lt;p&gt;Copy the URL value for &lt;code&gt;sendEventPostUri&lt;/code&gt;, replace &lt;code&gt;{eventName}&lt;/code&gt; with &lt;code&gt;Event_Ship&lt;/code&gt; and run the command below with the the URL on command prompt.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;curl --request POST 'http://localhost:7071/runtime/webhooks/durabletask/instances/{instanceId}/raiseEvent/Event_Ship' \&lt;br&gt;
--header 'Content-Type: application/json' --data-raw ''&lt;/code&gt;&lt;/p&gt;

</description>
      <category>azure</category>
      <category>serverless</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
