<?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: Sohaib Tariq</title>
    <description>The latest articles on DEV Community by Sohaib Tariq (@sohaibtariq).</description>
    <link>https://dev.to/sohaibtariq</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%2F365644%2Facfc02b5-2c9b-4100-8adc-608b1946fc99.png</url>
      <title>DEV Community: Sohaib Tariq</title>
      <link>https://dev.to/sohaibtariq</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sohaibtariq"/>
    <language>en</language>
    <item>
      <title>Show Dev: Here's how we made AI 2x faster at integrating APIs</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Thu, 02 Apr 2026 15:36:34 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/show-dev-heres-how-we-made-ai-2x-faster-at-integrating-apis-3c34</link>
      <guid>https://dev.to/sohaibtariq/show-dev-heres-how-we-made-ai-2x-faster-at-integrating-apis-3c34</guid>
      <description>&lt;p&gt;We ran an experiment with our team:&lt;/p&gt;

&lt;p&gt;Each of us asked Cursor to integrate the PayPal API into an e-commerce app multiple times.&lt;/p&gt;

&lt;p&gt;Here are the results across all of our attempts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;13% of the attempts pulled in a deprecated PayPal SDK&lt;/li&gt;
&lt;li&gt;87% of the attempts generated API calls based on deprecated PayPal documentation&lt;/li&gt;
&lt;li&gt;0% of the attempts used the current, official PayPal Server SDK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's the interesting part, PayPal provides official API docs and SDKs for their APIs. The AI just never used them. Instead, it cobbled together code from blog posts, Stack Overflow answers, and stale training data (since PayPal is such a well-known API).&lt;/p&gt;

&lt;p&gt;This isn't just a PayPal problem. There are millions of APIs out there. Their docs change. SDKs evolve. New API versions come out.&lt;/p&gt;

&lt;p&gt;When an AI assistant tries to integrate an API using Web Search or model memory alone, mistakes are almost inevitable. Developers end up spending more time debugging AI output than they saved by using AI in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we solved this problem
&lt;/h2&gt;

&lt;p&gt;We built &lt;strong&gt;Context Plugins&lt;/strong&gt;: given an OpenAPI spec, we generate SDKs and an MCP server that exposes structured API context to AI coding assistants.&lt;/p&gt;

&lt;p&gt;This gives tools like Cursor access to comprehensive, up-to-date API context (including SDK documentation and API integration patterns), instead of relying on outdated training data or code scraped from GitHub.&lt;/p&gt;

&lt;p&gt;Here's how it works:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An API provider uploads their OpenAPI spec to APIMatic&lt;/li&gt;
&lt;li&gt;We generate high-quality SDKs in multiple programming languages&lt;/li&gt;
&lt;li&gt;We generate an MCP server with tools and prompts that expose language-specific SDK context, optimized for LLMs&lt;/li&gt;
&lt;li&gt;Developers install the MCP server in their IDE (Cursor, Claude Code, or GitHub Copilot)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When a developer asks to integrate an API, the coding assistant queries the MCP server, retrieves the required context (auth flows, integration patterns, latest SDK version, SDK interfaces), and generates code using the official SDK — not guesswork.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/XMTb2Go1rZA"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Here is a key insight we picked up along the way: &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAPI specs or API Reference docs alone aren't enough context for AI agents.&lt;/strong&gt; They describe endpoints/operations and schemas, but the AI still has to infer how to handle authentication, pagination, error handling, and then translate all of that into working code. That's a long chain of inference, and every extra step is another place things could go wrong. &lt;/p&gt;

&lt;p&gt;SDKs and SDK context cuts that chain short — much of the complexity is already wrapped in the library, so the model figures out which method to call and how to wire it up, instead of writing the entire integration from scratch.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
We've just launched a pilot with PayPal, it's live on the &lt;a href="https://developer.paypal.com/serversdk/java/getting-started/how-to-get-started?ide=claudeCode&amp;amp;isContextPlugin=true" rel="noopener noreferrer"&gt;PayPal Developer Portal&lt;/a&gt;. Check it out!&lt;br&gt;

&lt;/div&gt;


&lt;h2&gt;
  
  
  The benchmarks
&lt;/h2&gt;

