39

Build & publish Azure Functions app that uses a budget SQLite database &...

 2 years ago
source link: https://blog.medhat.ca/2022/03/cheap-data-storage-using-sqlite-with.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

In this tutorial I will build a Web API application using Azure Functions & SQLite. Although it is not typical to use SQLite with Azure Functions, this is a decent option if you want to have a cheap storage solution. I will later deploy the SQLite enabled Azure Function. This tutorial was done on a Windows 11 computer with VS Code.

Prerequisites

Create a folder named SQLiteFunction on your hard drive at the location where your project will reside. 

Under the Functions tab in VS Code, create a new Azure Functions project.

Navigate to the location on your hard drive that you have designated as your workspace folder for this project. You will next be asked to select a programming language. Choose C#.
AVvXsEhK8uufljdWdBVokMBXNW-dlS-9WABQo6c-Y9Z1YeWhri-xl_XDvm1x7dUhm2dwsCg5V69faZFx_vyyXj-M9Fn36RrJAKeh1p-bV_dP9lK2i0T1dgm_m9vYNZAppdmY93Nu6JbAEzsB8NzB9PirdFx6tW8bwJL4H5St1EIfdTJ9p4A_9uTbmX41kj4yAw=w400-h274
You will then be asked to choose the .NET runtime, choose .NET 6:
AVvXsEhIUkFBO-J3ihQEn570Vx3AZYvtWH_QkD6y0flqPloe_WlmVM-06z3K2XD5DikzieMRk7ZJdi5IbF8z2sZh04EGtrzpEMip8SLLPisFxTtAQsiyf7vJdrlSvdv-07SCOdrGwHcpvyPGp1vwREUowtf9canYq4L8iVgEt1HxqfJwrcbbU1gNaMFbAIm1Gg=w400-h98
You will be asked to choose a template for your project's first function. Note that you can have more than one function in your project. Choose HttpTrigger.
AVvXsEhJn3wuNu9xJvJ4N1ZnazpBVr54OYI3ovNBmE5NTW_r7-ZaL3xja79isPrqPo-xQOS41Di3iVk_B8NDCb37_CqzX7UXVHnY3-C1AZtb8hwayiVWh1NxL84eoaK2AlI8BYDX0zGd01DzVD9EA_InCY5h2rPbbFeCJ7fJ5iabaEz58ZckQZBgm7SP-1DtHA=w400-h266
Give your function a name. I named my function HttpApi.
AVvXsEhZCINd_VvzbdC8wkGp1mezRwXitRu0fRANAK_agyp6RhdvtZ6y4ENZnU5e2JWgSXpS6kexz5LgbkLMXgyB5YylTduxvdHw1hEaL6BiKp1lPY7mWvLNM_Xeu3Y8sv9-likNAHYI-r5_yGWtHord9ZQTbVszrylYtC-LWuAEh63lGmWWd06l90nE4iZ7Qg=w400-h68

Hit Enter after you give your function a name. Give your class a namespace. The namespace I used is SQLiteFunction. I then hit Enter.

AVvXsEh_mSmgI65HQQ3q-c-Us3Q0A37GVqovvHXR5w69jKs69hDTrLZ3jTgFT_3rIiFvNkNL0DVnvowfFh9giAP66y99fPeySvDzsl8bTQPpu2YtocsUNcgQZSAenKMr_yJ5APfBSWcbAuIY_EnHt0GCj5qrzf5ZbCkUkXIXZux7mPN-TBIdUc09M69yCtyQhQ=w400-h65
Choose Anonymous for AccessRights.
AVvXsEghLKVRdPX0xREY5WcNOYQAKxwmZk-FpBDncs696C3RB9Y7WKGEsYrUmao1y0DfCIUKz3ldA0v-TwzRvkZL1Fa5K-h9EziK7DbSRHSt1cZTZ12TwW1eq34ktUYw00Zv3I3h0V6JRRJ_4cqVEsmv_KZ3oyw3jABBEnYnRhNaVLkdi_p4Fwxt-3FBc0m7Mg=w400-h96

When asked about how you would like to open your project, choose "Open in current window".

