By Dr. Andrew Le Gear, September 3, 2018
We have several complex and robust web solutions deployed here at Horizon. We use Azure App Services and find it is very professional and truly is a wonderful solution for production products, but this doesn’t come cheap. It costs about £700 per annum for a service plan that can accommodate an app service.
While that cost seems high, it gives you fabulous, built-in solutions for load balancing, high-availability, geo distribution, logging, analytics and more out of the box, leaving developers to focus on their product USP, saving an enormous amount of time to produce a professional product solution.
That said, sometimes you just want a quick, dirty, internal tool that either surfaces some content or executes some dev ops admin functionality. You may care little about the range of professional services that accompany a web app and are far more concerned about minimising the price of putting the tool live – preferably free!
Enter – Azure functions! Azure functions are now being pushed as part of Microsoft’s Serverless Computing and Micro-services development philosophy. I won’t get bogged down in explanations of these concepts here, but Microsoft does a much better job of explaining these:
- https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-overview-microservices
- https://azure.microsoft.com/en-us/services/functions/
What is important, is that these are mostly pushed as a means of providing http-based API’s as part of SaaS solutions on the back end of an infrastructure or solution. Standard tutorials are mostly like this: https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function
But wouldn’t it be nice to hack the Azure function to return content to your browser instead?
First annotate your Azure Function so that it responds to “GET” requests with no authentication:
public static async Task<object> Run([HttpTrigger(AuthorizationLevel.Anonymous, "GET")]HttpRequestMessage req, TraceWriter log)
On “req” if you want to access query parameters that you pass on the GET request simple fetch them like this:
var queryParams = req.GetQueryNameValuePairs();
Then you want to return html content to the requester. This must be an entire valid html document. The media type of the response should be “text/html”. Here, I put the content in a variable called “html”:
var response = new HttpResponseMessage(); response.Content = new StringContent(html); response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html"); return response;
For more complicated html pages I created a template file that I load and then replace key strings to produce my content. Also, the html I return can’t contain references to other resources external to the file such as images – this is because if a browser sees such a reference it will make another request, to what it thinks is a full blown web server and attempt to fetch the resource. What you can do though, as a neat work-around, is embed the image in your html document as a base 64 encoded string.
For example:
<img src="data:image/png;base64,iVBORw0KGgoA...SuQmCC">
You can use a site such as https://www.base64-image.de/ to convert your image to base 64. The drawback here, of course, is that we have lost all the wonderful power of ASP.NET Core. No razor pages, no built-in jQuery, no model resolution etc, but if it is a quick tool or service you want hosted, then this is great!
So why is this cheap? Well, the answer isn’t so clear cut.
For some this may not be cheap. As I mentioned, we host several full-blown app services on Azure here at Horizon. To host these services, we purchase a defined service plan from Microsoft, which gives us a particular set of compute resources and features. As you would imagine, each pre-defined service plan comes in different sizes and we have some spare capacity.
Crucially, you can place multiple types of apps into any chosen service plan, including function apps, and they will run on the same Azure VM and thus it means we can run our functions at no additional cost, until we exhaust the spare resource.
The alternative would be to run the function app on a consumption plan and you would pay for exactly what is used. The merits of consumption plans versus service plans could be a blog all of its own, so that’s a debate I will leave for now.
Here is an example of one of our Azure functions surfacing html. We use it as a simple block explorer for Kovan Ethereum: