Azure Functions - James Montemagno https://staging.montemagno.com/tag/azure-functions/ https://staging.montemagno.com/content/images/2017/08/MonogramIcon_Orange_NoBuffer.png Azure Functions - James Montemagno https://staging.montemagno.com/tag/azure-functions/ Hugo -- gohugo.io Tue, 13 Oct 2026 23:21:57 GMT 60 Introducing Island Tracker for Animal Crossing New Horizons https://staging.montemagno.com/introducing-island-tracker-for-animal-crossing-new-horizons/ 5eb04dd46c478d00392fb981 Sat, 09 May 2020 17:25:00 GMT

tldr; I built a new iOS & Android app called Island Tracker that enables you to track turnip prices, get predictions, and share them with friends. It is available today.

Get it on: Download on the App Store Android app on Google Play

When Animal Crossing New Horizons launched in late March I fell in love immediately. My wife adopted my Nintendo Switch Lite and we both got copies the night of release. Over on the Nintendo Dispatch podcast, we call it the perfect game at the perfect time. It truly has been for us during this time of staying inside away from all of our closest friends. Each day we dig up fossils, shake trees, give gifts to neighbors, visit islands and collect things for our museum.

However, something is different each Sunday morning at our house. We wake up and race to our Switch to see what price we can buy bundles and bundles of turnips. Then throughout the week we are constantly bugging our friends to see what we can sell them for, in hopes that someone has a huge spike and we can make a mad profit. After a week of text message madness, my must solve everything with a mobile app mind went to work and Island Tracker was born.

Island Tracker screens for sharing turnip prices with friends, tracking prices, weekly predictions, and an island profile

Island Tracker enables you to easily track your turnip purchases on Sunday and then track your prices throughout the week. You can easily get predictions, see if you are up or down, and then share your prices with all of your friends with a click of the button! Through weeks of beta testing with Animal Crossing die hards, I have even added some really cool features such as sharing your Switch Friend Code and nifty calculators to make buying turnips a breeze. After weeks of development, architecting, testing, and getting ready for release, Island Tracker is available right now on Google Play for Android and the Apple App Store for iOS for $2.99. Need some convincing? Here is a full walk through:

The Tech Behind Island Tracker

As you would expect the entire application is completely open source and available on GitHub. The application shares around 98% shared source code between iOS & Android, leveraging Xamarin.Forms for the user interface and C# business logic. There are tons of great libraries that I leveraged to build the app including PancakeView, Sharpnado, Syncfusion, MvvmHelpers, Monkey Cache, App Center, Xamarin.Essentials, and Resizetizer.NT.

For the backend system I leveraged Azure Functions combined with Azure Table Storage. With just a few Tables I was able to achieve some really cool functionality with a full friends system, encryption, and no-signup users.

Diagram of the phone app exchanging data with Azure Functions, which reads and writes Azure Table Storage

If you are interested in how it all works checkout this YouTube video I shot on the entire process.

A Huge Thanks

There is an amazing Xamarin community making awesome libraries that really helped me be productive throughout the process. I built a lot of the app live on my Twitch stream and got tons of great feedback and help. Then there is the hard work of Mike Bryant and Steve aka sparkie108 who ported tons of the predictions code to JavaScript and then to  C# to use in the app, which is awesome! Finally, thanks to all of my awesome beta testers that gave me feedback all throughout the last month really making the app spectacular.

What's Next

Well, it is out! I am super proud of this app and hope that people enjoy it and make tons of bells in Animal Crossing! I will continue to improve the app, add new features, and make it the best Animal Crossing app that I can! Cheers <3

Get it today: Download on the App Store Android app on Google Play

]]>
Going Serverless with Azure Functions: SendGrid https://staging.montemagno.com/going-serverless-with-azure-functions-sendgrid/ 598df8f2c121b60019bf2fde Thu, 22 Dec 2016 18:48:57 GMT A while back I wrote an app called MyShoppe, which served as a sample application that would enable any business owner with multiple locations to build an app to help their customers get store information and leave feedback. This was more than just a sample application as I built the original application for my brother who has several stores in Texas.