&lt;p&gt;We ran 4 controlled experiments on two real-world .NET applications, &lt;a href="https://github.com/nopSolutions/nopCommerce" rel="noopener noreferrer"&gt;nopCommerce&lt;/a&gt; (mature e-commerce platform) and &lt;a href="https://github.com/dotnet/eshop" rel="noopener noreferrer"&gt;eShop&lt;/a&gt; (Microsoft's .NET reference app). &lt;/p&gt;

&lt;p&gt;We ran the same task across the same IDE and models — with and without Context Plugins.&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%2F20qoztkj853r8xkx0k3z.webp" 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%2F20qoztkj853r8xkx0k3z.webp" alt="Integrating APIs with context plugins" width="800" height="431"&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.amazonaws.com%2Fuploads%2Farticles%2Fuqj0p2a7ysbmbxl6iinh.webp" 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%2Fuqj0p2a7ysbmbxl6iinh.webp" alt="Integrating APIs without context plugins" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Aggregate results across all 4 experiments:
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Without Plugin&lt;/th&gt;
&lt;th&gt;With Plugin&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Errors&lt;/td&gt;
&lt;td&gt;16 avg&lt;/td&gt;
&lt;td&gt;1.5 avg&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;↓ 91%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Prompts needed&lt;/td&gt;
&lt;td&gt;34 avg&lt;/td&gt;
&lt;td&gt;15.5 avg&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;↓ 54%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tokens consumed&lt;/td&gt;
&lt;td&gt;57M avg&lt;/td&gt;
&lt;td&gt;20M avg&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;↓ 65%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Manual fixes&lt;/td&gt;
&lt;td&gt;2.75 avg&lt;/td&gt;
&lt;td&gt;0 avg&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;↓ 100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What went wrong without the plugin (real examples):
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hallucinated that SDK classes didn't exist&lt;/strong&gt; — the agent decided &lt;code&gt;OAuthAuthorizationController&lt;/code&gt; wasn't in the SDK and wrote a custom replacement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;29+ compile errors&lt;/strong&gt; from guessed model shapes, enums, and namespaces&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security vulnerabilities&lt;/strong&gt; — a URL injection allowed order capture on ID mismatch; &lt;code&gt;?paid=1&lt;/code&gt; query param triggered false payment approvals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selected deprecated SDK versions&lt;/strong&gt; despite being told to use v2.0.0&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;33% hallucination rate&lt;/strong&gt; when relying on web search for API knowledge&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What happened with the plugin:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Zero hallucinations across all experiments&lt;/li&gt;
&lt;li&gt;Zero manual fixes required to the generated code&lt;/li&gt;
&lt;li&gt;Agent verified its knowledge proactively via MCP tool calls before writing code&lt;/li&gt;
&lt;li&gt;Clean compilation from the first attempt in 3 of 4 experiments&lt;/li&gt;
&lt;li&gt;Eliminated 200+ lines of manual HTTP boilerplate in the eShop integration&lt;/li&gt;
&lt;li&gt;AI completed the integration 2x faster on average&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The full case study with detailed experiment logs is here: &lt;a href="https://www.apimatic.io/product/context-plugins/case-study?utm_campaign=40484888-Context%20Plugins&amp;amp;utm_source=dev" rel="noopener noreferrer"&gt;Context Plugins Case Study&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;We've published Context Plugins for a few APIs in our Product showcase, this is the quickest way to try them out:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.apimatic.io/product/context-plugins/showcase?utm_campaign=40484888-Context%20Plugins&amp;amp;utm_source=dev" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Try the Context Plugins Showcase&lt;/a&gt;
&lt;/p&gt;

&lt;p&gt;Pick an API (PayPal, Twilio, Stripe, Google Maps, Spotify, Slack, Adyen, and more), install the MCP server in your IDE, and start building. &lt;/p&gt;

&lt;h2&gt;
  
  
  What we learned from developers trying this
&lt;/h2&gt;

&lt;p&gt;A few patterns emerged from our benchmarks and early user tests:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Trust follows grounding.&lt;/strong&gt; Developers feel significantly better about AI output when the model is visibly pulling SDK method names and library docs, versus when it looks like it's piecing things together from web search or training data. The source of context matters as much as the correctness of the output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "dual responsibility" problem is real.&lt;/strong&gt; When an AI agent has to simultaneously research an API &lt;em&gt;and&lt;/em&gt; implement the integration, the quality of both suffers. Context Plugins separate those concerns — the MCP server brings authoritative API knowledge, the agent handles the coding. This division of labour consistently produces better results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developers have already hacked together solutions to this problem.&lt;/strong&gt; Developers write their own skills and AGENT.md files to try and get their AI agents to write correct integration code for the APIs they use. Doing this involves trial and error, and they continuously need to update their local context as the API evolves.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;I'd love to hear from the community:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's the worst AI-generated API integration bug you've encountered? We're collecting failure patterns to improve our context coverage. Horror stories are especially welcome 🙃.&lt;/li&gt;
&lt;li&gt;How are you currently handling API context for your coding assistants? AGENTS.md files? Custom MCP servers? Something else?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>showdev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Have you invested in crypto yet?</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Thu, 18 Feb 2021 08:49:10 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/have-you-invested-in-crypto-yet-4ifc</link>
      <guid>https://dev.to/sohaibtariq/have-you-invested-in-crypto-yet-4ifc</guid>
      <description>&lt;p&gt;The crypto space is buzzing right now. Bitcoin broke past $50,000 and most AltCoins are at all time high levels. Has this boom convinced you to invest yet ? Or are you waiting for the next dip to buy into crypto ? Or are you still skeptical about cryptocurrencies? &lt;br&gt;
Lets get a discussion going, there's not a whole lot about crypto on DEV. &lt;/p&gt;

&lt;p&gt;PS: I noticed that some crypto associated tags exist on DEV but I am unable to use them in my post. Does DEV discourage discussions around crypto?  &lt;/p&gt;

</description>
      <category>discuss</category>
      <category>watercooler</category>
    </item>
    <item>
      <title>Why do you use Dev.to ?</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Wed, 27 Jan 2021 07:44:05 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/why-do-you-use-dev-to-4pa2</link>
      <guid>https://dev.to/sohaibtariq/why-do-you-use-dev-to-4pa2</guid>
      <description>&lt;p&gt;What do you aim to accomplish on dev? are you here for the tutorials? career advice? are you hoping to build connections with people in the tech industry or are you here to build a following? Or maybe you're just here for fun ? 😃 &lt;br&gt;
Let me know in the comments below.   &lt;/p&gt;

</description>
      <category>watercooler</category>
      <category>discuss</category>
      <category>developer</category>
      <category>help</category>
    </item>
    <item>
      <title>What are the best non-programming books you have read recently ?</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Mon, 25 Jan 2021 12:11:11 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/what-are-the-best-non-programming-books-you-have-read-recently-3jn8</link>
      <guid>https://dev.to/sohaibtariq/what-are-the-best-non-programming-books-you-have-read-recently-3jn8</guid>
      <description>&lt;p&gt;I'm looking for book recommendations to add to my reading list. I would be delighted to learn which non-technical books the dev community has been reading. &lt;br&gt;
PS: No restrictions on topic/genre, anything goes😊.&lt;/p&gt;

</description>
      <category>help</category>
      <category>watercooler</category>
      <category>discuss</category>
    </item>
    <item>
      <title>What is your 1 tip for new writers on dev ?</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Thu, 21 Jan 2021 12:10:07 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/what-is-your-1-tip-for-new-writers-on-dev-i03</link>
      <guid>https://dev.to/sohaibtariq/what-is-your-1-tip-for-new-writers-on-dev-i03</guid>
      <description>&lt;p&gt;Dev.to is a big community, with more people joining everyday. What tip would you like to give, that could help new users make the most of this platform ? &lt;br&gt;
Your tips could be around type of content to write, how to optimize content for visibility, how to interact with people, how to engage the dev audience or anything that you have found useful in you time on dev. &lt;br&gt;
THANKS!&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>watercooler</category>
      <category>help</category>
      <category>writing</category>
    </item>
    <item>
      <title>Deploying a .Net Core Console app as Azure WebJob</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Thu, 21 Jan 2021 11:41:44 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/deploying-a-net-core-console-app-as-azure-webjob-1n18</link>
      <guid>https://dev.to/sohaibtariq/deploying-a-net-core-console-app-as-azure-webjob-1n18</guid>
      <description>&lt;p&gt;If you are using Azure App Service, WebJobs are a great way of running background tasks without provisioning new resources or incurring additional costs. &lt;br&gt;
However, Deploying a Console app as a WebJob to Azure is not the smoothest of experiences, specially if you want to setup Continuous Deployment. &lt;br&gt;
In this post I'll take you through the entire process, and hopefully save you some time. &lt;/p&gt;
&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;An Azure App Service instance can host multiple WebJobs. WebJobs can be deployed by placing their binaries at a predefined location, either manually, &lt;strong&gt;OR&lt;/strong&gt; programmatically using a build script. &lt;/p&gt;

&lt;p&gt;Azure supports two type of WebJobs:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Triggered&lt;/li&gt;
&lt;li&gt;Continuous&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The default location for deploying triggered WebJobs is:&lt;br&gt;
&lt;code&gt;d:\home\site\wwwroot\app_data\jobs\triggered\&amp;lt;name of job&amp;gt;&lt;/code&gt; &lt;br&gt;
The default location for deploying continuous WebJobs is:&lt;br&gt;
&lt;code&gt;d:\home\site\wwwroot\app_data\jobs\continuous\&amp;lt;name of job&amp;gt;&lt;/code&gt;  &lt;/p&gt;
&lt;h2&gt;
  
  
  Manual Deployment
&lt;/h2&gt;

&lt;p&gt;If you want to get up and running quickly and want to forego CI/CD, you can manually deploy your console app as a WebJob using the Kudu Console.  &lt;/p&gt;

&lt;p&gt;Based on the type of WebJob, create a directory structure for your code according to the path shown above and upload your binaries to it. &lt;br&gt;
If the entry-point for your application is an .exe file, you're good to go, however, if you are using .dll files, you may have to create a &lt;code&gt;run.exe&lt;/code&gt; or &lt;code&gt;run.cmd&lt;/code&gt; file to allow Azure to recognize which file to run.&lt;br&gt;
Your &lt;em&gt;run.cmd&lt;/em&gt; file may be as simple as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;&lt;span class="kd"&gt;MyWebjob&lt;/span&gt;.dll
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Continuous Deployment with Kudu App Service
&lt;/h2&gt;

&lt;p&gt;There are multiple methods of setting up CI/CD for Azure App Service. For the purpose of this tutorial, we will use Kudu App Service. However, you will easily be able to translate the following steps to the platform of your choice.&lt;/p&gt;

&lt;p&gt;When you set up Continuous Deployment for an App Service with Kudu, a deployment script is generated automatically. This script handles the setup and deployment of your application. &lt;br&gt;
You can modify this deployment script in order to specify where your WebJob binaries ought to be published. &lt;/p&gt;

&lt;p&gt;To access the default deployment script used by Kudu, open the &lt;em&gt;Tools&lt;/em&gt; menu in the Kudu Debug Console and select '&lt;em&gt;Download Deployment Script&lt;/em&gt;'. &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%2Fi%2Fwxeeiw4ab0ex1kmyrwjl.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%2Fi%2Fwxeeiw4ab0ex1kmyrwjl.png" alt="Kudu Console" width="242" height="214"&gt;&lt;/a&gt;&lt;br&gt;
The downloaded folder contains 2 files, &lt;em&gt;.deployment&lt;/em&gt; and &lt;em&gt;deploy.cmd&lt;/em&gt;. Add both files to the root folder of your repository so that you can modify and commit them with your code.&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%2Fi%2Fqr06ekn4bxp5gzn44xcj.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%2Fi%2Fqr06ekn4bxp5gzn44xcj.png" alt="Alt Text" width="214" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The file we will be editing is the &lt;strong&gt;deploy.cmd&lt;/strong&gt; file.&lt;br&gt;&lt;br&gt;
If this is your first time working with a deployment script, do not feel overwhelmed, we will only be editing a small part of it.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Deployment Script
&lt;/h3&gt;

&lt;p&gt;As you will see in the &lt;strong&gt;Deployment&lt;/strong&gt; section of the attached script, MSBuild is used to restore, build and publish the code for your App Service.&lt;br&gt;&lt;br&gt;
You will need to add a similar step for your Console App project with a slight modification:&lt;br&gt;&lt;br&gt;
use the &lt;em&gt;OutputPath&lt;/em&gt; option to specify the location where the binaries for your WebJob need to go. This example is for a triggered WebJob so we will set this option to &lt;code&gt;"%DEPLOYMENT_TEMP%\app_data\jobs\triggered\AnalyticsEmail"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight batchfile"&gt;&lt;code&gt;@if &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%SCM_TRACE_LEVEL%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;NEQ&lt;/span&gt; &lt;span class="s2"&gt;"4"&lt;/span&gt; @echo &lt;span class="na"&gt;off&lt;/span&gt;

&lt;span class="c"&gt;:: ----------------------&lt;/span&gt;
&lt;span class="c"&gt;:: KUDU Deployment Script&lt;/span&gt;
&lt;span class="c"&gt;:: Version: 1.0.17&lt;/span&gt;
&lt;span class="c"&gt;:: ----------------------&lt;/span&gt;

&lt;span class="c"&gt;:: Prerequisites&lt;/span&gt;
&lt;span class="c"&gt;:: -------------&lt;/span&gt;

&lt;span class="c"&gt;:: Verify node.js installed&lt;/span&gt;
&lt;span class="nb"&gt;where&lt;/span&gt; &lt;span class="kd"&gt;node&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="kr"&gt;nul&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="kr"&gt;nul&lt;/span&gt;
&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="nv"&gt;%ERRORLEVEL%&lt;/span&gt; &lt;span class="kd"&gt;NEQ&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="kd"&gt;Missing&lt;/span&gt; &lt;span class="kd"&gt;node&lt;/span&gt;.js &lt;span class="kd"&gt;executable&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;please&lt;/span&gt; &lt;span class="kd"&gt;install&lt;/span&gt; &lt;span class="kd"&gt;node&lt;/span&gt;.js&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="kd"&gt;already&lt;/span&gt; &lt;span class="kd"&gt;installed&lt;/span&gt; &lt;span class="kd"&gt;make&lt;/span&gt; &lt;span class="kd"&gt;sure&lt;/span&gt; &lt;span class="kd"&gt;it&lt;/span&gt; &lt;span class="kd"&gt;can&lt;/span&gt; &lt;span class="kd"&gt;be&lt;/span&gt; &lt;span class="kd"&gt;reached&lt;/span&gt; &lt;span class="kd"&gt;from&lt;/span&gt; &lt;span class="kd"&gt;current&lt;/span&gt; &lt;span class="kd"&gt;environment&lt;/span&gt;.
  &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="kd"&gt;error&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;:: Setup&lt;/span&gt;
&lt;span class="c"&gt;:: -----&lt;/span&gt;

&lt;span class="nb"&gt;setlocal&lt;/span&gt; &lt;span class="na"&gt;enabledelayedexpansion&lt;/span&gt;

&lt;span class="kd"&gt;SET&lt;/span&gt; &lt;span class="kd"&gt;ARTIFACTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vm"&gt;%~dp0&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;..\artifacts

&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="kd"&gt;NOT&lt;/span&gt; &lt;span class="kd"&gt;DEFINED&lt;/span&gt; &lt;span class="kd"&gt;DEPLOYMENT_SOURCE&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;SET&lt;/span&gt; &lt;span class="kd"&gt;DEPLOYMENT_SOURCE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="vm"&gt;%~dp0&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;.
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="kd"&gt;NOT&lt;/span&gt; &lt;span class="kd"&gt;DEFINED&lt;/span&gt; &lt;span class="kd"&gt;DEPLOYMENT_TARGET&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;SET&lt;/span&gt; &lt;span class="kd"&gt;DEPLOYMENT_TARGET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;%ARTIFACTS%&lt;/span&gt;\wwwroot
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="kd"&gt;NOT&lt;/span&gt; &lt;span class="kd"&gt;DEFINED&lt;/span&gt; &lt;span class="kd"&gt;NEXT_MANIFEST_PATH&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="kd"&gt;SET&lt;/span&gt; &lt;span class="kd"&gt;NEXT_MANIFEST_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;%ARTIFACTS%&lt;/span&gt;\manifest

  &lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="kd"&gt;NOT&lt;/span&gt; &lt;span class="kd"&gt;DEFINED&lt;/span&gt; &lt;span class="kd"&gt;PREVIOUS_MANIFEST_PATH&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
    &lt;span class="kd"&gt;SET&lt;/span&gt; &lt;span class="kd"&gt;PREVIOUS_MANIFEST_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;%ARTIFACTS%&lt;/span&gt;\manifest
  &lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="kd"&gt;NOT&lt;/span&gt; &lt;span class="kd"&gt;DEFINED&lt;/span&gt; &lt;span class="kd"&gt;KUDU_SYNC_CMD&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  :: &lt;span class="kd"&gt;Install&lt;/span&gt; &lt;span class="kd"&gt;kudu&lt;/span&gt; &lt;span class="kd"&gt;sync&lt;/span&gt;
  &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="kd"&gt;Installing&lt;/span&gt; &lt;span class="kd"&gt;Kudu&lt;/span&gt; &lt;span class="kd"&gt;Sync&lt;/span&gt;
  &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="kd"&gt;npm&lt;/span&gt; &lt;span class="kd"&gt;install&lt;/span&gt; &lt;span class="kd"&gt;kudusync&lt;/span&gt; &lt;span class="na"&gt;-g --silent
  &lt;/span&gt;&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="nv"&gt;!ERRORLEVEL!&lt;/span&gt; &lt;span class="kd"&gt;NEQ&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="kd"&gt;error&lt;/span&gt;

  :: &lt;span class="kd"&gt;Locally&lt;/span&gt; &lt;span class="kd"&gt;just&lt;/span&gt; &lt;span class="kd"&gt;running&lt;/span&gt; &lt;span class="s2"&gt;"kuduSync"&lt;/span&gt; &lt;span class="kd"&gt;would&lt;/span&gt; &lt;span class="kd"&gt;also&lt;/span&gt; &lt;span class="kd"&gt;work&lt;/span&gt;
  &lt;span class="kd"&gt;SET&lt;/span&gt; &lt;span class="kd"&gt;KUDU_SYNC_CMD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;%appdata%&lt;/span&gt;\npm\kuduSync.cmd
&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::&lt;/span&gt;
&lt;span class="c"&gt;:: Deployment&lt;/span&gt;
&lt;span class="c"&gt;:: ----------&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="kd"&gt;Handling&lt;/span&gt; &lt;span class="kd"&gt;ASP&lt;/span&gt;.NET &lt;span class="kd"&gt;Core&lt;/span&gt; &lt;span class="kd"&gt;Web&lt;/span&gt; &lt;span class="kd"&gt;Application&lt;/span&gt; &lt;span class="kd"&gt;deployment&lt;/span&gt; &lt;span class="kd"&gt;with&lt;/span&gt; &lt;span class="kd"&gt;MSBuild16&lt;/span&gt;.

&lt;span class="c"&gt;:: 1. Restore, Build and publish&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nl"&gt;:ExecuteCmd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="vm"&gt;%MSBUILD&lt;/span&gt;&lt;span class="s2"&gt;_16_DIR&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="s2"&gt;\MSBuild.exe"&lt;/span&gt; &lt;span class="na"&gt;/restore &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%DEPLOYMENT_SOURCE%&lt;/span&gt;&lt;span class="s2"&gt;\AppServiceProject\AppServiceProject.csproj"&lt;/span&gt; &lt;span class="na"&gt;/p&lt;/span&gt;&lt;span class="nl"&gt;:DeployOnBuild&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kd"&gt;true&lt;/span&gt; &lt;span class="na"&gt;/p&lt;/span&gt;&lt;span class="nl"&gt;:configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kd"&gt;Release&lt;/span&gt; &lt;span class="na"&gt;/p&lt;/span&gt;&lt;span class="nl"&gt;:publishurl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%DEPLOYMENT_TEMP%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;%SCM_BUILD_ARGS%&lt;/span&gt;
&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="nv"&gt;!ERRORLEVEL!&lt;/span&gt; &lt;span class="kd"&gt;NEQ&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="kd"&gt;error&lt;/span&gt;

&lt;span class="c"&gt;::--------THIS IS THE CODE WE HAVE ADDED--------------&lt;/span&gt;
&lt;span class="c"&gt;::----------------------------------------------------&lt;/span&gt;

&lt;span class="c"&gt;:: 1. Restore, Build and publish WebJob&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nl"&gt;:ExecuteCmd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="vm"&gt;%MSBUILD&lt;/span&gt;&lt;span class="s2"&gt;_16_DIR&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="s2"&gt;\MSBuild.exe"&lt;/span&gt; &lt;span class="na"&gt;/restore &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%DEPLOYMENT_SOURCE%&lt;/span&gt;&lt;span class="s2"&gt;\WebJobProject\WebJobProject.csproj"&lt;/span&gt; &lt;span class="na"&gt;/p&lt;/span&gt;&lt;span class="nl"&gt;:DeployOnBuild&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kd"&gt;true&lt;/span&gt; &lt;span class="na"&gt;/p&lt;/span&gt;&lt;span class="nl"&gt;:configuration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kd"&gt;Release&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;&lt;span class="kd"&gt;OutputPath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%DEPLOYMENT_TEMP%&lt;/span&gt;&lt;span class="s2"&gt;\app_data\jobs\triggered\MyWebJob"&lt;/span&gt; &lt;span class="na"&gt;/p&lt;/span&gt;&lt;span class="nl"&gt;:publishurl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%DEPLOYMENT_TEMP%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;%SCM_BUILD_ARGS%&lt;/span&gt;

&lt;span class="c"&gt;::----------------------------------------------------&lt;/span&gt;
&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="nv"&gt;!ERRORLEVEL!&lt;/span&gt; &lt;span class="kd"&gt;NEQ&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="kd"&gt;error&lt;/span&gt;

&lt;span class="c"&gt;:: 4. Run web job deploy script&lt;/span&gt;
&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="kd"&gt;DEFINED&lt;/span&gt; &lt;span class="kd"&gt;WEBJOBS_DEPLOY_CMD&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nl"&gt;:ExecuteCmd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%WEBJOBS_DEPLOY_CMD%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;:: 2. KuduSync&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nl"&gt;:ExecuteCmd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%KUDU_SYNC_CMD%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="na"&gt;-v &lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt; &lt;span class="na"&gt;-f &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%DEPLOYMENT_TEMP%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="na"&gt;-t &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%DEPLOYMENT_TARGET%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="na"&gt;-n &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%NEXT_MANIFEST_PATH%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="na"&gt;-p &lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%PREVIOUS_MANIFEST_PATH%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="na"&gt;-i &lt;/span&gt;&lt;span class="s2"&gt;".git;.hg;.deployment;deploy.cmd"&lt;/span&gt;
&lt;span class="kd"&gt;IF&lt;/span&gt; &lt;span class="nv"&gt;!ERRORLEVEL!&lt;/span&gt; &lt;span class="kd"&gt;NEQ&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="kd"&gt;error&lt;/span&gt;

&lt;span class="c"&gt;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::&lt;/span&gt;
&lt;span class="k"&gt;goto&lt;/span&gt; &lt;span class="kd"&gt;end&lt;/span&gt;

&lt;span class="c"&gt;:: Execute command routine that will echo out when error&lt;/span&gt;
&lt;span class="nl"&gt;:ExecuteCmd&lt;/span&gt;
&lt;span class="nb"&gt;setlocal&lt;/span&gt;
&lt;span class="kd"&gt;set&lt;/span&gt; _CMD_&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nv"&gt;%_CMD_%&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;%ERRORLEVEL%&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="kd"&gt;NEQ&lt;/span&gt; &lt;span class="s2"&gt;"0"&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="kd"&gt;Failed&lt;/span&gt; &lt;span class="kd"&gt;exitCode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;%ERRORLEVEL%&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;%_CMD_%&lt;/span&gt;
&lt;span class="k"&gt;exit&lt;/span&gt; &lt;span class="na"&gt;/b &lt;/span&gt;&lt;span class="nv"&gt;%ERRORLEVEL%&lt;/span&gt;

&lt;span class="nl"&gt;:error&lt;/span&gt;
&lt;span class="nb"&gt;endlocal&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="kd"&gt;An&lt;/span&gt; &lt;span class="kd"&gt;error&lt;/span&gt; &lt;span class="kd"&gt;has&lt;/span&gt; &lt;span class="kd"&gt;occurred&lt;/span&gt; &lt;span class="kd"&gt;during&lt;/span&gt; &lt;span class="kd"&gt;web&lt;/span&gt; &lt;span class="kd"&gt;site&lt;/span&gt; &lt;span class="kd"&gt;deployment&lt;/span&gt;.
&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nl"&gt;:exitSetErrorLevel&lt;/span&gt;
&lt;span class="k"&gt;call&lt;/span&gt; &lt;span class="nl"&gt;:exitFromFunction&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="kr"&gt;nul&lt;/span&gt;

&lt;span class="nl"&gt;:exitSetErrorLevel&lt;/span&gt;
&lt;span class="k"&gt;exit&lt;/span&gt; &lt;span class="na"&gt;/b &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;

&lt;span class="nl"&gt;:exitFromFunction&lt;/span&gt;
&lt;span class="o"&gt;()&lt;/span&gt;

&lt;span class="nl"&gt;:end&lt;/span&gt;
&lt;span class="nb"&gt;endlocal&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="kd"&gt;Finished&lt;/span&gt; &lt;span class="kd"&gt;successfully&lt;/span&gt;.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Making this small change in the deployment script will allow the Kudu App Service to build and deploy your WebJob to the correct location.   &lt;/p&gt;



&lt;h2&gt;
  
  
  Schedule
&lt;/h2&gt;

&lt;p&gt;We are building a triggered WebJob so we must have some sort of trigger to to execute it. For this demonstration we will use a scheduled or time-triggered WebJob. This will require a cron expression. &lt;br&gt;
All we need to do is create a &lt;em&gt;settings.job&lt;/em&gt; file inside our Console App directory which contains a cron expression against a &lt;em&gt;schedule&lt;/em&gt; property.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"schedule"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0 */15 * * * *"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When our WebJob is deployed, the schedule property will automatically be used to set up a schedule for our WebJob &lt;/p&gt;

&lt;p&gt;Congratulations! you just deployed a WebJob to Azure and didnt have to pull your hair out while doing it. &lt;/p&gt;

&lt;p&gt;If you would like more information about how Kudu handles WebJobs, you can visit the kudu project &lt;a href="https://github.com/projectkudu/kudu/wiki/WebJobs" rel="noopener noreferrer"&gt;wiki&lt;/a&gt; on github.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>dotnet</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Azure Datafactory pricing simplified</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Mon, 14 Dec 2020 11:56:35 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/azure-datafactory-pricing-simplified-2jo7</link>
      <guid>https://dev.to/sohaibtariq/azure-datafactory-pricing-simplified-2jo7</guid>
      <description>&lt;p&gt;The first time I used Azure Data Factory, I found its pricing rather confusing. The pricing policy mentioned words like Read/Write Operations, Monitoring Operations and Activity Runs that did not make sense to me as a beginner. &lt;/p&gt;

&lt;p&gt;I was simply trying to decide whether it would be more efficient and cost effective to use Data Factory rather than hand coding a data pipeline. However, I ended up spending a good few hours going through the documentation and just to get a rough cost estimate.  &lt;/p&gt;

&lt;p&gt;Below is a very basic overview of what &lt;strong&gt;Azure Data Factory V2&lt;/strong&gt; pricing looks like for &lt;strong&gt;data pipelines&lt;/strong&gt;. This article should suffice for beginners who are trying out Data Factory pipelines for the first time, but please note that this is not a comprehensive overview, advanced users should refer to the official pricing documents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;p&gt;The first thing you need to know about Data Factory is that not only are you charged for executing pipelines, but also for developing/debugging and monitoring them.&lt;/p&gt;

&lt;p&gt;If you're looking to build data pipelines in Azure Data Factory, your cost will be split into two categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data Factory Operations&lt;/li&gt;
&lt;li&gt;Pipeline Orchestration and Execution&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Data Factory Operations
&lt;/h2&gt;

&lt;p&gt;This is the cost associated with developing and debugging pipelines. There are 2 types of Data Factory Operations, Read/Write and Monitoring.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Read/Write:&lt;/strong&gt;&lt;br&gt;
Every time you create/edit/delete a pipeline activity or a Data Factory entity such as a dataset, linked service, integration runtime or trigger, it counts towards your Data Factory Operations cost. These are billed at &lt;strong&gt;$0.50 per 50,000 operations&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Monitoring:&lt;/strong&gt;&lt;br&gt;
You can monitor each pipeline run and view the status for each individual activity. For each pipeline run, you can expect to retrieve one record for the pipeline and one record for each activity or trigger. &lt;br&gt;
For instance, you would be charged for 3 Monitoring activities if you debug a pipeline containing 2 activities. Monitoring activities are charged at &lt;strong&gt;$0.25 per 50,000 run records retrieved&lt;/strong&gt;      &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you may have concluded by now, Data Factory Operations are very inexpensive and for the most part, can be ignored for cost calculation purposes. The bulk of the cost comes from &lt;strong&gt;Pipeline Orchestration and Execution&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipeline Orchestration
&lt;/h2&gt;

&lt;p&gt;This refers to the cost of provisioning resources to run a pipeline and its associated activities. &lt;br&gt;
Data Factory provides users with the option of running pipelines on their own servers(&lt;em&gt;Self Hosted&lt;/em&gt;) or using a serverless integration runtime provided by Azure (&lt;em&gt;Azure Integration Runtime&lt;/em&gt;). Pricing is slightly different for both options. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Please note that Integration runtime charges are prorated by the minute and rounded up&lt;/em&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Self Hosted
&lt;/h4&gt;

&lt;p&gt;Every time you run a pipeline, you are charged for every activity and trigger inside that pipeline that is executed at a rate of &lt;strong&gt;$1.50 per 1000 Activity runs&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Azure Integration Runtime
&lt;/h4&gt;

&lt;p&gt;This option is slightly cheaper at &lt;strong&gt;$1 per 1000 runs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As an example, executing a pipeline with a trigger and two activities would be charged as 3 Activity runs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pipeline Execution
&lt;/h2&gt;

&lt;p&gt;This is the cost for the compute resources required for Pipeline execution. You can expect the bulk of the cost for Azure Data Factory pipelines to fall into this category.&lt;br&gt;
This is further divided into three sub-categories :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data movement activities&lt;/strong&gt; : This covers the cost of moving data across data stores in activities such as the copy data activity.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline activities&lt;/strong&gt; : Pipeline activities such as Lookup, Delete and schema operations during authoring (test connection, browse folder list and table list, get schema, and preview data).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External activities&lt;/strong&gt; : These are data transformation activities that execute in a computing environment such as Azure Databricks or Azure HDInsight. You can find a list of external activities &lt;a href="https://docs.microsoft.com/en-us/azure/data-factory/transform-data" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each sub-category has separate pricing, as listed below: &lt;/p&gt;

&lt;h4&gt;
  
  
  Self hosted
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Data movement : &lt;strong&gt;$0.10/hour&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Pipeline activities : &lt;strong&gt;$0.002/hour&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;External activities : &lt;strong&gt;$0.0001/hour&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Azure Integration runtime
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Data movement : &lt;strong&gt;$0.25/DIU-hour&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Pipeline activities : &lt;strong&gt;$0.005/hour&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;External activities : &lt;strong&gt;$0.00025/hour&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may have noticed that every sub-category is charged by the hour except Data movement which is charged in units of DIU-hour. &lt;/p&gt;

&lt;p&gt;"A Data Integration Unit (DIU) is a measure that represents the power of a single unit in Azure Data Factory. Power is a combination of CPU, memory, and network resource allocation."&lt;br&gt;
A DIU therefore, is a measure of the compute resources available to your pipeline. The more compute you allocate, the higher the cost. &lt;/p&gt;

&lt;p&gt;The copy activity is configured to use 4 DIUs by default but you can modify this to set the value between 2 and 256 depending on your performance requirements. You can find a detailed article on DIUs and how to optimize costs and performance for the copy activity &lt;a href="https://docs.microsoft.com/en-us/azure/data-factory/copy-activity-performance" rel="noopener noreferrer"&gt;here&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Azure Also charges for &lt;strong&gt;inactive pipelines&lt;/strong&gt; so its good to clean up after you're done.&lt;br&gt;
A pipeline is considered inactive if it has no associated trigger or any runs within the month. An inactive pipeline is charged at &lt;strong&gt;$0.80 per month&lt;/strong&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Thats all folks
&lt;/h2&gt;

&lt;p&gt;The above information should allow you to make a fair cost estimate for running data pipelines in Azure Data Factory V2. However please note that you may face additional charges such as egress charges if you are copying data from an Azure database OR compute charges if you choose to create custom activities. These charges vary from case to case and are out of the scope of this blog post. The &lt;a href="https://docs.microsoft.com/en-us/azure/data-factory/pricing-concepts" rel="noopener noreferrer"&gt;examples&lt;/a&gt; provided by Azure could prove useful in this regard.&lt;/p&gt;

</description>
      <category>azure</category>
      <category>database</category>
      <category>sql</category>
    </item>
    <item>
      <title>2 Apps that SUPERCHARGED my productivity during lockdown</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Wed, 28 Oct 2020 17:49:19 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/2-apps-that-supercharged-my-productivity-during-lockdown-4a6h</link>
      <guid>https://dev.to/sohaibtariq/2-apps-that-supercharged-my-productivity-during-lockdown-4a6h</guid>
      <description>&lt;p&gt;The Covid-19 pandemic was my first taste of working from home. The first week went by in a blur of confusion and while &lt;strong&gt;I didn't get much done, I still somehow ended up feeling exhausted and overworked.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;It was clear that over the years, &lt;strong&gt;my productivity as an engineer had become so deeply entangled with my presence in a professional setting&lt;/strong&gt;, that I would have to rethink my approach to work in order to get anything done.  &lt;/p&gt;

&lt;p&gt;   &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;The Problem&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Like any good engineer, &lt;strong&gt;I started out by breaking my problem into manageable chunks:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Tracking Time:&lt;/strong&gt; I needed a way to keep track of the &lt;strong&gt;number of hours of actual productive work&lt;/strong&gt; I did, minus the intermittent distractions that working from home brings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Tracking Tasks:&lt;/strong&gt; I needed to quickly &lt;strong&gt;write down&lt;/strong&gt; and &lt;strong&gt;prioritize&lt;/strong&gt; all the &lt;strong&gt;tasks that were discussed in the multitude of zoom calls&lt;/strong&gt;. In addition to that, I also needed to keep track of &lt;strong&gt;small tasks that were weighing on my mind&lt;/strong&gt; like following up on messages/emails I had sent out or points I needed to discuss with particular co-workers when they became available.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;The Solution&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;After some research and trying out a bunch of different apps, I settled on 2 that would solve both of the aforementioned problems: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;a href="https://www.toggl.com/track/" rel="noopener noreferrer"&gt;Toggl track&lt;/a&gt; (formerly toggl)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.onenote.com" rel="noopener noreferrer"&gt;OneNote&lt;/a&gt; &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;My &lt;strong&gt;criteria&lt;/strong&gt; was simple, I wanted a &lt;strong&gt;quick and dirty solution&lt;/strong&gt; to my problems that was going to be &lt;strong&gt;inexpensive&lt;/strong&gt; or, even better, &lt;strong&gt;FREE&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Toggl track&lt;/strong&gt;
&lt;/h2&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%2Fdhg4o26j90g11cfnjirb.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%2Fdhg4o26j90g11cfnjirb.png" alt="toggl.PNG" width="800" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What I loved about toggl is &lt;strong&gt;how easy it is to get up and running&lt;/strong&gt; and the fact that it has a  &lt;strong&gt;useable free tier&lt;/strong&gt;, unlike many freemium apps these days.&lt;br&gt;
Toggl comes with mobile, desktop and web apps with real time data syncing between them. &lt;strong&gt;Oh and did I mention, its free !&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I set up 3 very basic projects on toggl : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;work&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;work break&lt;/strong&gt; (for when I took a coffee break or phone break or watching random youtube videos break; while working)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;personal productivity&lt;/strong&gt; (non-work, but productive stuff, such as writing this article)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These enabled me to track just enough of my time to make me &lt;strong&gt;accountable and productive without it feeling like a chore.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;OneNote&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Chances are, you've probably used/ heard of OneNote before. But did you know you can make &lt;strong&gt;kanban boards in OneNote&lt;/strong&gt; ? ... well sort of. &lt;/p&gt;

&lt;p&gt;That was a game changer for me. &lt;/p&gt;

&lt;p&gt;Overnight OneNote went from being an app I occasionally used for note taking to a staple app that always remains open on my laptop.  &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;blockquote&gt;
&lt;h2&gt;
  
  
  Sorry trello, you have been replaced.
&lt;/h2&gt;
&lt;/blockquote&gt;

&lt;p&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%2Fzxz903t746d1vf9921q5.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%2Fzxz903t746d1vf9921q5.gif" alt="onenote-capture.gif" width="1011" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With three columns set up for &lt;strong&gt;"Waiting"&lt;/strong&gt;, &lt;strong&gt;"Todo"&lt;/strong&gt; and &lt;strong&gt;"Complete"&lt;/strong&gt; items, I was able to build a very simplistic task tracking system that works for me. &lt;/p&gt;

&lt;p&gt;I can jot down tasks during meetings in the "Waiting" section while they come in thick and fast. There is no limit on the length and type of content I can add to a task so &lt;strong&gt;I can mix text, images and doodles&lt;/strong&gt;. Then, using OneNote's convenient ability to drag and drop bullet points, I can move the ones I want to work on into the "Todo" section. &lt;/p&gt;

&lt;p&gt;Once done, I can simply drag a task, along with all associated data over to the "Complete" section. If I want to record the time at which a particular item is completed, a timestamp is just a right-click away.&lt;/p&gt;

&lt;p&gt;The sheer simplicity of using OneNote for task tracking is just mind blowing for me. It makes me wonder why more people don't use it, &lt;strong&gt;specially since its free&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;tl;dr&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;Using OneNote and Toggl track has allowed me to &lt;em&gt;reach&lt;/em&gt;, or dare I say, &lt;em&gt;surpass&lt;/em&gt; my prior levels of productivity. I'm feeling a lot less stressed out because I don't have to worry about remembering small tasks. I can navigate the distractions that come with working from home, satisfied in the knowledge that I wont forget anything. And at the end of the day, I'm no longer left wondering about where all the time went.&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;PS&lt;/strong&gt;
&lt;/h1&gt;

&lt;p&gt;If you have any productivity tips/hacks/ideas that have worked for you, please can leave them in the comments below or tweet them to me at &lt;a href="https://twitter.com/thesohaibtariq" rel="noopener noreferrer"&gt;@thesohaibtariq&lt;/a&gt;. As a &lt;strong&gt;self professed serial procrastinator, I need all the productivity advice I can get&lt;/strong&gt; 😀&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you found this article even remotely helpful, it would mean the world to me if you could share it with your friends&lt;/strong&gt;. I'm trying to give this blogging thing a go, positive feedback will help me persevere through the initial lonely phase. &lt;/p&gt;

</description>
      <category>productivity</category>
    </item>
    <item>
      <title>Barebones Authorization for Hangfire Dashboard</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Sat, 05 Sep 2020 14:47:04 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/barebones-authorization-for-hangfire-dashboard-18lp</link>
      <guid>https://dev.to/sohaibtariq/barebones-authorization-for-hangfire-dashboard-18lp</guid>
      <description>&lt;p&gt;I just set up a Hangfire dashboard for our .NET Core application. As a security measure, the hangfire dashboard only allows local requests. If you wish to access the dashboard on a production server, you need to set up some form of Authorization by creating an implementation of IDashboardAuthorizationFilter. Now, there are a number of ways to do this, depending on your reuirements. All we needed was a quick solution that would allow us to see our dashboard on our development server.&lt;/p&gt;

&lt;p&gt;If you are also looking for a quick and dirty solution,here is how I did it :&lt;/p&gt;

&lt;p&gt;First, create an implementation of &lt;em&gt;IDashboardAuthorizationFilter&lt;/em&gt;. We provide this implementation in the form of an Action Filter called &lt;em&gt;HangfireAuthorizationFilter&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You are now required to implement the Authorize method. We will authorize our user using credentials supplied in the query string. We simply store a username and password in our &lt;em&gt;appsetting.json&lt;/em&gt; and correlate the supplied credentials with these stored credentials. If they match, we store them in a &lt;strong&gt;session cookie&lt;/strong&gt; and return true, completing the Auth process. &lt;/p&gt;

&lt;p&gt;Why do we need a cookie you say? thats because hangfire periodically makes requests to the application server in order to provide realtime data. Therefore, although the first request will contain the credentials in the query string, all subsequent calls will not, and hence, they will return a 401 status code. We fix this by including a session cookie in the reponse of our auth call. All subsequent requests made in that same session will contain this cookie and we can reauhtorize each incoming request.&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="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;Authorize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DashboardContext&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;httpContext&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;GetHttpContext&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;userName&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserName&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;password&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_settings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Password&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;//if user has already logged in, in this session, subsequent requests will read credentials from cookie&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;httpContext&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;Cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;]&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;httpContext&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;Cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"pwd"&lt;/span&gt;&lt;span class="p"&gt;]&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;httpContext&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;Cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;httpContext&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;Cookies&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"pwd"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&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;true&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="k"&gt;if&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;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;)&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;context&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="nf"&gt;GetQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pwd"&lt;/span&gt;&lt;span class="p"&gt;)&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;context&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="nf"&gt;GetQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&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;Request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pwd"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;//Store credentials in cookie so that subsequent requests dont require them&lt;/span&gt;
                &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;httpContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pwd"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&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;true&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;false&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;Next, simply include you implemenation of &lt;em&gt;IDashboardAuthorizationFilter&lt;/em&gt; in your startup file and youre done.&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="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseHangfireDashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/hangfire"&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;DashboardOptions&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;IsReadOnlyFunc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DashboardContext&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;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_hangfireSettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MakeDashboardReadonly&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;Authorization&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&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;HangFireAuthorizationFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_hangfireSettings&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;



