练习 - 在本地使用 Visual Studio 创建和测试简单的 Azure Functions

已完成

Visual Studio 为创建和测试 Azure 函数应用提供了一个绝佳环境。 在将 Azure Functions 部署到云之前,可在本地开发 Azure Functions 并验证其是否正常运行。

在奢侈手表在线网站场景中,函数的要求为:当给定手表的型号时,该函数返回有关手表的详细信息。 需要返回的数据包括制造商、表壳背面类型(实心、透明或雕刻)、外圈、表盘样式、表壳表面处理、珠宝数量等信息。

在本练习中,你将使用 Visual Studio 对此函数的一个版本进行本地实现和测试。

注意

开始本练习之前,请确保已安装了 VS 2022,以及 Web 和云工作负载扩展“ASP.NET 与 Web 开发”和“Azure 开发”

创建 Azure 函数应用

使用 Azure Functions 模板创建 Azure 函数应用。

  1. 启动“Visual Studio 安装程序”并在“Visual Studio 2022”开始页上,选择“修改” 。

  2. 请确保选择“ASP.NET 和 Web 开发”以及“Azure 开发”且均可用,(如果不选择“下载时安装”),然后选择“关闭”。

    突出显示了 asp dot net 和 Azure 开发工作负载的 Visual Studio 2022 的屏幕截图。

  3. 在“Visual Studio 2022”开始页上,选择“启动”。

  4. 在“开始”菜单上,选择“新建项目”。 随即显示“创建新项目”页。

  5. 搜索或滚动到“Azure Functions”模板,然后选择“下一步”。

    Visual Studio 2022 的屏幕截图:“新建项目”页面,其中突出显示了 Azure Functions 模板。

  6. 随即显示“配置新项目”页。 输入以下值。

    字段
    项目名称 WatchPortalFunction
    位置 通过浏览到文件夹或在本地计算机上创建文件夹,选择要存储项目的位置。
    解决方案名称 接受“WatchPortalFunction”(默认)。
    将解决方案和项目放在同一目录中 未选中(未选择)。 此设置将确保此模块的文件夹结构正确。

    “配置新项目”页面的屏幕截图,其中突出显示了“新建”。

  7. 选择“下一页”。

  8. 将显示“其他信息”页。

  9. 选择以下值。

    字段
    Dotnet 版本 *.NET 6.0(长期支持)
    函数触发器 Http 触发器
    将 Azurite 用于运行时存储账户 (AzureWebJobsStorage) 已选中
    启用 Docker 未选中
    授权级别 匿名

    如果 Visual Studio 通知显示更新已准备就绪,选择“刷新”。

  10. 选择“创建” 。

    显示 Azure Functions 触发器的屏幕截图,其中突出显示了 HTTP 触发器。

    Visual Studio 创建 WatchPortalFunction 项目,并显示代码编辑器窗口中的 Functions 应用源代码文件 Function1.cs。 该文件包含名为 Function1 的类的代码。

    如下面的示例代码所示,Function1 类包含 HTTP 触发器模板中的样板代码。 Run 方法使用 [FunctionName ("Function1")] 属性进行批注。 在上一单元中,我们了解到 Run 方法的样板参数是一个 HttpRequest 对象,其中包含触发函数的请求的详细信息,以及用于记录跟踪信息的跟踪日志条目。

    namespace WatchPortalFunction
    {
        public static class Function1
        {
            [FunctionName("Function1")]
            public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "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");
            }
        }
    }
    

