五、使用 Azure 逻辑应用和功能构建推特自动活动管理器

自从 200 多年前查尔斯·巴贝奇构想出第一台计算机以来,计算的目的就是自动化和精确。也就是说,我们希望计算机能做我们能做的事情,但速度更快,错误更少。自从模拟计算机时代以来,事情已经发生了很大的变化,现在我们有了可以保存千兆字节数据的系统,而且我们通常把计算机放在口袋里,这让 50 年前把人送上月球的计算机蒙羞!然而,所有这些的前提都是一样的:我们只是希望计算机做我们能做的同样的事情,但是速度更快,错误更少。

我们在这一章中要解决的特殊问题在很大程度上是自动化问题:想象一下,你刚刚在一家新公司开始工作,作为你的第一份工作,你登录了推特,并被告知该公司希望发起一场营销活动来销售他们的新产品。你的任务是定期发送推文,让人们了解他们的新产品。你可以坐在那里,每隔半小时手动输入这些条目,但是如果你能在不到半小时的时间内自动完成这个过程呢?

在这一章中,我们将讨论微软的工作流引擎,逻辑应用,我们将看到如何用很少的代码,我们可以生成一个完全自动化的系统,可以执行相对复杂的任务。

本章将涵盖以下主题:

  • 从头开始创建微软逻辑应用
  • 将微软逻辑应用与 Azure 功能和微软 Excel 集成,以获得更多功能

在本章中,我们将构建一个逻辑应用,它将读取微软 Excel 电子表格,并根据内容发布推文。虽然我们需要的大部分功能将在逻辑应用中提供,但我们需要调用 Azure 函数来进行一些日期计算。

技术要求

与前几章一样,您将需要 Azure 订阅。您还需要一份电子表格,或者访问 Office Online。最后,您需要一个 OneDrive 帐户——这些帐户可以免费设置,并且可以在这里找到:https://onedrive.live.com/

因为我们在这个项目中使用了推特,所以你需要一个有效的推特账户。如果没有,那么可以在这里创建一个:https://twitter.com/signup

与本书其他章节一样,本章的代码可以在这里找到:https://github.com/PacktPublishing/C-8-and-.NET-Core-3-项目-使用-Azure-第二版

工作流引擎、逻辑应用和功能概述

工作流引擎已经存在了一段时间。基本上,这个想法是你有一个非常高级的系统,你可以把复杂的、独立的组件插在一起。微软对此的实现有一个非常直观的图形界面,可以在网络浏览器或 Visual Studio 中编写。当您找不到满足您需求的预构建组件时,您可以调用一个 HTTP 端点,从而允许工作流与 Azure Functions 或另一个云提供商无缝集成。

Azure 函数就是所谓的无服务器;这并不是因为它们很神奇,并且在没有任何硬件的情况下运行,而只是因为您作为开发人员,不需要关心它们在运行什么。它们是功能的小单元——想想 C#中的单个方法——它通常接受一个参数并返回一个值;这正是使用 Azure 函数所得到的结果。

我们已经确定(或者至少在本章结束时我们将确定)使用 Azure Functions 和逻辑应用比从头开始设置所有这些功能更快,但是您还能得到什么?

你得到的主要是规模;你的软件运行在它所需要的硬件上,所以如果你不使用软件,你就不需要付费。如果您遇到使用高峰,微软将提供更多硬件来满足您的软件需求。

创建 Excel 表格

我们需要做的第一件事是创建一个可读的 Excel 电子表格。对 Excel 的任何一种细节的解释都不在本章(和本书)的范围内;但是,在 Excel 中,创建一个新的电子表格并插入一个表格,如下所示:

重命名表(这样以后更容易识别):

At the time of writing, some versions of Excel (the free online ones) don't support the renaming of a table.

将 Excel 文件保存在您的 OneDrive 帐户中。我们将很快回到这个文件,因为它将被用作这个应用的数据源。

在 Azure 门户中构建逻辑应用

在本章中,我们将使用 Visual Studio 和逻辑应用功能(作为扩展提供)来创建和测试我们的应用。但是,在此之前,我们将快速了解一下,如果您选择直接在 Azure 门户中进行构建,您会在哪里进行构建。

在 Azure 门户中,搜索logic apps,然后选择逻辑应用服务,如下所示:

Remember that once the blade has launched, you can pin it to your dashboard using the pin icon on the top right-hand corner.

当刀片启动时,您将看到您当前订阅的任何逻辑应用;如果您没有,那么您将看到一个按钮,邀请您创建一个,如下图所示:

从这一点来看,在 Azure 门户中创建逻辑 app 的过程与使用 Visual Studio 基本相同。如下表所示,在 Azure 门户中创建应用和使用 Visual Studio 插件各有优势:

| Visual Studio | 蔚蓝门户 | | 源代码控制很容易,对逻辑应用、相关功能和 web 作业的更改可以放在一起 | 更改会被跟踪,但源代码控制并不那么容易 | | 功能稍微落后于门户 | 最新功能 | | 需要安装 Azure 工作负载和逻辑应用扩展 | 不需要在本地机器上安装任何软件(甚至不需要 Visual Studio) |

从这里开始,我们将切换到 Visual Studio。

在 Visual Studio 中构建逻辑应用

在开始之前,我们需要经历几个安装步骤;首先是在 Visual Studio 中安装 Azure 工作负载。

Azure 开发工作负载

为此,请运行 Visual Studio 安装程序,并在运行的版本上选择修改,如下所示:

The Visual Studio Installer is a part of the initial installation and is where you change or update your installation of Visual Studio.

选择(或勾选)Azure 开发工作负载,然后选择修改:

如果您当前正在运行 Visual Studio,则需要在更新进行期间关闭它。下载和安装可能需要几分钟,所以这可能是喝咖啡的好时机!

Workloads are collections of features that allow Visual Studio to perform certain tasks, or be aware of certain languages.

逻辑应用扩展

要安装此扩展,首先启动扩展和更新...从 Visual Studio 的“工具”菜单中,如下所示:

这是您可以管理 Visual Studio 扩展的地方。我们将在此搜索我们的逻辑应用扩展,如下所示:

一旦您安装了这个,您将需要重新启动 Visual Studio,一旦您这样做了,您应该准备好开始开发我们的逻辑应用。

创建资源组

现在我们已经安装了 Azure 工作负载和逻辑应用扩展,还有一些功能可用;其中之一是能够创建一个新的项目类型:Visual Studio 中的资源组。我们现在就开始吧:

一旦创建完成,您将看到第二个对话框,询问您想要创建什么。选择逻辑应用,如下图所示:

创建的项目有三个文件,如下所示:

Deploy-AzureResourceGroup.ps1是一个 PowerShell 脚本,它将把你的逻辑应用部署到 Azure 中。另外两个文件是逻辑应用模板本身,描述为 JSON。

如果愿意,可以直接编辑 JSON。如果你有一个非常小的变化要做,或者如果你希望比较或合并变化,这很有效,但是尝试创建这样的逻辑应用至少会有挑战性!相反,右键单击LogicApp.json文件并选择使用逻辑应用设计器打开:

您将被要求选择一个 Azure 订阅和资源组来关联您的应用。然后,您将看到以下内容:

如您所见,有一个有用的小视频让您开始,一些预构建的触发器模板,以及一些几乎准备就绪的模板。

创建工作流

这里的基本流程是在每次循环中询问 Excel 文件,在那里我们找到一个符合条件的行,发送一条带有该行文本的推文,然后删除该行。我们将创建一个空白的逻辑应用,这样我们就可以研究每一步。

步骤 1–选择触发器

一旦您选择了一个空白的逻辑应用,您将看到模板设计器,您需要选择触发器:

A trigger is simply something that will cause the workflow to begin. This could be an event from another system, a file appearing in storage, a message being put on a queue, or just a schedule.

对于我们的情况,我们将只选择时间表,之后,您将获得一个关于时间表类型的选项。在撰写本文时,这里只有一个选项可用,即 Recurrence,所以让我们选择它。

