Konfiguracja Azure Functions i Table Storage, czyli jak prosto przechować swoje dane – część 1

Konfiguracja Azure Functions i Table Storage, czyli jak prosto przechować swoje dane - część 1

Przechowywanie danych w modelu serverless nie musi być trudne i skomplikowane. Dzisiaj kolejny tydzień z Azure Functions w którym zajmiemy się przechowywaniem danych. Na pierwszy ogień pójdzie Table Storage.

O Azure Functions pisałem już w poprzednich częściach artykułów do, których serdecznie zapraszam

  1. Azure Functions na macOS? Pokażę Ci jak zacząć
  2. Jaki rodzaj rozliczania wybrać dla Azure Functions?
  3. Jak w 5 minut zbudować swoje pierwsze mock API w Azure Functions?
  4. Konfiguracja Azure Functions Routing Na 3 Sposoby
  5. Jak skonfigurować różne wersje interfejsu API w Azure Functions?
  6. Azure Functions i Swagger, czyli jak profesjonalnie zaprezentować nasze API

Natomiast jeżeli chcielibyście poczytać ogólnie o serverless możecie to zrobić tutaj.
Serverless, do czego może się przydać w aplikacjach mobilnych?

Czym jest Table Storage?

Jest to najprostsza usługa w Azure stworzona do przechowywania danych typu „NoSQL”. Nie jest ona w żaden sposób rozbudowana i nie dostarcza zaawansowanych funkcjonalności jak np. CosmosDB. Jest ona za to prosta, tania i szybka. Nasze dane są dodatkowo zapisywane z użyciem transakcji, oraz podlegają automatycznej replikacji do różnych datacenter.

Można w niej w bardzo prosty sposób przechować bardzo duże ilości danych. Jedna tabela jest w stanie przechować aż 500 TB danych.

Table Storage pozwala na przechowanie do 252 unikalnych kolumn w tym 3 kolumny systemowe takie jak:

  • PartitionKey – używane jako element klucza głównego, oraz ustawiane przez programistę
  • RowKey – używane jako element klucza głównego, oraz ustawiane przez programistę
  • Timestamp – jest to data modyfikacji danego rekordu ustawiana automatycznie przez system

Połączenie Storage Account, Table i Partition Key pozwala systemowi zidentyfikować partycję na której znajdują się nasze dane.

Pozwala nam również na używanie prostych typów danych takich jak:

  • byte[]
  • bool
  • DateTime
  • double
  • Guid
  • int
  • long
  • String

Po takim krótkim wprowadzeniu przejdźmy teraz do tzw. mięsa, czyli jak to wszystko ze sobą połączyć.

Jak połączyć Azure Functions i Table Storage

W Azure Functions w wersji v1 (runtime) można to było zrobić prosto z poziomu portalu wybierając jako output Table Storage.

Azure Table Storage output
Azure Table Storage output

Od wersji v2 (preview) taka opcja znikneła z portalu i trzeba output skonfigurować ręcznie używając edytora.

Advanced editor
Advanced editor

Konfiguracja w portalu

Jako, że głównie się skupiam na funkcjach w wersji v2 dlatego też pokaże konfiguracje Table Storage dla funkcji które obecnie są nadal w wersji beta runtime.

Zakładam, że mamy już stworzoną aplikacje i funkcje, oraz skonfigurowany odpowiedni runtime. Jak to zrobić znajdziecie w innych częściach serii o Azure Functions.

Klikamy w naszej funkcji opcję Integrate -> Advance editor. Pokaże nam się zawartość pliku function.json.
Musimy dodać nowe wyjście z naszej funkcji używając JSON

    {
      "name": "personTable",
      "direction": "out",
      "type": "table",
      "tableName": "personTable",
      "connection": "MyConnectionString"
    }

Co my tu mamy?

  • „name”: „personTable” – nazwa naszego parametru w kodzie CSharp Script
  • „direction”: „out” – kierunek w którym nasz parametr będzie dostępny. Czy będzie wejście czy naszym wyjście z funkcji
  • „type”: „table” – typ parametru (table, queue )
  • „tableName”: „personTable” – nazwa naszej tabeli
  • „connection”: „MyConnectionString” – nasz connection string. do Table Storage

Finalny plik będzie wyglądał następująco

{
  "bindings": [
    {
      "authLevel": "function",
      "name": "req",
      "type": "httpTrigger",
      "direction": "in",
      "methods": [
        "post"
      ],
      "route": "todo"
    },
    {
      "name": "$return",
      "type": "http",
      "direction": "out"
    },
    {
      "name": "personTable",
      "direction": "out",
      "type": "table",
      "tableName": "personTable",
      "connection": "MyConnectionString"
    }
  ]
}

Konfiguracja w kodzie

Teraz zostaje nam konfiguracja w kodzie funkcji. Na początek zmienimy sygnaturę naszej metod i dodamy parametr

ICollector personTable

Aby dodać nowy wiersz musimy wywołać metodę Add.

personTable.Add(new Person());

Finalny kod naszej funkcji będzie wyglądał jak na poniższym listingu.

#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Table;
using Newtonsoft.Json;

public static IActionResult Run(HttpRequest req, ICollector<Person> personTable, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");

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

    string requestBody = new StreamReader(req.Body).ReadToEnd();
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    name = name ?? data?.name;
    
    var person = new Person { Name = name, RowKey = name, PartitionKey = "todoPartition" };

    personTable.Add(person);

    return name != null
        ? (ActionResult)new OkObjectResult($"Hello, {name}")
        : new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}

public class Person
{
    public string RowKey { get; set; }
    public string PartitionKey { get; set; }

    public string Name { get; set; }
}

Podsumowanie

Na dziś koniec części pierwszej artykułu o Table Storage. W przyszłym tygodniu zajmiemy się konfiguracją funkcji w wersji pre-compiled.

Share