DEV Community

Cover image for Azure Functions in .NET (C#) — The Ultimate Fun Version 🥳
Zied Rebhi
Zied Rebhi

Posted on

Azure Functions in .NET (C#) — The Ultimate Fun Version 🥳

What is Azure Functions?

Imagine you’re throwing a party. You have tons of guests (events) arriving at different times. Instead of hiring a full-time butler (server) to manage it all, you have Azure Functions, which is like a party planner who only shows up when needed. When a guest arrives (an event happens), the planner (your function) gets to work, does their thing, and leaves when the job is done. No hassle, no drama. Just pure serverless fun! 🥳

Why Should You Care About Azure Functions?

  • Zero Server Drama: No need to manage servers. It just works.

  • Scalable Like a Superhero: It grows or shrinks as needed (no stress about overworking it).

  • Pay Only for What You Use: You don’t pay for a full-time worker (server); you only pay for when your party planner shows up.


Setting Up Your First Azure Function

  1. Install Your Tools: Visual Studio or Visual Studio Code is your playground. Make sure to install the Azure Functions Tools. It’s like installing your party setup kit.

  2. Create a New Project: Open Visual Studio and create a new Azure Function project. Choose the HTTP Trigger template (because, hey, you want to start with something easy like handling guest RSVPs via HTTP, right?).

Writing Your First Function (The HTTP Trigger)

Here’s where the magic happens. Imagine this function is like sending an invite that says “Hey, tell me your name!”

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

public static class MyFirstFunction
{
    [FunctionName("HelloFunction")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("The function just got a request!");

        string name = req.Query["name"];

        // If they don't tell you their name, give them a little nudge
        return name != null
            ? (ActionResult)new OkObjectResult($"Hello, {name}, welcome to the party!")
            : new BadRequestObjectResult("Oops! Please tell us your name on the query string.");
    }
}

Enter fullscreen mode Exit fullscreen mode

This function is triggered by an HTTP request. If someone says their name (via the query string name), the function greets them like a true host. If not, they get a “Please tell us your name!” nudge.

Testing It Out Locally:


Example 2: Timer Trigger (The Office Alarm)

Now, let’s add a fun twist! Imagine you want to send out an announcement every 5 minutes: “Time for snacks!”

Here’s how to set up a Timer Trigger:

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using System;

public static class SnackBreak
{
    [FunctionName("SnackTimeReminder")]
    public static void Run([TimerTrigger("0 */5 * * * *")] TimerInfo myTimer, ILogger log)
    {
        log.LogInformation($"It's snack time! The time is: {DateTime.Now}");
    }
}

Enter fullscreen mode Exit fullscreen mode

The Timer Trigger runs every 5 minutes. You can think of it as the office alarm that reminds you to take a break. No more forgetting about snacks!


Example 3: Blob Trigger (Snack Delivery)

What if someone drops a snack (a file) into the Azure Blob Storage, and you want your function to grab it and send an alert? Here’s how:

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;

public static class BlobTriggerFunction
{
    [FunctionName("BlobSnackArrival")]
    public static void Run([BlobTrigger("snack-container/{name}", Connection = "AzureWebJobsStorage")] string myBlob, string name, ILogger log)
    {
        log.LogInformation($"New snack dropped in the container! {name} arrived. It contains: {myBlob}");
    }
}

Enter fullscreen mode Exit fullscreen mode

This function gets triggered when a new snack (file) is uploaded to the snack-container. Your function immediately tells everyone, “A new snack just arrived!” 🥳


Example 4: Queue Trigger (Serving Requests)

Sometimes, you might get too many requests at once, so you need a queue. This example shows how you can use a Queue Trigger to process snack requests:

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;

public static class QueueTriggerFunction
{
    [FunctionName("ProcessSnackRequest")]
    public static void Run([QueueTrigger("snack-requests")] string snackRequest, ILogger log)
    {
        log.LogInformation($"Processing snack request: {snackRequest}");
    }
}

Enter fullscreen mode Exit fullscreen mode

The function gets triggered whenever a message is added to the snack-requests queue. Imagine a request like “Bring me chips!” 🎉


Example 5: Send an Email (The Party Invite)

Let’s say you want your function to send an email whenever a new user registers for your party (or app, or whatever your event is). You can use a Queue Trigger or HTTP Trigger to handle this.

Here’s a simple example using the **SendGrid **email service to send an email.

  1. Install SendGrid NuGet Package: First, install the SendGrid NuGet package via NuGet Package Manager or by running this in your terminal:
    dotnet add package SendGrid

  2. Create the Azure Function to Send an Email:

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using SendGrid;
using SendGrid.Helpers.Mail;
using System.Threading.Tasks;

public static class EmailTriggerFunction
{
    [FunctionName("SendWelcomeEmail")]
    public static async Task Run([QueueTrigger("new-user-queue")] string username, ILogger log)
    {
        log.LogInformation($"New user {username} registered. Sending welcome email...");

        // SendGrid API key (store it in Application Settings)
        string sendGridApiKey = Environment.GetEnvironmentVariable("SendGridApiKey");
        var client = new SendGridClient(sendGridApiKey);
        var from = new EmailAddress("partyplanner@example.com", "Party Planner");
        var subject = "Welcome to the Party!";
        var to = new EmailAddress($"{username}@example.com");
        var plainTextContent = "Hi, welcome to our awesome party!";
        var htmlContent = "<strong>Hi, welcome to our awesome party!</strong>";
        var msg = MailHelper.CreateSingleEmail(from, to, subject, plainTextContent, htmlContent);

        // Send the email
        var response = await client.SendEmailAsync(msg);
        log.LogInformation($"Email sent to {username}: {response.StatusCode}");
    }
}

Enter fullscreen mode Exit fullscreen mode
  • How it works: This function triggers when a new user is added to the new-user-queue. It sends them a welcome email using SendGrid.

  • Real use case: You could use this for sending onboarding emails to new users or subscribers.


Example 6: Process Files in Blob Storage (The Snack Delivery)

Imagine you’re hosting a party and guests are dropping off snack recipes (files) in your Azure Blob Storage. You want to process those recipes and log them in the event that someone needs to order the ingredients.

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;

public static class ProcessSnackFiles
{
    [FunctionName("ProcessRecipeFile")]
    public static void Run([BlobTrigger("snacks/{name}", Connection = "AzureWebJobsStorage")] string recipeFile, string name, ILogger log)
    {
        log.LogInformation($"New recipe file: {name}. Here’s the content: {recipeFile}");

        // Process the file, for example, save it to a database or parse it
    }
}

Enter fullscreen mode Exit fullscreen mode
  • How it works: This function listens to a blob container (snacks/). When a new file is uploaded (for example, a recipe), it triggers and logs the file contents.

  • Real use case: You could use this for handling uploaded documents, images, or reports.


Example 8: Durable Functions (The Party Workflow)

What if you have a complex workflow? Maybe you need to send multiple emails, update databases, and even call external APIs as part of a longer-running process (like processing party RSVPs). You can use Durable Functions to chain tasks together and ensure everything runs in order.

using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.DurableTask;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using System.Threading.Tasks;

public static class PartyWorkflow
{
    [FunctionName("PartyWorkflow_HttpStart")]
    public static async Task<HttpResponseMessage> Start(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestMessage req,
        [DurableClient] IDurableOrchestrationClient starter,
        ILogger log)
    {
        string instanceId = await starter.StartNewAsync("PartyWorkflow", null);
        log.LogInformation($"Started orchestration with ID = {instanceId}");

        return starter.CreateCheckStatusResponse(req, instanceId);
    }

    [FunctionName("PartyWorkflow")]
    public static async Task RunOrchestrator(
        [OrchestrationTrigger] IDurableOrchestrationContext context)
    {
        var outputs = new List<string>();

        // Call external functions or activities sequentially
        outputs.Add(await context.CallActivityAsync<string>("SendInvite", "John"));
        outputs.Add(await context.CallActivityAsync<string>("SendSnackReminder", "John"));
        outputs.Add(await context.CallActivityAsync<string>("ConfirmRSVP", "John"));

        // Do something with the outputs (like update a database or send a final email)
    }

    [FunctionName("SendInvite")]
    public static string SendInvite([ActivityTrigger] string name, ILogger log)
    {
        log.LogInformation($"Sending invite to {name}.");
        return $"Invite sent to {name}.";
    }

    [FunctionName("SendSnackReminder")]
    public static string SendSnackReminder([ActivityTrigger] string name, ILogger log)
    {
        log.LogInformation($"Sending snack reminder to {name}.");
        return $"Snack reminder sent to {name}.";
    }

    [FunctionName("ConfirmRSVP")]
    public static string ConfirmRSVP([ActivityTrigger] string name, ILogger log)
    {
        log.LogInformation($"Confirming RSVP for {name}.");
        return $"RSVP confirmed for {name}.";
    }
}

Enter fullscreen mode Exit fullscreen mode
  • How it works: This example demonstrates Durable Functions, where multiple activities (like sending an invite, reminding guests about snacks, and confirming RSVPs) are orchestrated together. This is great for workflows that need to maintain state or wait for external inputs.

  • Real use case: Perfect for processing complex tasks like order processing, multi-step approvals, or handling multi-step customer interactions.


Example 9: Integrating with External APIs (The Party Food Order)

What if you need to order food or supplies from an external service (like an API)? Here’s how you can integrate Azure Functions with an external API to automate ordering party supplies!

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Threading.Tasks;

public static class ExternalApiTrigger
{
    private static readonly HttpClient client = new HttpClient();

    [FunctionName("OrderFood")]
    public static async Task Run([TimerTrigger("0 0 12 * * *")] TimerInfo myTimer, ILogger log)
    {
        log.LogInformation("Time to order food!");

        // Make an API call to an external service to order food
        HttpResponseMessage response = await client.GetAsync("https://api.foodservice.com/order?item=pizza");

        if (response.IsSuccessStatusCode)
        {
            log.LogInformation("Food order placed successfully!");
        }
        else
        {
            log.LogError("Failed to place food order.");
        }
    }
}

Enter fullscreen mode Exit fullscreen mode
  • How it works: This function is triggered daily at noon (with a Timer Trigger). It calls an external API to order pizza for the party (or other supplies).

  • Real use case: You could use this in an e-commerce setting or any business that needs to interact with external APIs on a schedule.


Cost Management: Pay Only for What You Eat (Or Use)

The best part? You only pay when your function is doing its job, like a party planner that only bills you for the time they actually worked! There are several pricing plans:

  • Consumption Plan: Pay for only the time your function runs.
  • Premium Plan: More control, more features (like VNET integration).
  • Dedicated Plan: Full-time party planner with fixed scaling.

Conclusion: More Ways to Party with Azure Functions

With these real examples, you can see how Azure Functions can be used for a variety of tasks — from sending emails, processing files, and interacting with external APIs, to managing complex workflows with Durable Functions.

The best part? Azure Functions is like the best party planner: it shows up when needed, gets the job done, and leaves without any fuss. Plus, it scales automatically, so no party is too big or too small! 🥳

Top comments (1)

Collapse
 
mbrito profile image
Miguel Brito

Very good article