AVvXsEjZ9SrdcxQ5Dc97hGlotEWRA18BLJ3X5MVNGl5WCP2Nk2j1U8tg0t3D8L0_43dckoupuajgmiOrDkLuqf368T9MlyPIdU2e6RqxX461WipeACnw50LbB2G1SqwALCuDISR-yZtIootr2sfdlB6aq4ax8wAlE2OHELOyLItFiQQ8eU2FBbLMQRnSoHoPuQ=w400-h94
If a popup window appears asking if you wish to restore unresolved dependencies, click the Restore button.
AVvXsEiaGw-QwJYRDoRtaRZ1HWaok701juWE8QFEVZS-2ZVQ1cm6U59iJ7_mLztNQLbj2SarDaz3oZfktuPgH_fH3eV6K0HTlqvA35oV8XtiIBuduU-ql3PoSQcUDgg67g_sPvjAPMEWQrT32DHFh9nXVFLCP2K-_fHgnHuUpkPQUUnVri71WjPA8f-p83TNyg=w400-h101
Let us see what the app does. Hit CTRL F5 on the keyboard. The built-in VS Code terminal window will eventually display a URL that uses port number 7071:
AVvXsEjzwZA6et7XYzODhahO9XgXS6kSSCTL8EZ1HGkINUUUgiJ5k_MbdnxLWcPT0F4jlwV8FYzIoTSZZPlZRLzZtPgabrTbfcVSlLKKw5Y2Yi_gQqda6Nny0Uwv1-zK66eYOENE6RUnjYyjoxC_3o0GrvqF9fUzImFeOUEciBBktipP1bqpDsdBi2iYJeCy1w=w640-h162

NOTE: You can start your function app with the terminal command: func start

Copy and paste the URL into a browser or hit CTRL Click on the link. You will see the following output in your browser:

AVvXsEhg1GHXNbaBhsJAdQM830ZfkgxFtj86O4PNnkhHWU8l3IRsshIPdyVr4PTwrFjJYUBGONNXynfce1W5kso9wOiDnox1Ts9B_Pi-GArWu-roXLc_TmXV6X3HxZRohUGnbhoouZR2LeOwAUr4A0Olbzx3w7CfHXDxtVxxvSWkU-V0MHwCtMJbcb8J2ekcyg=w640-h51
The message in your browser suggests that you should pass a name query string. I appended the following to the URL: ?name=Superman and got the following result:
We will need to add some NuGet packages. Execute the following dotnet commands from a terminal window in the root directory of your project:
dotnet add package Microsoft.Azure.Functions.Extensions
dotnet add package Microsoft.EntityFrameworkCore.SQLite
dotnet add package Microsoft.EntityFrameworkCore.SQLite.Design
dotnet add package Microsoft.EntityFrameworkCore.Tools
Let us make a few minor enhancements to our application.
1) Our SQLite database will be named school.db. Add the following to the project's .csproj file so that the SQLite database is copied to the output directory when the app gets built:
<ItemGroup>
 <None Update="school.db">
   <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
 </None>  
</ItemGroup>
2) Change the signature of the HttpAPI class so that it does not have the static keyword. Therefore, the signature of the class will look like this:
public class HttpApi
3) Create a Models folder and add to it a simple Student.cs class file with the following content:

using System.ComponentModel.DataAnnotations;

namespace SQLiteFunction.Models;
public class Student {
    public int StudentId { get; set; }
    [Required]
    public string FirstName { get; set; }
    [Required]
    public string LastName { get; set; }
    [Required]
    public string School { get; set; }
4) We will deploy our Azure Functions app to a Windows server on Azure. When the school.db SQLite database file is published to Azure, it will reside in directory d:\home\site\wwwroot. Therefore, we shall create a helper class that will locate for us the SQLite database file in both development and deployment environments. Create a file named Utils.cs in the Models folder and add to it the following code:
using System;
namespace SQLiteFunction.Models;
public class Utils
    public static string GetSQLiteConnectionString()
        var home = Environment.GetEnvironmentVariable("HOME") ?? "";
        Console.WriteLine($"home: {home}");
        if (!string.IsNullOrEmpty(home))
            home = System.IO.Path.Combine(home, "site", "wwwroot");
        var databasePath = System.IO.Path.Combine(home, "school.db");
        var connStr = $"Data Source={databasePath}";
        return connStr;