最后,您可以选择希望工作流运行的频率。当我们创建工作流时,保持默认的一个小时;然而,当我们完成它时,我们会将它设置为更具响应性的东西。

The value that you select here may have a very direct effect to the cost of running the workflow. If you have heavy processing running every minute, you might find your Azure bill getting higher. As we're doing very modest processing with this workflow, it shouldn't affect the cost too much to have it run every minute.

一旦您确认了此对话框,循环将被折叠到一个较小的框中,您将能够选择工作流的功能。选择+新建步骤,如下图所示:

Following the initial trigger, you can only add an action, but from subsequent actions, you can add conditions and loops. 

步骤 2–读取 Excel 文件

选择“新步骤”后,您将看到数百种可能操作的列表。搜索Excel,选择 Excel Online (OneDrive):

选择 Excel 类别后,列表会缩小。在结果列表中,选择“列出表格中存在的行”(预览):

As you can see, at the time of writing, this feature was still in preview.

选择此选项后,您将被要求登录 OneDrive。这是一次性事件,但对于需要凭据的每个操作来说都是必要的。然后,您的凭据将被安全存储。

现在您需要选择存储在 OneDrive 中的 Excel 文件和您创建的表格:

If you're using the online free version of Excel, then you won't have been able to rename your table. It will, however, still be visible here, but will be named something like Table1. Where you to have more than one table, it would be difficult to identify the correct one.

在下面的截图中,您可以看到我的文件和表格:

随着逻辑应用的开发,有一点需要注意的是,动作的数量增长很快。与使用默认名称如Button1Button2的 UI 设计者一样,如果您离开默认命名,当您只添加了几个动作时,您会发现自己陷入了混乱。我们将在此处重命名我们的操作:

给它起个能识别它的名字很重要:

You may wish to map out the flow first on paper and give each step a code, for example, 001 GetData and 002 Write File; that way, you can map it back.

由于我的工作流程相对简单,我只是给它起了一个描述性的名字。

下一步是遍历电子表格中的日期,确定哪些是过去的日期;然而,在撰写本文时,逻辑应用并不能很好地处理日期,尤其是 Excel 日期。对于这种事情,能够调用 Azure 函数是非常有用的。典型地,对于像这样的高级系统,一旦你到达它没有处理的东西,你就被卡住了。然而,逻辑应用的美妙之处在于,只要有需要,你就可以简单地降入普通代码。让我们现在创建一个 Azure 函数。

新的 Azure 函数

我们将在同一个解决方案中创建我们的新功能。这使我们能够将逻辑应用的所有功能集中在一起:

我们正在创建的项目类型是 Azure 工作负载添加的新项目类型之一,它是 Azure Functions:

一旦你选择了这个,你会看到一个对话框,询问你想创建什么样的函数。Azure Functions v2 现已推出,它利用了.NET Core,所以我们将选择它,我们将选择 Http 触发器:

对 Azure 函数以及它们能做什么和不能做什么的完整而详细的解释超出了本书的范围。然而,简单地说,函数是可以调用的无状态功能,并且能够自动扩展。

但是,如果您曾经使用过 web APIs,那么默认生成的代码应该不会太陌生。我们应该做的第一件事是从函数 1 更改类名:

我们的新类将代表一个单一的 Azure 函数。下面的代码是您需要的函数代码,所以用这个替换默认函数:

[FunctionName("DatesCompare")]
public static IActionResult Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequest req, ILogger log)
{
    log.Log(LogLevel.Trace, "C# HTTP trigger function processed a request.");
    string requestBody = new StreamReader(req.Body).ReadToEnd();
    return ParseDates(requestBody);
}

如您所见,除了记录它被调用的事实和用请求体调用ParseDates之外,函数在这里没有做太多的事情。这里需要注意的重要事项都在方法签名中。

虽然函数本身被称为Run,但是装饰器表示它将从其他地方被称为DatesCompare;当我们将其插入逻辑应用时,您会看到更多这样的内容。