The Old Backend

The app isn’t overly complex. I leveraged Azure Mobile Apps (at the time Mobile Services) as a backend to do online/offline sync with an ASP.NET website so I could write everything in C#. The only thing that the backend was really doing was validating an admin app that I had created when Keith logged in and then it would send an email leveraging SendGrid to Keith whenever someone left feedback.

The New Backend

The app was getting out of date and iOS 10 basically broke the UI, so I had to update it. I decided to simplify the application and get rid of my ASP.NET backend (mosty because I didn’t have the code anywhere) and move to a simplified nodejs backend (even though I hate javascript). The issue of course would be that I would need to handle authentication and sending emails via javascript instead of the nice and pretty C# code that I had in my old ASP.NET backend. No worries though as Azure Functions came to the rescue since I could shove any heavy logic off to the C# world.

Azure Functions 101

If you aren’t aware of what Azure Functions are, let me give you a 101 crash course really quick. Basically think of functions as event based or trigger based methods that get invoked that have inputs and outputs. For instance a trigger could be a HTTP Post and the output could be an email via Send Grid, or perhaps the input is someone uploaded something to blob storage and you want to take it as in input and re-scale it. There are tons of great examples. For my needs I thought… well I could literally send a web request to an Azure Function and write all my parsing and SendGrid logic in C# (Function can actually be written in C#, F#, javascript, and a bunch of other languages).

The App Code

The first step a very simple Azure Mobile App and enabled Easy Tables and Easy APIs which leverage nodejs on the backend.

Inside of my Xamarin apps I made the “Store” table a sync table and the “Feedback” table an ‘online’ only table since I only ever want to push data to the server and don’t need to ever sync to my clients. Essentially here is my code from the app:

if(freedbackTable == null)
  feedbackTable = MobileService.GetTable<Feedback> ();

await feedbackTable.InsertAsync(feedback);

With these lines of code the feedback will be sent to my backend and stores in my SQL backend on Azure. I mostly decided to go this route because I want to always have the data backed up instead of just trying to send an email from the app.

The Azure Function Code

Let’s create a function app! So easy, peasy, basically New -> Compute -> Function App. Fill in a bit of information and this Function app contains a suite of functions inside of it. I like to group all functions for an app together.

There are a lot of nice templates to get you started. I went with a simple “HttpTrigger-CSharp” template since I knew that I wanted that to be my input. Essentially I wanted my mobile app backend to call into my Azure function so it is nice and secure and the mobile apps never call the Function directly so it can’t get spammed.

Under the “Integrate” section, you will see an input and output. I deleted the current output and selected a new SendGrid output.

You now need to fill in a bit of information for the output. The most important part here is that the SendGrid API Key doesn’t actually get posted in here, you have to actually add it under your “Function app settings” -> Go to App Service Settings -> Application Settings -> then add a new app setting ->

If you fail to put it in here and if the keys don’t match up it gets all mad. Alright now for the code. This is super easy. I just copied my model into the function, brought in Json.NET and used the SendGrid API. Here is the code:

#r "SendGrid"
#r "Newtonsoft.Json"

using System;
using SendGrid.Helpers.Mail;
using Microsoft.Azure.WebJobs.Host;
using Newtonsoft.Json;
using System.Net;
using System.Collections.Generic;
using System.Linq;

