{"id":11065,"date":"2017-12-21T21:41:48","date_gmt":"2017-12-22T04:41:48","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/webdev\/?p=11065"},"modified":"2017-12-21T21:41:48","modified_gmt":"2017-12-22T04:41:48","slug":"take-a-break-with-azure-functions","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/take-a-break-with-azure-functions\/","title":{"rendered":"Take a Break with Azure Functions"},"content":{"rendered":"<p>So, it&#8217;s the Holidays. The office is empty, the boss is away, and you&#8217;ve got a bit of free time on your hands. How about learning a new skill and having some fun?<\/p>\n<p>Azure Functions are a serverless technology that executes code based on various triggers (i.e. a URL is called, an item is placed on a queue, a file is added to blob storage, a timer goes off.) There&#8217;s all sorts of things you can do with Azure Functions, like running high CPU-bound calculations, calling various web services and reporting results, sending messages to groups &#8211; and nearly anything you can imagine. But unlike traditional applications and services, there&#8217;s no need to set up an application host or server that&#8217;s constantly running, waiting to respond to requests or triggers. Azure Functions are deployed as and when needed, to as many servers as needed, to meet the demands of incoming requests. There&#8217;s no need to set up and maintain hosting infrastructure, you get automatic scaling, and &#8211; best of all &#8211; you only pay for the cycles used while your functions are being executed.<\/p>\n<p>Want to have a go and try your hand at the latest in web technologies? Follow along to get started with your own Azure Functions.<\/p>\n<p>In this post I\u2019ll show you how to create an Azure Function that triggers every 30 minutes and writes a note into your slack channel to tell you to take a break. We\u2019ll create a new Function app, generate the access token for Slack, then run the function locally.<\/p>\n<p><b>Prerequisites:<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/www.visualstudio.com\/downloads\/\" rel=\"noopener\" target=\"_blank\">Visual Studio 2017<\/a> (v15.5 or above) with <a href=\"https:\/\/www.visualstudio.com\/vs\/support\/selecting-workloads-visual-studio-2017\/\" rel=\"noopener\" target=\"_blank\">Azure development workload<\/a><\/li>\n<li>Access to a <a href=\"https:\/\/slack.com\/\" rel=\"noopener\" target=\"_blank\">Slack<\/a> workspace<\/li>\n<\/ul>\n<h4>Create a Function App (Timer Trigger)<\/h4>\n<p>We all know how important it is to take regular breaks if you spend all day sitting at a desk, right? So, in this tutorial, we&#8217;ll use a Timer Trigger function to post a message to a Slack channel at regular intervals to remind you (and your whole team) to take a break. A Timer Trigger is a type of Azure Function that is triggered to run on regular time intervals.<\/p>\n<h5>Just run it<\/h5>\n<p>If you want to skip ahead and run the function locally, fetch the source from <a href=\"https:\/\/github.com\/justcla\/TakeABreak\" rel=\"noopener\" target=\"_blank\">this repo<\/a>, insert the appropriate Slack channel(s) and OAuth token in the local.settings.json file, start the Azure Storage Emulator, then Run (or Debug) the Functions app in Visual Studio.<\/p>\n<h5>Step-by-step guide<\/h5>\n<ol>\n<li>Open Visual Studio 2017 and select <strong>File-&gt;New Project<\/strong>.<\/li>\n<li>Select <strong>Azure Functions<\/strong> under the Visual C# category.<\/li>\n<li>Provide a name (e.g. TakeABreakFunctionApp) and press <strong>OK<\/strong>.\n    The New Function Project dialog will open.<\/li>\n<li>Select <strong>Azure Functions v1 (.NET Framework)<\/strong>, chose <strong>Timer trigger<\/strong> and press <strong>OK<\/strong>.\n    Note: This will also work with Azure Functions v2, but for this tutorial I\u2019ve chosen v1, since v2 is still in preview.<br><\/p>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/NewTimerTrigger.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/NewTimerTrigger-1.png\" alt=\"New Timer Trigger\" width=\"600\" height=\"346\" class=\"alignnone size-full wp-image-11125\" \/><\/a><\/p>\n<p>     A new solution is created with a Functions App project and single class called Function1 that contains a basic Timer trigger.<\/li>\n<li>Edit Function1.cs.\n<ul>\n<li>Add helper methods:\n<ul>\n<li>Env (for fetching environment variables)<\/li>\n<li>SendHttpRequest (for sending authenticated http requests)<\/li>\n<li>SendMessageToSlack (for generating and sending the appropriate Slack request &#8211; based on environment variables)<\/li>\n<\/ul>\n<\/li>\n<li>Update method: <strong>Run<\/strong>\n<ul>\n<li>Change the return type to <i><b>async Task<\/b><\/i>.<\/li>\n<li>Add an asynchronous call to the <strong>SendMessageToSlack<\/strong> method.<\/li>\n<li>Update Chron settings for the <strong>TimerTrigger<\/strong> attribute.<\/li>\n<\/ul>\n<\/li>\n<li>Add appropriate <strong>Using<\/strong> statements.<\/li>\n<\/ul>\n<\/li>\n<p><br>The completed code should look like this:<\/p>\n<pre><code><span style=\"font-size:9pt\">using System;\nusing System.Net.Http;\nusing System.Net.Http.Headers;\nusing System.Threading.Tasks;\nusing Microsoft.Azure.WebJobs;\nusing Microsoft.Azure.WebJobs.Host;\n \nnamespace TakeABreakFunctionsApp\n{\n    public static class Function1\n    {\n        [FunctionName(\"Function1\")]\n        public static async Task Run([TimerTrigger(\"0 *\/30 * * * *\")]TimerInfo myTimer, TraceWriter log)\n        {\n            log.Info($\"C# Timer trigger function executed at: {DateTime.Now}\");\n            await SendMessageToSlack(\"You're working too hard. How about you take a break?\", log);\n        }\n \n        private static async Task SendMessageToSlack(string message, TraceWriter log)\n        {\n            \/\/ Fetch environment variables (from local.settings.json when run locally)\n            string channel = Env(\"ChannelToNotify\");\n            string slackbotUrl = Env(\"SlackbotUrl\");\n            string bearerToken = Env(\"SlackOAuthToken\");\n \n            \/\/ Prepare request and send via Http\n            log.Info($\"Sending to {channel}: {message}\");\n            string requestUrl = $\"{slackbotUrl}?channel={Uri.EscapeDataString(channel)}&amp;text={Uri.EscapeDataString(message)}\";\n            await SendHttpRequest(requestUrl, bearerToken);\n        }\n\n        private static async Task SendHttpRequest(string requestUrl, string bearerToken)\n        {\n            HttpClient httpClient = new HttpClient();\n            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(\"Bearer\", bearerToken);\n            HttpResponseMessage response = await httpClient.GetAsync(requestUrl);\n        }\n\n        private static string Env(string name) =&gt; Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);\n    }\n}<\/span><\/code><\/pre>\n<li>Edit local.settings.json.\nAdd the following environment variables.<\/p>\n<ul>\n<li>SlackbotUrl &#8211; The URL for the Slack API to post chat messages<\/li>\n<li>SlackOAuthToken &#8211; An OAuth token that grants permission for your app to send messages to a Slack workspace.\n        &#8211; See below for help generating a Slack OAuth token.<\/li>\n<li>ChannelToNotify &#8211; The Slack channel to send messages to<\/li>\n<\/ul>\n<\/li>\n<p>Your local.settings.json should look something like this:\n(Your SlackOAuthToken and ChannelToNotify variables will be specific to your Slack workspace.)<\/p>\n<pre><code><span style=\"font-size:9pt\">{\n  \"IsEncrypted\": false,\n  \"Values\": {\n    \"AzureWebJobsStorage\": \"UseDevelopmentStorage=true\",\n    \"AzureWebJobsDashboard\": \"UseDevelopmentStorage=true\",\n    \"SlackbotUrl\": \"https:\/\/slack.com\/api\/chat.postMessage\",\n    \"SlackOAuthToken\": \"[insert your generated token]\",\n    \"ChannelToNotify\": \"[your channel id]\"\n  }\n}<\/span><\/code><\/pre>\n<\/ol>\n<p>Your Functions app is now ready to run! You just need to grab an authorization token for your Slack workspace.<\/p>\n<h4>Generate an OAuth token for your app to send messages to your Slack workspace<\/h4>\n<p>Before you can post a message to a Slack workspace, you must first tell Slack about the app and assign specific permissions for the app to send messages as a bot. Once you&#8217;ve installed the app to the Slack workspace, you will be issued an OAuth token that you can send with your http requests. For full details, you can <a href=\"https:\/\/api.slack.com\/docs\/oauth\" rel=\"noopener\" target=\"_blank\">follow the instructions here<\/a>. Otherwise, follow the steps below.<\/p>\n<ul>\n<li>\n<a href=\"https:\/\/api.slack.com\/apps?new_app=1\" rel=\"noopener\" target=\"_blank\">Click here<\/a> to register your new Functions app with your Slack workspace.<\/li>\n<li>Provide a name (e.g. &#8220;Take a Break&#8221;) and select the appropriate Slack workspace, then press <strong>Create App<\/strong>.<\/li>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/CreateASlackApp-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/CreateASlackApp-1-1.png\" alt=\"Create A Slack App\" width=\"450\" class=\"alignnone size-full wp-image-11096\" \/><\/a><\/p>\n<p>When the app is registered with Slack, the Slack API management page opens for the new app.<\/p>\n<li>Select <strong>OAuth &amp; Permissions<\/strong> from the navigation menu on the left.<\/li>\n<li>In the OAuth &amp; Permissions page, scroll down to <strong>Scopes<\/strong>, select the permission <strong>chat:write:bot<\/strong>, then select <strong>Save Changes<\/strong>.<\/li>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/SelectPermissionScopes.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/SelectPermissionScopes-2.png\" alt=\"Select Permission Scopes\" width=\"600\" class=\"alignnone size-full wp-image-11066\" \/><\/a><\/p>\n<li>After the scope permissions have been created and the page has refreshed, scroll to the top of the OAuth &amp; Permissions page and select <strong>Install App to Workspace<\/strong>.<\/li>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/SlackInstallAppToWorkspace-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/SlackInstallAppToWorkspace-1-1.png\" alt=\"Slack Install App to Workspace\" width=\"600\" class=\"alignnone size-full wp-image-11085\" \/><\/a><\/p>\n<li>A confirm page opens. Review the details, then click <strong>Authorize<\/strong>.<\/li>\n<li>Your OAuth Access Token is generated and presented at the top of the page.<\/li>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/OAuthAccessToken.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/OAuthAccessToken-1.png\" alt=\"OAuth Access Token\" width=\"602\" height=\"274\" class=\"alignnone size-full wp-image-11135\" \/><\/a><\/p>\n<li>Copy this token and add it to your local.settings.json as the value for <strong>SlackOAuthToken<\/strong>.<br>\n<strong>Note<\/strong>: The OAuth access token is a secret and should not be made public. If you check this token into a public source control system like GitHub, Slack will find it and permanently disable it!<\/li>\n<\/ul>\n<h4>Run your Functions App on your local machine<\/h4>\n<p>Now that you\u2019ve registered your app with Slack and have provided a valid OAuth token in your local.settings.json, you can run the Function locally.<\/p>\n<h5>Start the local Storage Emulator<\/h5>\n<p>You can configure your function to use a storage account on Azure. But if your app is configured to use development storage (which is the default for new Functions), then it will run against the local Azure Storage Emulator. Therefore, you\u2019ll need to make sure the Storage Emulator is started before running your Functions app.<\/p>\n<ul>\n<li>Open the Windows Start Menu and search for &#8220;Storage Emulator&#8221;.<\/li>\n<\/ul>\n<p>Microsoft Azure Storage Emulator will launch. You can manage it via the icon in the Windows System Tray.<\/p>\n<h5>Start the Function app from Visual Studio<\/h5>\n<ul>\n<li>Press Ctrl+F5 to build and run the Functions app.<\/li>\n<li>If prompted, update to the latest Functions tools.<\/li>\n<li>A new command window launches and displays the log output from the Functions app.<\/li>\n<\/ul>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/FunctionAppRunning.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/FunctionAppRunning-1.png\" alt=\"Function App Running\" width=\"2155\" height=\"654\" class=\"alignnone size-full wp-image-11105\" \/><\/a><\/p>\n<p>After a certain period of time, the Timer trigger will fire and send a message to your Slack workspace.<\/p>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/FunctionTimerExecutes.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/FunctionTimerExecutes-1.png\" alt=\"Function Timer Executes\" width=\"1639\" height=\"228\" class=\"alignnone size-full wp-image-11115\" \/><\/a><\/p>\n<p>You should see the message appear in the appropriate Slack channel.<\/p>\n<p><a href=\"http:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/MessageAppearsInSlack.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/aspnet\/wp-content\/uploads\/sites\/16\/2017\/12\/MessageAppearsInSlack-1.png\" alt=\"Message Appears In Slack\" width=\"602\" height=\"169\" class=\"alignnone size-full wp-image-11116\" \/><\/a><\/p>\n<p>Feel free to play around with the Timer Chron options in the Run method&#8217;s attributes to configure the function to execute at the intervals you&#8217;d like. Here are some example Chron settings.\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Trigger Chron format: (seconds minutes hours days months years)\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&#8220;0 *\/15 6-20 * * *&#8221;) = Every 15 minutes, between 06:00 AM and 08:59 PM\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(&#8220;0 0 0-5,21-23 * * *&#8221;) = Every hour from 12:00 AM to 06:00 AM and 09:00 PM to 12:00 AM<\/p>\n<p><strong>Congratulations!<\/strong> You&#8217;ve written a working Azure Functions App with a Timer trigger function.<\/p>\n<h5>What&#8217;s next?<\/h5>\n<p><br><b>Publish your Functions App to the cloud<\/b>\nSo that your Functions app is always available, and can be accessed globally (eg. For Http trigger types), you can publish your app to the cloud. <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/azure-functions\/functions-create-your-first-function-visual-studio#publish-the-project-to-azure\" rel=\"noopener\" target=\"_blank\">This article<\/a> describes the process of publishing a Functions app to Azure.<\/p>\n<p><b>Experiment with other Functions types<\/b>\nThere&#8217;s an excellent collection of open-source samples available <a href=\"http:\/\/functionlibrary.azurewebsites.net\/\" rel=\"noopener\" target=\"_blank\">here<\/a>. Poke around and see what takes your interest.<\/p>\n<p><b>Tell us about your experience with Azure Functions<\/b>\nWe&#8217;d love to hear about your experience with Azure Functions. If you&#8217;ve got a minute, please complete <a href=\"https:\/\/go.microsoft.com\/fwlink\/?linkid=865108\" rel=\"noopener\" target=\"_blank\">this short survey<\/a>.\nAs always, feel free to leave comments and questions in the space below.<\/p>\n<p>Happy holidays!<\/p>\n<p><strong>Justin Clareburt<\/strong>\nSenior Program Manager\nVisual Studio and .NET<\/p>\n","protected":false},"excerpt":{"rendered":"<p>So, it&#8217;s the Holidays. The office is empty, the boss is away, and you&#8217;ve got a bit of free time on your hands. How about learning a new skill and having some fun? Azure Functions are a serverless technology that executes code based on various triggers (i.e. a URL is called, an item is placed [&hellip;]<\/p>\n","protected":false},"author":467,"featured_media":58792,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[197,327],"tags":[],"class_list":["post-11065","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-aspnet","category-azure"],"acf":[],"blog_post_summary":"<p>So, it&#8217;s the Holidays. The office is empty, the boss is away, and you&#8217;ve got a bit of free time on your hands. How about learning a new skill and having some fun? Azure Functions are a serverless technology that executes code based on various triggers (i.e. a URL is called, an item is placed [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/11065","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/467"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=11065"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/11065\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/58792"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=11065"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=11065"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=11065"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}