如何快速构建一个带有绑定和数据库的无服务器 C# .Net Core API
在Twitter上关注我,很高兴接受您对主题或改进的建议/Chris
本文是#ServerlessSeptember的一部分。在这个关于无服务器的全系列内容中,您可以找到其他有用的文章、详细的教程和视频。九月份,社区成员和云倡导者每天都会发布新文章——没错,就是每天。
无服务器在很多方面都很出色。
你对无服务器的第一印象可能是它能帮你省钱。你意识到有些代码很少运行,于是就把它们移到 Azure 函数中。太好了,你现在已经很满意了,谁不喜欢更多的资源呢?然后你发现了其他同样好甚至更棒的东西。因为它驻留在云端,所以几乎不需要任何配置就可以将它应用到你在云端的所有服务中。怎么会这么简单?之所以这么简单,是因为我们用了一种叫做绑定的东西。那么,让我们来谈谈无服务器,以及绑定为什么以及如何成为无服务器成功故事的一部分。
在本文中,我们将介绍:
- 无服务器,它是什么,我们为什么要使用它?
- 核心概念,让我们介绍绑定和触发器
- 演示,让我们使用绑定和数据库构建一些东西,并展示它是多么简单
资源
-
注册一个免费的 Azure 帐户
如果您想构建逻辑应用程序和 Azure 功能,您将需要一个 Azure 帐户,它是免费的。 -
关于 CosmosDB 和 Azure Functions 的很棒的文章,
很棒的文章,总体来说很棒的博客
无服务器
无服务器现在人人都在谈论。无服务器这个,无服务器那个。为什么呢?
部分原因是,如今云已成为默认的托管平台,几乎不再需要服务器机房。云实际上是别人的服务器机房,但归根结底,你无需关心这些。云在很多方面都有帮助,包括安全性、可靠性、备份、可扩展性,以及最重要的,它能够让云中的其他设备相互通信。
那么这为什么很棒呢?
大多数公司都拥有大量的服务,这些服务共同构成了他们所谓的“业务”IT架构。让所有或大部分服务相互通信是一项耗时耗力的任务,或者至少需要耗费大量资源。如今,大多数云平台都非常擅长在云内甚至跨云连接这些服务。
那么无服务器适合于哪里呢?
无服务器技术是在云计算发展过程中经历了诸多阶段之后才诞生的。最初,我们决定不再管理硬件。后来,我们决定不再处理应用服务器。因此,我们最终决定只关注代码、代码,以及一切。这意味着一个全新的平台诞生了,或者说 FaaS(函数即服务)。随着无服务器技术的出现,我们意识到了其他一些事情。我们越来越意识到,我们只想为实际的代码执行付费,而这正是无服务器技术所能提供的——完全托管,按使用量付费。
但这不是我们阅读这篇文章的原因吗?
正确,我们在这里学习如何使用称为绑定的东西将无服务器功能与其他东西集成。
核心概念
当谈到集成和无服务器时,我们需要了解三个主要概念,它们是
- 触发器,这就是我们函数被调用的方式。触发调用的原因可能是 HTTP 调用、新的数据库条目、队列中的新消息,甚至更多其他因素。重点是,触发器是启动我们函数的关键。
- 输入绑定,这是与某种数据源的连接。其目的是从该数据源读取数据。这些数据可以是 Excel 文档、数据库或队列等。
- 输出绑定,即我们创建一个与数据库的连接,明确地想要更改数据。通常,我们会访问一条可以填充的记录,然后这条记录会进入数据源,通常用于更新或创建新数据。
现在,我们知道了开始之前需要知道的最重要的概念。
演示
好的,那么我们要构建什么呢?为了展示无服务器的强大之处,我们至少需要连接两样东西。这意味着我们需要构建/配置:
- 数据库,我们将提供一个 CosmosDB 数据库
- Azure Function App,当然,我们需要构建一个与我们的数据库连接的 Azure Function App
数据库
这一步很简单。我们需要登录 Azure 门户。您有账户吗?如果没有,可以在这里创建一个免费Azure 账户。
以下是我们需要采取的所有步骤:
- 提供我们的数据库
- 设置数据库并添加示例数据
提供我们的数据库
好的,我们已经登录到门户了。现在让我们像这样配置一个数据库:
接下来,我们需要输入一些有关数据库的信息。以下列出了所有需要填写的必填字段。请确保选择API
“作为” Core(SQL)
,并确保选择距离Location
您较近的机构,以获得最佳响应时间。
最后,点击Review + Create
底部。这将触发配置。几分钟后,您的资源/数据库就可以使用了。
设置数据库
现在我们的资源已配置完毕,可以开始配置了。我们要做的第一件事是添加一个容器。
什么是容器?
很高兴你问这个问题 :) 容器实际上用来存放我们的数据或实体。容器本身包含一些叫做文档 的东西。
要创建容器,我们Data explorer
从左侧菜单中选择,然后单击New Container
,如下所示:
下一步是填写创建容器所需的所有详细信息。
它将要求您填写以下字段:
- 数据库 id,你可以给它起任何你想要的名字,我选择将其命名为database-chris
- 吞吐量,赋值为1000
- 容器 ID,这是集合的名称。集合包含文档列表。每个文档就像表中的一行,表和集合大致相同。将其命名为“书签”
- 分区键,分区键指定 Azure Cosmos DB 集合中的文档如何在逻辑数据分区之间分布。这到底意味着什么?这意味着该数据库可以在云中扩展。我们告诉它如何扩展以及如何使用分片技术来实现扩展。赋值/id
该表单将如下所示:
添加示例数据
好了,数据库现在设置好了,我们可以开始往里面填充数据了。下一步是点击Collection
书签,然后Items
点击 ,Net Item
在收藏夹中插入一条记录,如下所示:
如您在右侧看到的,它打开了一个文本区域,我们可以使用它来插入数据。让我们将其更改为以下内容:
{
"id": "docs",
"url": "https://docs.microsoft.com/azure"
}
然后点击Save
。像这样添加更多记录:
{
"id": "portal",
"url": "https://portal.azure.com"
}
最后一条:
{
"id": "learn",
"url": "https://docs.microsoft.com/learn"
}
Azure 函数应用
好的,我们已经有了数据库和数据源。现在是时候构建一个 Azure Function 应用和一个 Azure Function,并真正演示连接数据源是多么简单。我们将执行以下操作:
- 搭建Azure Function 应用和 Azure Function 的基架
- 建立数据库连接
- 从我们的数据库中读取信息,从而了解输入绑定
- 写入我们的数据库并从而了解输出绑定
先决条件
为了能够搭建我们的 Azure Function 应用程序,我们需要安装一些东西,即
- Azure 核心工具
- VS Code 的 Azure Functions 扩展,扩展
- 免费的 Azure 帐户或现有帐户(如果有)
好的,都设置好了没有?
好的,我们继续吧!:)
搭建 Azure Function App 的基架
打开 VS Code。选择View/Command Palette
(Windows 上按 Ctrl + Shift + P,Mac 上按 CMD + Shift + P)。
开始输入Azure Function: Create new Project
并选择它。
- 选择当前文件夹
- 选择 C# 作为语言
- 选择 HttpTrigger 作为我们的第一个函数
- 命名
Bookmarks
- 您可以随意命名命名空间,但我们先使用
Company
。 - 选择授权类型
Function
将会弹出一个窗口restore dependencies
。点击该窗口,或者如果你错过了,请前往终端并输入dotnet restore
。这样它就会下载所有指定的依赖库。
好的。我们已经得到了一个名为的函数Bookmarks
,它位于中Bookmarks.cs
,如下所示:
我们开放一下Bookmarks.cs
好吗?
// Bookmarks.cs
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Company
{
public class Bookmark
{
public string Id { get; set; }
public string Url { get; set; }
}
public static class Bookmarks
{
[FunctionName("Bookmarks")]
public static async Task<IActionResult> Run(
[HttpTrigger(
AuthorizationLevel.Function,
"get",
"post",
Route = null)
] HttpRequest req,
ILogger log
)
{
log.LogInformation("C# HTTP trigger function processed a request.");
string name = req.Query["name"];
string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
dynamic data = JsonConvert.DeserializeObject(requestBody);
name = name ?? data?.name;
return name != null
? (ActionResult)new OkObjectResult($"Hello, {name}")
: new BadRequestObjectResult("Please pass a name on the query string or in the request body");
}
}
}
我们最感兴趣的是函数的顶部,让我们放大它:
[FunctionName("Bookmarks")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
ILogger log
) { /* function body */ }
我们可以看到,该属性FunctionName
用于确定我们正在处理一个函数,并且该函数被调用Bookmarks
。然后我们可以看到,我们有一个属性HttpTrigger
,表示它可以由 HTTP 调用触发。
添加 CosmosDB 输入绑定
那么,我们如何将 CosmosDB 添加到其中呢?有两种方法:
-
将 CosmosDB 属性添加到我们的文件中
Bookmarks.cs
,然后从终端安装正确的 NuGet 包,以确保所有内容都能编译 -
添加一个带有 CosmosDB 触发器的函数,这将安装所需的依赖项,还将触发一个存储对话框,让您选择存储帐户、数据库名称和集合
让我们尝试第一个选项。首先,打开终端并输入:
dotnet add package Microsoft.Azure.WebJobs.Extensions.CosmosDB
现在我们准备好进行下一步,即向我们的Bookmarks.cs
文件添加输入绑定。
为此,我们将使用一个名为的属性类CosmosDB
。我们需要赋予它一些值,即
- 数据库名称,这就是我们命名数据库的名称,即database-chris
- 集合名称,我们将集合命名为书签
- 连接字符串,至于连接字符串,我们可以在 Azure 门户中找到。前往资源,点击菜单中的“键” ,然后复制“主连接字符串”中显示的值。
现在,我们可以在代码中添加数据库名称和集合名称,如下所示:
// excerpt from Bookmarks.cs
[FunctionName("Bookmarks")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
[CosmosDB("database-chris", "Bookmarks", ConnectionStringSetting ="CosmosDB")]IEnumerable<Bookmark> bookmarks
ILogger log
) { /* function body */ }
上面我们添加了属性类CosmosDB
并修饰了参数bookmarks
。我们可以看到bookmarks
是类型IEnumerable<Bookmarks>
这个类型从何而来
Bookmark
?
这是我们需要创建的类型,无论是在文件中Bookmarks.cs
还是在它自己的文件中,但它需要具有以下形状:
public class Bookmark
{
public string Id { get; set; }
public string Url { get; set; }
}
它具有属性Id
并且Url
与数据库中的形状相匹配。
进一步查看代码,我们给出ConnectionStringSetting
值CosmosDB
它从哪里来?
它来自一个文件local.settings.json
及其Values
属性,如下所示:
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet",
"CosmosDB": "value of primary connection string"
}
}
尝试一下
让我们首先在函数的第一行设置一个调试器Bookmarks.cs
。
在 VS Code 的菜单中选择Debug/ Start Debugging
。
转到浏览器并输入http://localhost:7071/Bookmarks
,您的断点应该被命中,如下所示:
正如您所看到的,我们的bookmarks
变量已填充数据,我们正在与数据库对话,并且它正在为我们提供数据,成功:)
限制我们的反应
上面的代码很棒,我们从数据库中获取了数据。但是,数据库中可能有数百万条记录,该如何限制响应量呢?
这很容易做到,我们需要向我们的CosmosDB
属性添加两个参数,即:
- ID
- 分区键
关于分区键,值得学习。可以阅读CosmosDB 的分区键。
好的,我们要做的是添加一个新函数,该函数可以query
从触发器中获取参数,并使用它来查询 CosmosDB。因此,请添加以下函数:
[FunctionName("GetBookmark")]
public static IActionResult GetBookmark(
[HttpTrigger(AuthorizationLevel.Function, "get", Route=null)] HttpRequest req,
[CosmosDB(
"database-chris",
"Bookmarks",
ConnectionStringSetting = "CosmosDB",
Id = "id",
PartitionKey = "{Query.id}"
)]Bookmark bookmark,
ILogger log
)
{
return (ActionResult) new OkObjectResult(bookmark);
}
现在启动我们的应用程序并在浏览器中运行以下 URL 。这将确保使用值http://localhost:7071/api/GetBookmark?id=portal
查询我们的 CosmosDB 。结果应该是这样的:id
portal
输出绑定
我们使用输入绑定从数据库读取数据。输出绑定用于写入数据库。让我们看看两种不同的场景。
- 创建,我们将从触发器中获取查询参数,并使用它们在我们的数据库中创建一个条目
- 更新,我们将采用现有条目并更新该条目
创造
那么,创建输出绑定需要什么呢?嗯,几乎不需要。我们唯一需要的就是在 type 函数中添加一个新参数out
,如下所示:
out dynamic bookmark
让我们创建一个新的专用函数并调用它CreateBookmark
并像这样定义它:
[FunctionName("CreateBookmark")]
public static IActionResult CreateBookmark(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route=null)] HttpRequest req,
[CosmosDB("database-chris","Bookmarks",
ConnectionStringSetting = "CosmosDB")]out dynamic bookmark,
ILogger log
) {
string id = req.Query["id"];
string url = req.Query["url"];
bookmark = new { id = id, url = url };
return (ActionResult)new OkObjectResult("created");
}
现在启动程序,并http://localhost:7071/api/CreateBookmark?id=devto&url=dev.to%2Fsoftchris
在浏览器中输入如下 URL。就这样,这应该会创建一个新条目。不相信吗?在门户中查看一下你的数据库:
更新
因为这是 CosmosDB。这意味着,如果存在一条具有该 ID 值的现有记录,它将被直接替换。然而,这可能并非您所想。如果您只想更新某些属性,我建议您采用以下方法:
- 使用输入绑定检索现有记录
- 将输入记录中的值复制到输出绑定
- 将从触发器获取的任何值复制到输出绑定
就是这样,这就是我们的两个更新方案。
概括
我们学习了输入绑定和输出绑定。输入绑定允许我们从数据库中读取数据,而输出绑定允许我们创建或更新数据。此外,我们还学习了如何配置 CosmosDB 数据库并使用名为 CosmosDB 的属性类连接到它。当然也可以将 CosmosDB 作为触发器,但那将是另一篇文章的内容 :)
文章来源:https://dev.to/azure/how-you-can-build-a-serverless-net-core-api-in-no-time-with-bindings-and-cosmosdb-2eg8