public static Mail Run(HttpRequestMessage req, TraceWriter log)
{

    log.Info($"SendGrid Function Triggered");
    string jsonContent = req.Content.ReadAsStringAsync().Result;

    if(string.IsNullOrWhiteSpace(jsonContent))
    {
        log.Info($"No data");
        return null;
    }

    var f = JsonConvert.DeserializeObject&lt;Feedback&gt;(jsonContent);

    log.Info($"WCSendGrid function processing order: {f.Id}");

    Mail message = new Mail()
    {
        Subject = $"Feedback from {f.Name} {f.VisitDate.ToShortDateString()}!"
    };
    var service = string.Empty;
    switch(f.ServiceType)
    {
        case 0: service = "Billing and Payments";
        break;
        case 1:service = "Device Help";
        break;
        case 2:service = "Upgrade Device";
        break;
        case 3:service = "New to Store";
        break;
        case 4:service = "Other";
        break;
    }

    var callback = f.RequiresCall ? "need a callback" : "do NOT need a call";

    Content content = new Content
    {
        Type = "text/plain",
        Value = $"Feedback from {f.Name}, for their visit on {f.VisitDate.ToLongDateString()} to store: {f.StoreName}: \n\n" +
        $"{f.Text} \n\n" +
        $"Their rating was: {f.Rating} \n\n" +
        $"Their service type was: {service}\n\n" +
        $"Their phone is: {f.PhoneNumber} and they {callback}"
    };

    message.AddContent(content);

     log.Info($"WCSendGrid function processed order: {f.Id}");
    return message;
}

public class Feedback
{
    [JsonProperty(PropertyName = "id")]
    public string Id { get; set; }

    [JsonProperty(PropertyName = "text")]
    public string Text {get;set;} = string.Empty;

    [JsonProperty(PropertyName = "feedbackDate")]
    public DateTime FeedbackDate {get;set;} = DateTime.UtcNow;

    [JsonProperty(PropertyName = "visitDate")]
    public DateTime VisitDate {get;set;} = DateTime.UtcNow;

    [JsonProperty(PropertyName = "rating")]
    public int Rating {get;set;} = 9;

    [JsonProperty(PropertyName = "serviceType")]
    public int ServiceType {get;set;} = 4;

    [JsonProperty(PropertyName = "name")]
    public string Name {get;set;} = string.Empty;

    [JsonProperty(PropertyName = "phoneNumber")]
    public string PhoneNumber {get;set;} = string.Empty;

    [JsonProperty(PropertyName = "requiresCall")]
    public bool RequiresCall {get;set;} = false;

    [JsonProperty(PropertyName = "storeName")]
    public string StoreName { get; set; } = string.Empty;

    [JsonIgnore]
    public string VisitDateDisplay
    {
        get { return FeedbackDate.ToString ("g"); }
    }

    [JsonIgnore]
    public string SortBy
    {
        get { return FeedbackDate.ToString("MMMM yyyy"); }
    }
}

It isn’t overly complex once you realize that the return value of the function is the output and the parameters are the input. Besides that it is just standard C#! Beautiful!

Update Backend Logic

For each of the tables there is some javascript essentially that lives behind it like a controller in ASP.NET that has different inserts/update/deletes. So, my plan here was to write as little code as possible and I don’t really know javascript very well so I went to stack overflow and found this bit of code that I could put into the table code behind:

var request = require('http');
table.insert(function (context) {
	var item = context.item;

	var body = JSON.stringify(item);

	var request = new http.ClientRequest({
	    hostname: "fa.azurewebsites.net",
	    port: 80,
	    path: "/api/WCSendGrid?code=YourCode",
	    method: "POST",
	    headers: {
	        "Content-Type": "application/json",
	        "Content-Length": Buffer.byteLength(body)
	    }
	});

	request.end(body);
    return context.execute();
});

This isn’t too bad even though it tooke me like 30 minutes to debug silly hostname issue, but then someone told me about this crazy awesome javascript library called request, which essentially is the new hottness and turned my code into:

var request = require('request');
table.insert(function (context) {
    request.post("https://fa.azurewebsites.net/api/WCSendGrid?code=YourCode", {body: context.item, json:true});
    return context.execute();
});

And just like that all my logic got placed on to a super cheap Azure Function that I only have to pay per the execution time :) My next steps are to move even more logic to the Azure Function to keep all my costs :)

]]>