</description>
    </item>
    <item>
      <title>Exponential backoff for AWS Lambda</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Sat, 05 Sep 2020 14:43:10 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/exponential-backoff-for-aws-lambda-3aj2</link>
      <guid>https://dev.to/sohaibtariq/exponential-backoff-for-aws-lambda-3aj2</guid>
      <description>&lt;p&gt;I recently set up a Lambda function that reads data from an SQS Queue &lt;br&gt;
and makes an API call to one of our microservices. &lt;br&gt;
Naturally, this calls for an error handling mechanism, considering that the microservice &lt;br&gt;
could be down or unresponsive.&lt;/p&gt;

&lt;p&gt;AWS Lambda provides its own retry mechanism where a message is picked up from the queue by the Lambda &lt;br&gt;
consumer and becomes invisible to other consumers for a specific duration called the &lt;em&gt;visibility timeout&lt;/em&gt;.&lt;br&gt;
If the consumer completes execution successfully, it automatically deletes the message from the queue. &lt;br&gt;
In case of unsuccesful execution (such as a Runtime Exception), the &lt;em&gt;approximate receive count&lt;/em&gt; &lt;br&gt;
of the message is incremented and it becomes available to other consumers after the &lt;em&gt;visibility timeout&lt;/em&gt; passes.&lt;br&gt;
The number of times a message can be re-read from the queue&lt;br&gt;
before it is finally sent to a Dead Letter Queue(DLQ) is configured in the Redrive policy of the &lt;br&gt;
SQS Queue and is tracked via the &lt;em&gt;approximate receive count&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This retry mechanism was not exactly what I had in mind for our use case. I was thinking along the &lt;br&gt;
lines of a backoff strategy that keeps retrying the API call with exponentially increasing wait time; &lt;br&gt;
finally sending the message to a DLQ after a set number of retries. This would give us ample time to &lt;br&gt;
fix any issues with our miscroservice and prevent it from being bombarded with failing API calls. &lt;/p&gt;