创建 WatchInfo Azure Functions

  1. 在“视图”菜单中,选择“解决方案资源管理器”。 在“解决方案资源管理器”窗口中,右键单击“WatchPortalFunction”Azure Functions 项目,接着在上下文菜单中选择“添加”>“新建 Azure 函数”。

    “解决方案资源管理器”窗口的屏幕截图。用户选择了“添加”->“新建 Azure 函数”。

  2. 在“添加新项 - WatchPortalFunction”窗口中,选择“Azure Functions”。 在“名称”字段中,输入“WatchInfo.cs”,然后选择“添加”。

    “添加新项”窗口的屏幕截图。选择 Azure Function 模板,并将新函数命名为WatchInfo.cs。

  3. 在“新建 Azure 函数 - WatchInfo”窗口中,选择“Http 触发器”。 在“授权级别”下拉列表中,选择“匿名”,然后选择“添加”。

    “新建 Azure 函数”窗口的屏幕截图。已选择具有匿名访问权限的 Http 触发器。

    Visual Studio 会创建一个新函数,并使用 [FunctionName("WatchInfo")] 属性对 Run 方法进行批注。

  4. Run 函数的正文中,删除 log.LogInformation 行后的代码。 结果应如下所示。

    namespace WatchPortalFunction
    {
        public static class WatchInfo
        {
            [FunctionName("WatchInfo")]
            public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
                ILogger log)
            {
                log.LogInformation("C# HTTP trigger function processed a request.");
            }
        }
    }
    
  5. 将以下代码插入 log.LogInformation 行后的 Run 方法的正文中。

    // Retrieve the model id from the query string
    string model = req.Query["model"];
    
    // If the user specified a model id, find the details of the model of watch
    if (model != null)
    {
        // Use dummy data for this example
        dynamic watchinfo = new { Manufacturer = "abc", CaseType = "Solid", Bezel = "Titanium", Dial = "Roman", CaseFinish = "Silver", Jewels = 15 };
    
        return (ActionResult)new OkObjectResult($"Watch Details: {watchinfo.Manufacturer}, {watchinfo.CaseType}, {watchinfo.Bezel}, {watchinfo.Dial}, {watchinfo.CaseFinish}, {watchinfo.Jewels}");
    }
    return new BadRequestObjectResult("Please provide a watch model in the query string");
    

    此代码从 HTTP 请求中的查询字符串中读取 model 参数,并返回该监视模型的详细信息。 在此示例代码中,我们创建了无论 model 值如何都会返回的虚拟 watchinfo 数据。 此函数返回包含这些详细信息的响应。 或者,如果 HTTP 请求不包含查询字符串,该函数将返回错误消息。 在实际示例中,将使用 model 该值来查找要返回的正确的 watchinfo

在本地测试 Azure Functions

  1. 在命令栏上,选择“调试”>“开始调试”。

    Visual Studio 生成 Azure 函数应用并启动 Azure Functions 运行时。 运行时启动时,将打开“输出”窗口以显示消息。 运行时准备就绪后,将显示一个 HTTP 函数列表以及可用于触发每个函数的 URL。

    Azure Functions 运行时窗口的屏幕截图。运行时启动 Azure Function 应用,并显示 Function1 和 WatchInfo Azure Functions 的 URL。

  2. 打开 Web 浏览器,并输入运行时窗口中显示的 URL 默认 URL 是 http://localhost:7071/api/WatchInfo?model=abc,因此,这就是我们在本练习中所使用的 URL。 此请求触发 WatchInfo 函数,并将模型 abc 作为查询字符串参数传递。 Web 浏览器应显示函数生成的虚拟详细信息。

    触发 WatchInfo Azure Functions 的 Web 浏览器的屏幕截图。该函数返回所提供的 URL 查询字符串中指定模型的虚拟详细信息。

  3. 输入 URL http://localhost:7071/api/WatchInfo。 此请求不包含查询字符串。 触发器返回错误响应,Web 浏览器显示 Please provide a watch model in the query string 消息。

  4. 关闭 Web 浏览器,但保持 Azure 函数应用正常运行。

  5. 在 Visual Studio 中,在从查询字符串检索模型的代码行上设置断点。

    显示从查询字符串中读取模型的语句上的断点的 Visual Studio 屏幕截图。

  6. 重启 Web 浏览器,然后输入不带查询字符串的 URL http://localhost:7071/api/WatchInfo

    Visual Studio 在暂停执行的断点处突出显示代码。

  7. 在 Visual Studio 中,按 F10 跳过断点处的语句。

  8. 在“调试器”窗口的“自动”选项卡中,验证 model 变量是否为 null。 该变量显示此值,因为查询字符串不包含模型参数。

    显示模型变量值的 Visual Studio 调试器屏幕截图。

  9. 再次按 F10,并验证控件是否跳转到返回 BadRequestObjectResult 对象的语句。

  10. F5 继续运行该方法并返回到 Web 浏览器。 应显示相同的错误消息。

  11. 在 Web 浏览器中,输入带有查询字符串和模型参数的 URL。 在调试器中单步调试函数,并验证是否正确检索了模型。 应使用参数的值填充 model 变量,并将模型的详细信息作为 OkObjectResult 对象返回。

  12. 在菜单栏上,选择“调试”>“停止调试”。

在本练习中,你已了解如何在 Visual Studio 中使用 Azure Functions 工具扩展简化 Azure Function 应用的创建体验,后者可让你使用熟悉的工具来生成和调试代码。