Eduard Keilholz

Hi, my name is Eduard Keilholz. I'm a Microsoft developer working at 4DotNet in The Netherlands. I like to speak at conferences about all and nothing, mostly Azure (or other cloud) related topics.
LinkedIn | Twitter | Mastodon | Bsky


I received the Microsoft MVP Award for Azure

Eduard Keilholz
HexMaster's Blog
Some thoughts about software development, cloud, azure, ASP.NET Core and maybe a little bit more...

Why Azure Functions Are So Cool

So I ran in to Azure Functions and realized I totally missed something there. One of my co-workers is a serverless advocate and kind of drew my attention about a year ago. And so I started exploring the world of serverless. First impression is that it’s hard to learn and complicated, but all these thoughts appeared to be not true… It’s just different. A different way of thinking and a different way of programming.

So as a lot of developers do, I started a project which made sort of sense and started learning while the project evolved. And now, a year has passed. What happened during that year? I created a couple of github repos for the project, threw them away, re-created repos and threw them away as well… And now, a few weeks ago, I started a new repo with some code that I thought was worth sharing. And that’s where we are today….

TL;DR – A cool and awesome URL Shortner project running Azure Functions in probably the cheapest way possible, hit https://4dn.me/azfuncs.

Answer the question please!?

So the question remains… Why Azure Functions are so cool? Well, because you implement them in the easiest way possible. They’re triggered by native cloud services and thus integrate very well in every cloud solution. They scale like a maniac so huge amounts of traffic are no problem. Oh and wait…. Almost forgot to mention that running Azure Functions is cheap… Really cheap!!

So the project I was talking about, is the classic project of an URL Shortner. You paste in a long huge endpoint URL. The service stores the URL and returns a short code which can be used to visit the URL.

I added login functionality so users are able to manage their short links and change the short code so it’s even easier to remember as long as the short code is unique.

Finally I want to track hits on each short link so you can see how many hits a short link received and even see the most recent hits in a graph.

If users don’t want to log in, they can just paste a URL and have it shortened. They miss the advantage of being able to change the short code and extend the life time of a short link. All links will expire, users will be able to set / change the expiration date. Anonymous visitors cannot change that date.

So what is an Azure Function?

Basically, very simple… An Azure Function is just a piece of code, running because it’s executed by a trigger. You want to keep functions lean and clean. Ideally functions have a single purpose (responsibility) and rely as little as possible on code libraries. For example importing EntityFramework in an Azure Function runs fine and works perfect. However the EF library is large and makes your slim and lean function a big rhino running through an Azure datacentre. What you’re looking for is an agile free runner able to manoeuvre though the datacentre at lightning speed.

To help you, there’s a mechanism called bindings. So functions have a trigger, and bindings. With bindings, you are able to connect to other cloud services like storage, the service bus, event grid, sendgrid and more. And best of all, if your binding is not available by default, you’re free to create one yourself. Bindings are input (stuff coming in) or output (stuff sent out).

A tiny example

An easy example is sending email. Sending an email message is a relatively heavy process for web applications. Sending email messages within a web request, may block additional incoming requests. You dont’s want this kind of processes in your web request. Writing a function that sends these email messages for your makes your system more distributed, and best of all, removes the heavy process from your web request. Basically you would store an email message to blob storage and add a message to a queue. A function with a queue trigger, an input binding reading the message from blob, and an output binding to send the message using sendgrid would be an excellent solution. And best of all, you just removed the pressure from your web app.

So how does my demo app work?

An endpoint URL is passed to the backend, which generates a unique short code and stores the link in table storage. Pretty straigt forward.

public static async Task CreateShortLink(
    [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = "links")] HttpRequestMessage req,
    [Table(Constants.TableStorageLinksTableName)] CloudTable table,
    ILogger log)

This function uses a HTTP Trigger to fire (e.g. it waits for a web request). It uses an input binding to table storage and accepts a CloudTable so I can query for existing short codes and store the new short link in case everything is fine.

Then a couple of validations take place, and a unique short code is generated. In the end, I use the table to store the new short link.

var entity = new ShortLinkEntity
{
    ShortCode = validShortCode,
    RowKey = Guid.NewGuid().ToString(),
    CreatedOn = DateTimeOffset.UtcNow,
    EndpointUrl = shortLinkDto.EndpointUrl,
    ExpiresOn = expirationDate,
    PartitionKey = Constants.TableStorageLinksPartitionKey,
    Timestamp = DateTimeOffset.UtcNow,
    TotalHits = 0,
    OwnerId = owner
};

var operation = TableOperation.Insert(entity);
var result = await table.ExecuteAsync(operation);

Then I return a HTTP response containing information about the new short link.

Now when one of the short links is hit, the system needs to find if the short code exists and retrieve the endpoint associated to that short link. But because this is a cool and fancy Azure Functions Demo app, I want to track hits per short link. So I write also write a ‘hit’ to a storage queue.

A different function will be triggered when a message arrives on that queue, and starts processing the information about that hit. Here is the entire function:

[FunctionName("ProcessIncomingHit")]
public static async void Run(
    [QueueTrigger(Constants.TableStorageQueueHits)]ShortLinkHitDto hitDto,
    [Table(Constants.TableStorageLinksTableName)] CloudTable table,
    [Table(Constants.TableStorageHitsTableName)] CloudTable hitsTable,
    ILogger log)
{
            
    log.LogInformation($"Hit received for processing {hitDto.ShortCode}");
    var fetchOperation =
        TableOperation.Retrieve(Constants.TableStorageLinksPartitionKey, hitDto.RowKey);
    var retrievedResult = await table.ExecuteAsync(fetchOperation);
    if (retrievedResult.Result is ShortLinkEntity shortLinkEntity)
    {
        var hitEntity = new HitEntity
        {
            PartitionKey = Constants.TableStorageHitsPartitionKey,
            RowKey = Guid.NewGuid().ToString(),
            ShortCode = hitDto.ShortCode,
            HitOn = hitDto.HitOn,
            Timestamp = DateTimeOffset.UtcNow
        };


        shortLinkEntity.TotalHits = shortLinkEntity.TotalHits + 1;
        var insertOperation = TableOperation.Insert(hitEntity);
        await hitsTable.ExecuteAsync(insertOperation);
        var updateOperation = TableOperation.InsertOrReplace(shortLinkEntity);
        await table.ExecuteAsync(updateOperation);
    }
}

Obviously, the function is triggered on arrival of a message on the storage queue. I added bindings to the original short links table, and to a hits table. The original short links table is used to increment a total hits counter of the short link. Also I add a new entity to a hits table. This is used by an aggregate function that allows me to draw a graph of the hits over the past week.

The full source code can be found here.