&lt;p&gt;This is what I ended up with: &lt;/p&gt;

&lt;p&gt;First, a very basic Java function to calculate the exponential wait time, given the number of &lt;br&gt;
retries &lt;strong&gt;recvCount&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;randomInt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rand&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;nextInt&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Double&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pow&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recvCount&lt;/span&gt;&lt;span class="o"&gt;)).&lt;/span&gt;&lt;span class="na"&gt;longValue&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;randomInt&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;  &lt;span class="c1"&gt;//adding jitter to new random visibility timeout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the addition of &lt;strong&gt;randomInt&lt;/strong&gt;. That is 'jitter'. A bit of randomness. I read about it in some &lt;br&gt;
&lt;a href="https://cloud.google.com/storage/docs/exponential-backoff" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; by Google Cloud and included &lt;br&gt;
it as a good practice.&lt;/p&gt;

&lt;p&gt;Next up, set the visibility timeout of the message to the value that we just calculated above. The maximum value allowed by AWS is 43200 seconds&lt;br&gt;
or 12 hours.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;  &lt;span class="n"&gt;sqs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;changeMessageVisibility&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queueUrl&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getReceiptHandle&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;newVisibilityTimeout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;intValue&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we check the response to our API call. If it is a 400 or 500 series response, we throw a Runtime Exception and change the visibility timeout of the &lt;br&gt;
message. This is &lt;br&gt;
the easiest way I could come up with to signal unsuccessful execution of the Lambda function. Plus, we can only throw unchecked exceptions&lt;br&gt;
in our handler method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// api call&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;  
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getStatusLine&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;getStatusCode&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="o"&gt;){&lt;/span&gt;
                            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ExponentialBackoff&lt;/span&gt;&lt;span class="o"&gt;().&lt;/span&gt;&lt;span class="na"&gt;setVisibilityTimeout&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&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;RuntimeException&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Request to server failed"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
                        &lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ExponentialBackoff is my utility class where the code that calculates and sets the visibility timeout lives. It also has some other&lt;br&gt;
utility functions that are not essential for this demonstration.&lt;/p&gt;

&lt;p&gt;There you have it; A bare bones exponential backoff implementation for AWS Lambda. &lt;/p&gt;

</description>
      <category>aws</category>
      <category>java</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Replicating Azure SQL DB Instances on the fly for SaaS apps</title>
      <dc:creator>Sohaib Tariq</dc:creator>
      <pubDate>Fri, 04 Sep 2020 16:33:31 +0000</pubDate>
      <link>https://dev.to/sohaibtariq/replicating-azure-sql-db-instances-on-the-fly-for-saas-apps-48jc</link>
      <guid>https://dev.to/sohaibtariq/replicating-azure-sql-db-instances-on-the-fly-for-saas-apps-48jc</guid>
      <description>&lt;p&gt;If you are building a multi-tenant application on Azure, you may have to spin up Azure Sql instances on the fly when onboarding new tenants. I felt this would be a fairly common use case, but to my surprise, I failed to find any articles relating to this exact topic. After going through a number of different articles, I am compiling my learnings here with the hope that someone else will find this post useful.&lt;/p&gt;

&lt;p&gt;First off, you need an Azure SDK, and not just any SDK, a ‘management’ SDK. You will find it &lt;a href="https://www.nuget.org/packages/Microsoft.WindowsAzure.Management.Sql/" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The first task, as you may have guessed, is Authentication.&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;authContext&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;AuthenticationContext&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;authority&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;);&lt;/span&gt; &lt;span class="c1"&gt;//"https://login.microsoftonline.com/"&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;credential&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;ClientCredential&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;appId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;appSecret&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;authResult&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;authContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AcquireTokenAsync&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;//“https://management.azure.com/”&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;token&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;TokenCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;authResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AccessToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you receive an authentication token, you can move to the next step: instantiating a SqlManagementClient.&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="n"&gt;SqlManagementClient&lt;/span&gt; &lt;span class="n"&gt;mgmtClient&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;SqlManagementClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;mgmtClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SubscriptionId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;subscriptionId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have a database already set up which contains some common data which all tenants need access to. The objective is to replicate this database every time a new tenant is added to the platform.&lt;br&gt;
In order to achieve this, we will need to provide an identifier for the existing database along with the resource group, server, service tier, and Sku information for the new Database to be created.&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="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Databases&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateOrUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resourceGroup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dbName&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;Database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;location&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="c1"&gt;//centralus&lt;/span&gt;
                &lt;span class="n"&gt;sku&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;Sku&lt;/span&gt;&lt;span class="p"&gt;(&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;skuName&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;tier&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;),&lt;/span&gt; &lt;span class="c1"&gt;//S0 , Standard&lt;/span&gt;
                &lt;span class="n"&gt;createMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Copy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;sourceDatabaseId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;))&lt;/span&gt; &lt;span class="c1"&gt;// /subscriptions/.../resourceGroups/.../providers/Microsoft.Sql/servers/.../databases/&amp;lt;DB name&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CreateOrUpdate method will return a Database from which you can retrieve the database name or resource ID as required.  &lt;/p&gt;

&lt;p&gt;And there you have it, how easy was that ? Took me a good few hours to figure it out 😅  &lt;/p&gt;

</description>
      <category>csharp</category>
      <category>azure</category>
      <category>sql</category>
      <category>saas</category>
    </item>
  </channel>
</rss>
