Azure Functions ja staattiset tiedostot

Published on Sunday, December 29, 2019

Yleistä löpinää

Jossain vaiheessa saattaa tulla tarve jaella Azure Functionsin kautta staattisia tiedostoja (esim. help-sivut). Staattiset sivut voisi tallentaa vaikkapa Azure Blobsiin ja hakea ne sieltä, mutta joissain tilanteissa on helpompi laittaa tiedostot mukaan suoraan pakettiin, jolloin Functionsin ei tarvitse tehdä ylimääräisiä verkkokutsuja tiedostojen hakemista varten.

Tapa 1: .csproj ja Embedded Resources

Ensimmäinen tapa on tuttu .NET-maailmasta. Eli binäärin kääntämisen yhteydessä voidaan sen sisään laittaa mitä tahansa tiedostoja, joihin pääsee sitten ajonaikaisesti käsiksi .NET:in Reflection-rajapinnan kautta.

Operaatio aloitetaan avaamalla Azure Functions -projektin .csproj-tiedosto halutulla tekstieditorilla, ja sitten sinne lisätään uusi ItemGroup-ryhmä, jonka sisään laitetaan sitten halutut tiedostot (*-merkkiä voi käyttää useamman tiedoston mukaanotossa) omina EmbeddedResource-elementteinään

<ItemGroup>
  <EmbeddedResource Include="help.html" />
</ItemGroup>

Kyseisen tiedoston sisällön voi sitten ajonaikaisesti ladata seuraavalla komennolla

string fileContent;

var assembly = typeof(Nimiavaruus.luokka).GetTypeInfo().Assembly;
using (Stream stream = assembly.GetManifestResourceStream("csprojin_nimi.help.html"))
{
    using (var reader = new StreamReader(stream))
    {
        fileContent = await reader.ReadToEndAsync();
    }
}

Jos resurssien nimet ovat hukassa, voi ne listata seuraavalla komennolla

Console.WriteLine(string.Join(',', assembly.GetManifestResourceNames()));

Tapa 2: .csproj ja FunctionAppDirectory

Toinen tapa on hieman samanlainen kuin ensimmäinen. Tälläkin kertaa projektin .csproj-tiedostoon lisätään ne tiedostot, jotka halutaan mukaan, mutta EmbeddedResourcen sijaan käytetään None-tyyppiä (joille pitäisi oletuksena olla jo oma ItemGroup, jossa on mm. host.json-tiedosto), jolloin tiedosto päätyy binääreiden kanssa samaan hakemistoon omana tiedostonaan.

<None Update="help.html">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

Ajonaikaisesti tiedoston voi sitten ladata ExecutionContextin FunctionAppDirectory-muuttujan avulla

public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", Route = null)]HttpRequest req, ILogger log, ExecutionContext context)
{
   log.LogInformation("C# HTTP trigger function processed a request.");
   byte[] fileContent = await File.ReadAllBytesAsync(Path.Combine(context.FunctionAppDirectory, "help.html"));
   return new FileContentResult(fileContent, "text/html");
}

☁️