HttpTrigger表示函数被调用的时间。在HttpTrigger的情况下,该功能作为端点有效地暴露给整个网络;但是,也可以使用其他触发器;这个列表是不断变化的,可以在这里找到:https://docs . Microsoft . com/en-us/azure/azure-functions/functions-triggers-binding

我们来看看ParseDates的方法如下:

public static IActionResult ParseDates(string requestBody)
{
    dynamic data = JsonConvert.DeserializeObject(requestBody);
    DateTime date1 = (DateTime)data.date1;
    DateTime date2 = DateTime.FromOADate((double)data.date2);
    int returnFlagIndicator = 0;
    if (date1 > date2)
    {
        returnFlagIndicator = 1;
    }
    else if (date1 < date2)
    {
        returnFlagIndicator = -1;
    }
    return (ActionResult)new OkObjectResult(new
    {
        returnFlag = returnFlagIndicator
    });
}

这个方法实际上在功能方面做得很少,因为它实际上只是一个条件检查。这里需要注意的重要一点是DateTime.FromOADate。这将从 Excel 中提取一个日期,并将其转化为标准.NET DateTime格式。

我们也在利用dynamic数据类型;实际上,这告诉 C#运行时不要静态地键入变量。这是一把双刃剑;与 JavaScript 一样,这意味着您可以利用编译时不需要编译器知道的结构。此外,像 JavaScript 一样,这意味着如果你拼错了变量名,你可能会得到一个难以诊断的运行时异常或错误。

The dynamic data type should not be confused with the var keyword. The var keyword does represent a static data type; it's merely a way to have the compiler infer that type itself. A dynamic type is not known by the compiler until the code is executed.

部署和测试功能

现在我们已经编写了函数,我们需要部署它,以便逻辑应用设计人员可以看到它。我们将手动发布该函数;右键单击函数项目,然后选择发布...:

您将看到一个对话框,让您有机会在本地将函数发布到目录或 Azure:

暂时忽略其余部分,并选择发布。因为应用正在发布到 Azure,所以下一个屏幕与它将发布到 Azure 的确切位置相关:

一旦成功部署,您将看到以下屏幕。如您所见,有一个指向该函数部署到的 URL 的链接:

如果您点击此链接,您应该可以访问一个网站,该网站向您保证您的功能确实正在运行并且可以访问:

You can use this endpoint just like any other HTTP endpoint; for example, you could construct a call to it using Postman or another similar tool.

好的,所以它在运行;让我们快速测试一下。在天蓝色门户(www.portal.azure.com)中,搜索你的功能。找到后,选择你的函数名(在我这里是DatesCompare):

如果您滚动到右侧,您将看到一个小选项卡面板,如下所示:

选择测试,将出现一个全新的面板。这将允许你在原位测试你的功能。

As with many things on the Azure portal, unless you have an enormous screen, you'll spend a lot of time scrolling around.

要测试该函数,请输入一个示例 JSON 主体,然后选择运行:

现在,我们的功能已经启动并运行,让我们返回到逻辑应用并探索它。

遍历电子表格

逻辑应用提供了标准编程语言中的大部分功能;除了动作,你还有循环和条件。接下来我们需要的是一个循环。在逻辑应用设计器中,选择新建步骤,然后选择控制类别:

选择此选项后,您可以为每个循环选择一个:

The loop will iterate over each element of the table every time it is invoked. It's worth bearing this in mind, especially if you don't have any conditions that will exclude already processed records.

一旦我们创建了循环,我们就可以在循环中添加一个动作,也就是说,一个将在每次迭代中执行的动作:

这就把我们带到了我们正在做的事情的关键,那就是发一条推文。

发送推文

上一节应该会留下一个对话框,提示您选择一个操作:

  1. 搜索 Twitter,如下图截图所示:

  1. 选择后,您将看到推特上有许多可用的操作,但我们只想发布一条推文,因此我们将选择那一条:

  1. 选择该选项后,系统会提示您登录推特:

  1. 登录后,系统会询问您想要发布什么文本。我们在电子表格中已经有了这个,而且很容易获得:

信不信由你,就是这样。目前,工作流每小时运行一次,遍历列表,并发送它找到的任何推文。然而,我们现在有点太热心了。我们仍然需要只拾取具有正确日期的推文的功能,并且一旦推文被发送,我们需要移除该行(否则一旦日期过去,我们将继续发送它)。

添加条件并删除当前行

让我们从条件开始,这给我们带来了逻辑应用的一个非常有用的特性;虽然可以在流程的底部添加步骤,但也可以在现有流程中插入步骤和条件。每一步之间的区域隐藏一个圆圈中的加号;如果您将鼠标悬停在该区域上,它将会出现,并且可以选择:

在这种情况下,我们将选择推文发布上方的区域。选择后,将出现一个上下文菜单,允许您添加操作。如果您选择该选项,您将看到(现在)熟悉的对话框,允许您选择操作。在该对话框中,选择控制,如下图:

这一次,我们将选择条件。当你选择“条件”时,你会看到表面上看起来像是一组复杂的选项;然而,它实际上非常简单。

每个条件必须是一个测试,得出的答案;不能有任何中间立场。例如,如果测试是Is it 5pm GMT?,那么答案要么是Yes, it is exactly 5pm GMT,要么是No, it is not exactly 5pm GMT。逻辑应用需要知道在这些情况下应该做什么:

在我们的例子中,我们的条件只是使用当前日期和时间(即该函数运行时的日期和时间)以及电子表格上的日期和时间(即我们希望推文发送的日期和时间)调用我们的函数。因此,在添加测试之前,我们需要调用我们的函数。再次,在条件上方插入一个操作,如下所示:

现在,只需选择 Azure 函数作为操作类型:

现在应该会出现可用功能的列表,如下所示:

If you don't see your function here, then the likelihood is that there was a problem while publishing the function.

一旦选择了这个选项,你将会在你的函数应用中看到一个函数列表。

A single function app can contain many functions; however, each function is scaled independently.

将参数传递给函数

使用设计器的下一点并不是特别好的体验。本质上,我们必须将请求体格式化为 JSON 这意味着零件手动键入和零件选择内置功能。一旦你习惯了这一点,你可能会发现自己下降到原始的 JSON 添加这个;然而,让我们一步一步来。

请求主体的完成的 JSON 需要如下所示:

{ date1: '[Current Date]', date2: '[Date from Spreadsheet]' }

在请求正文中,输入 JSON 的第一部分,然后选择添加动态内容:

选择添加动态内容将弹出一个对话框。如您所见,我们的日期在这里,但现在,我们将切换到表达式选项卡:

在表达式选项卡中,您会发现许多内置函数,您会看到 utcNow():

UTC is a time zone that is unaffected by daylight savings or regional variations, which means that if you're dealing with date and times, you should be doing so in UTC (you may convert to the local time zone for display of input purposes).

一旦选择了函数,我们将需要完成 JSON 并从 Excel 传递日期(正如您之前看到的)。完成的 JSON 应该如下所示:

正如我们之前测试函数时看到的,这将返回一个 JSON 文档。如果我们希望稍后在工作流中使用这个函数的输出,我们需要解析JSON 输出。如果您在DatesCompare函数调用后直接插入一个动作,您将能够为此选择一个特殊的动作:

If you're wondering why you would ever not want to use the output of a function, it's worth remembering that functions can simply perform tasks; for example, you could have a function that updates a database or writes to a text file.

我们有一个名为Body的函数的输出。照目前的情况来看,这是标准的 JSON,所以您可以自己简单地剖析它;然而,我们将把它传递给我们的 Parse JSON 函数。

我们还需要指定模式,因为不太可能有人能够获得 JSON 模式。有一个漂亮的小函数,允许您只给它 JSON 输出(您可以直接从我们之前看到的测试屏幕中获得):

Try going back to the earlier part of the chapter and copying the output to paste into here.

生成的模式应该如下所示:

我们现在有一个日期比较,所以让我们回到我们的条件。

回到我们的状态

我们可以简单地插入值。记住Date1是我们当前的 UTC 日期,Date2是我们的 Excel 日期。所以逻辑应该测试当前日期是否等于或晚于 Excel 日期;在这一天,我们可以发布推文:

最后,让我们把我们的推文动作拖进真正的分支:

这基本上是完成的功能。我们现在应该已经成功发布了这条推文。

删除行

下一步是删除该行;我们将在推文下方添加以下内容:

再次搜索Excel,选择 Excel Online (OneDrive)。最后,我们将选择删除一行(预览):

在出现的对话框屏幕中,需要选择相同的电子表格和表格;然后,您将被要求选择一个键列和值:

这些列用于唯一标识要删除的行。在我们的例子中,我们只有两个选择:我们可以选择日期(这意味着我们只能安排在给定的日期发送一条推文),或者推文文本(这意味着我们不能多次发送同一条推文文本)。就我们而言,我们会选择日期。

If you were to extend this application, you may wish to define a third column with a unique identifier (you can even have Excel automatically generate this for you).

在键值框中,我们将选择较早的日期:

我们现在可以继续发布逻辑应用了。

发布逻辑应用

我们现在正处于最后阶段。剩下的就是将应用发布到 Azure。右键单击逻辑应用,选择部署,然后选择新建...:

As you can see from this screenshot, once you've deployed the project, a shortcut will be created to deploy to the correct resource group.

在出现的对话框中,要求您选择一个资源组:

最后,将要求您填写任何缺失的参数;在我们的例子中,这只是应用的名称:

发布后,您可以通过检查您的推特帐户和电子表格来检查工作流是否成功:

不过,你也可以看看日志。这些详细说明了工作流执行的时间,更重要的是,它们可能失败的地方。

失败

事实上,如果您完全复制了前面的步骤,您会发现,尽管做了它应该做的事情,应用还是报告失败了:

让我们看看是否能找到原因;点击其中一个失败,你会看到逻辑应用在抛出错误之前到底走了多远:

所以,我们可以看到我们已经走到ForEach了,有东西失败了,但是乍一看,好像成功了。选择下一个失败选项跳转到问题:

好吧,我们的功能有问题。逻辑应用非常擅长帮助诊断问题;继续点击要深入的步骤(点击日期准备):

那么,我们传递一个空字符串。原因当然是因为我们的 Excel 表包含空白条目。您可以通过简单地将表的大小缩小到可用的数据来解决这个问题,或者更改函数来过滤掉空行;不管怎样,我们现在都成功了:

我们现在有一个工作逻辑应用。让我们整理一下本章使用的资源。

清理 Azure 资源

在本章中,我们只使用了两个资源;让我们从清理逻辑应用开始:

  1. 在 Azure 门户中,选择逻辑应用刀片:

  1. 在此屏幕中,您现在应该能够看到您的应用:

  1. 接下来,我们可以以类似的方式找到我们的功能——选择功能刀片,或者从菜单选项中选择(如您所见,我的选项没有功能),或者只搜索Functions。同样的过程适用于:

If you don't tidy the function app, then it is unlikely you will be charged. Functions only execute when they are invoked; however, the logic app is designed to run at a set interval. If you chose not to tidy it, then you will probably incur charges.

既然我们已经处理了我们的资源,让我们回顾一下这一章。

摘要

我们现在已经创建了一个逻辑应用,从 Excel 电子表格中检索数据,分析数据,并根据结果与推特接口。虽然有很多步骤,但我希望你能看到,这比你必须自己编写所有这些接口要快得多。此外,您可以记录对您的逻辑应用的每个调用,因此您可以轻松诊断任何问题。

您可以很容易地添加一个错误处理功能,以便在失败时发送一封电子邮件;也许你想提出一个关于吉拉的问题;也许你有一个网站,你想每天对它进行一次测试,检查它是否还在运行,如果没有,就发邮件给你;也许你有一个服务总线队列,你想在每次收到死信时通知某人。所有这些都是可能的,不需要或只需要很少的代码。

在下一章中,我们将讨论如何使用身份服务器 4 在您的应用中实现授权。