The above helper class provides us with a static method Utils.GetSQLiteConnectionString() that returns the fully qualified location of the SQLite database file named school.db.
5) Add an Entity Framework DbContext class to the Models folder. In our case, we will add a class file named ApplicationDbContext.cs with the following content:
using Microsoft.EntityFrameworkCore;
using System;
namespace SQLiteFunction.Models;
public class ApplicationDbContext : DbContext
    public ApplicationDbContext() { }
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
    public DbSet<Student> Students { get; set; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        if (!optionsBuilder.IsConfigured)
             optionsBuilder.UseSqlite(Utils.GetSQLiteConnectionString());
    protected override void OnModelCreating(ModelBuilder builder)
        base.OnModelCreating(builder);
        builder.Entity<Student>().HasData(
              StudentId = 1,
              FirstName = "Jane",
              LastName = "Smith",
              School = "Medicine"
          }, new
              StudentId = 2,
              FirstName = "John",
              LastName = "Fisher",
              School = "Engineering"
          }, new
              StudentId = 3,
              FirstName = "Pamela",
              LastName = "Baker",
              School = "Food Science"
          }, new
              StudentId = 4,
              FirstName = "Peter",
              LastName = "Taylor",
              School = "Mining"
The above context class seeds some sample data pertaining to four students.
6) To register a service like ApplicationDbContext, create a class file named Startup.cs in the root of your application. The Startup class implements FunctionStartup. This class will look like this:
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using SQLiteFunction.Models;
[assembly: FunctionsStartup(typeof(SQLiteFunction.StartUp))]
namespace SQLiteFunction
    public class StartUp : FunctionsStartup
        public override void Configure(IFunctionsHostBuilder builder)
            builder.Services.AddDbContext<ApplicationDbContext>(options =>
                options.UseSqlite(Utils.GetSQLiteConnectionString());
        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
            base.ConfigureAppConfiguration(builder);
7) Inject the ApplicationDbContext class that is needed by your function class. Open HttpApi.cs in the editor and add the following instance variables and constructor at the top of the class:
private readonly ApplicationDbContext _context;
public HttpApi(ApplicationDbContext context) {
   _context = context;
8) The next step is to apply Entity Framework migrations. Open a terminal window in the root of your application and execute the following EF migration command inside the same terminal window:
dotnet-ef migrations add m1 -o Data/Migrations
This produces a Data/Migrations folder in your project.
9) The next step is to create the database and tables. Execute the following command in the same terminal window as above:
dotnet-ef database update
If all goes well, you will receive a message that looks like this:
Applying migration '20220314204919_m1'.
Done.
10) Let us now create an endpoint in our Azure function that returns all the students as an API. Add the following method to the Azure functions file named HttpApi.cs:
[FunctionName("students")]
public IActionResult GetStudents(
   [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "students")] HttpRequest req,
   ILogger log) {
   log.LogInformation("C# HTTP GET trigger function processed api/students request.");
   var studentsArray = _context.Students.ToArray();
   return new OkObjectResult(studentsArray);
All that is left for us to do is test out our application and make sure it returns our students data. Run the application by hitting CTRL F5 on the keyboard. You will see the following output in a VS Code terminal window:
AVvXsEgwzq1io7GNM9TlqgNtrucP9y2K_kTFzYbsaiCgTr-DR0PyRjosXBbUmGzLuSJM7Dgze_-XRfHjvSz-YMz_NZtPJ0rpUJ3eDIndXvSvwsK7RbEg56ZZBNW5IP2xteBpBUNwrodbe0dvzG546InHc89gINn5RzgiRs5f31PMrRFq4cyMlQVourXx-upSpQ=w640-h202
Copy and paste the /api/students endpoint into a browser. Alternatively, you can simply hit CTRL Click on the link. The result will look like this:
AVvXsEiSOpBMikyyB6pGqbESqIE0uvvrUqT0buZ_0mo1o1ydL1awteLV6f4bW1ApLrx5HqB2P9OSg7CX6ZHD0EPkwSXz7-yivccaEsbzx8J8fNd0lrbzbz3-1XhkXkq1rQJ0JOW8WJze-pSfFf76dMlqmvg2BDtz2GDFUri1W7fmOIy5s6ZSQ0PY79DDTSQfFQ=w640-h122

Deployment to Azure

Click on the "Deploy to Function App ..." icon.
Select your subscription.
Choose "+ Create new Function App in Azure ...".
Enter a globally unique name for your function app then hit Enter.
AVvXsEiwVbPH-Bpv8QXk1qAgzfUcOrypC1Vvigd2xer2anmhzNc7-1eghMnzq-BEtBAZOaXerBND0WFoqnFIZp06S6RLGoyYMevwRlCjqCk0dzyEI699da91tDKzyHBJFDzpMYCbDKi_P8x8oFSPdPAlULi1N9l6_Jfs-_8SCHbWu_zobmbN5MkBlU9ykHxdZA=w640-h130
Select .NET 6 for runtime stack:
Choose a preferred data center.
The deployment process starts. Be patient as it could take 3-4 minutes. When deployment is complete you will see the following message:
If you click on the "View output" you will see the two endpoints. 
AVvXsEio5FYnCx9nEJqzayDuRzWz-PefLBykTV-CxBPu87cPi68IdXOf7-VGX5KOBirWr-3MofgH276wT_ufLCOt2b2-rsc7hQlcJ3dTpCDJ8zGOJP4Hr9baamBWeY6jY9mKTXwTkxNsjNQrowRcU3nI55lvEtZ_zc3a3P5Dlv1x1fob_OiAh7R5fMhVtPH0EA=w640-h170
Although the first endpoint works, the second does not. To fix this problem, login into the azure portal https://portal.azure.com. In the filter field, enter func then choose "Function App".
AVvXsEin2alRNNy9fQWEfxS-57WF6muKyGQTaTXEZ79SmjxsCyeeJWqArS9bO6msxucYsUtvyVlYJO_xlDaNwSVzmKL58NEOfneICl4WbiYTew_23l4w1eGoKbimrINHWgGXqR1aRff-kpm4y1Tf4DoxbXZy3x8eNhLWDjosWy-FlkPfseCFBhIjtji2yteOBA=w400-h215
Click on the function that was created.
AVvXsEjJTbRbZV-WG65rHPFja4EyD72hG5mHRciHRmFCw_ZyO6rAbPj3Jf3tf-x4MLWlfOyljIHJJ9atbxmzV1tX7bccuxr8QobQG7H2xp7u0D1kUD1ikQN4pZYYRx695jZxkzEXcbQgwcKSoLhgmRF37coFuMwJVufhcLjCZjkKfVuXS4hrYZ9EyaXcHIm9PA=w400-h244
Select Configuration on the left navigation.
Click on WEBSITE_RUN_FROM_PACKAGE.
AVvXsEhSgr8bnRvN8WqAfoqkIu0rb-nhnYhGVB9ZXfA7J9WiIfoSVVn-ZLhNVaXeIYbp1xzsmsT072V5sDD52aWbeLA0KtsY_Za6ygJOQaC-RXi5EzXDYy_zVGCLlGpl_mA4tDk1Mz7reH5msqBR42GNPr2RStsftoB0b2gzCjwNWJgwZueqVUzri4wpuLs9Rg=w400-h294
Change the value from 1 to 0 then click on OK.
AVvXsEgIXPkZ1JJdik7kfm5tnEqdq90Em7I8zrHhjnqmgStlz2p6fljyUg4XwBGGfQWqPE9wNstDRttT3ELYlWv4uyrMSuFqncwXlvBwkVdDs6L1a1hAJBaPyWmRXV-b2N9LyY27xKzghNNjT1uDXHRebQ4QW5QyE2X0C02wimrWc3F28PNC2KPfFovI-8DzaA=w230-h400
Remember to Save at the top.
Back in VS Code, publish your functions app again.
Click on Deploy to confirm.
AVvXsEgSkyZyVg7wl__16M-8-vQk8uXH03ihWUfoJb17TUrAxEUB7igDSpP9RWIf4kDOORb6erEQI2uLWxnerUGF0kBmVPmj77BJWBjkuhPdoP-nle9Bpw9MM8yoiEgYW8FrnrBbfwtRIm-I421nMQw0k8cfcjFZi6pRPmRwYnj6j913d2T7cyYsQrDF5iG_fw=w400-h88
This time, deployment will not take as long as the last time. Once deployment is completed, try the /api/students on the deployed endpoint and you should find it working to your satisfaction.
AVvXsEiFnOl-In0-FG-Ll_BvXE2aQ1CMpepNJZh0RIIDAEygPaHTjQXeYiK1WKKBuv0T18WTcJeDbbZ4U1IlsTKFZrGhpUgiTl1H4U-EvyaWm2C8jUuXkwAzoJXm_TB4kN4eQmpRWot-455tUqqCcxheW7h6TcIpArtLnQEYJLMFybyLGKfwElTcFArkosD3Bw=w640-h64

Conclusion

It is easy to create Azure Functions with the SQLite. Also, creating an API with Azure Functions is much more cheaper than doing it with an ASP.NET Core Web API application because you pay a fraction of a cent for every request and the app does not need to be constantly running. It is also worth mentioning that using SQLite makes it even cheaper as you do not need to pay extra for hosting your relational database.

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK