点击上方蓝字关注“汪宇杰博客”
导语
Azure Function 是一个事件驱动型无服务器计算平台,可以解决复杂的业务流程问题,更加高效地进行开发。在本地构建和调试,而无需额外的设置,在云中大规模部署和操作,并使用触发器和绑定集成服务。对我来说,Function 能帮助我快速开发一些简单的API,我只需要编写业务代码,而无需构建完整的应用框架等基础代码。本文将会讲解如何使用.NET Core,C#语言,开发一个简单的 http 触发的 Function 应用,并完成 GitHub 的持续部署配置。
需求
我需要一个 API,用于返回客户端 IP 以及 User-Agent 字符串。但是我不想为了做这么一件简单的事,而创建一个完整的 ASP.NET Core Web API 项目。我只关心我要进行的业务逻辑,不想编写和管理配置文件、依赖注入、Controller、验证等基础代码。
准备开发环境
我们需要以下开发条件:
- 卖血买到的 Azure 订阅
- 丐版 Visual Studio 2019 Community 或豪版 Enterprise
- Azure development workload
- 免费开源的 .NET Core 2.1 / 2.2 SDK
创建 Function 应用
在 VS2019 里,选择 Azure 分类下的 Azure Function,新建一个工程。如:Edi.AzureFunctions
默认的.NET Core版本为2.1,我们可以手工改成2.2。编辑 Edi.AzureFunctions.csproj文件,将 TargetFramework 改成 netcoreapp2.2
同样,也可以将 Microsoft.NET.Sdk.Functions 升级到最新版。
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AzureFunctionsVersion>v2</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="1.0.29" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>
将默认类改名为 ClientInfoFuncion,完成我们的业务代码:取客户端IP及User-Agent
public static class ClientInfoFuncion
{
[FunctionName("IP")]
public static IActionResult GetClientIp(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("Requesting client IP.");
var ip = req.HttpContext.Connection.RemoteIpAddress.ToString();
return ip != null
? (ActionResult)new OkObjectResult($"{ip}")
: new BadRequestObjectResult("ip is null");
}
[FunctionName("UserAgent")]
public static IActionResult GetClientUserAgent(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("Requesting client User-Agent.");
var ua = req.Headers["User-Agent"].ToString();
return ua != null
? (ActionResult)new OkObjectResult($"{ua}")
: new BadRequestObjectResult("user-agent is null");
}
}
可以发现,Azure Function 的代码非常类似 ASP.NET Core MVC / Web API,返回类型正是 Microsoft.AspNetCore.Mvc.IActionResult,然而我们无需关心如何构建一个完整的ASP.NET Core Web API工程,也无需知道 Controller 的存在,只要编写业务逻辑即可。
FunctionName 可以理解为 ASP.NET Core 中的 Route,也就是最终用户调用 API 的 endpoint 地址。
[FunctionName("IP")] 也就最终对应:
https://你的function地址/api/IP
HttpTrigger 是 Azure Function 的一种触发器,表示通过HTTP请求,触发你写的业务逻辑。此处我允许匿名访问,并限定为 get / post 两种HTTP Verb。
ILogger 接口中的日志最终会输出到 Azure Function 的后台,用于调试。
按 F5 启动本地调试。会看见一个很炫酷的命令行窗口,里面启动的是本地的 Azure Function 模拟器。
模拟器准备完成后,控制台会输出两个绿色的URL地址,用于本地测试。
复制URL到浏览器,完成测试。
从 VS 创建和部署 Azure Function
在 Edi.AzureFunctions 点击右键,选择 Publish
点击 Start,选择 Azure Functions Consumption Plan,然后选择 Create New。如果你已经在 Azure 上创建过一个 Function 应用,则可选择 Select Existing。关于如何从 Azure portal 创建一个 Function 应用,在稍后讨论。
根据需要填写参数
最后点击 Publish 完成发布
如果发布成功,你可以在 Azure portal 里找到这个 Function 应用,并能看见其 URL
尝试在浏览器中访问两个API,分别是:
https://你的function名称.azurewebsites.net/api/ip
https://你的function名称.azurewebsites.net/api/useragent
你也可以在 Functions 下进入具体的 HttpTrigger,并在 Azure Portal 里完成测试。这会输出更详细的日志信息。
在 Azure Portal 创建 Function
刚才的例子里,我们通过 VS2019 一条龙开发和部署了一个Azure Function,而在实际应用中,通常不会这样操作。因为 Azure Portal 给我们提供了更细致的参数选项,以便根据自己的需求调整。要从 Azure Portal 创建一个空的Function 应用也十分简单,点击 Function App / Add
输入 App name,它将作为该function默认域名使用。
其他参数根据自己需要设置。我建议大家重用既有的 App Service Plan,这样可以省钱。
Runtime Stack 选择 .NET Core
从 GitHub 仓库持续部署
我在之前的博客文章中介绍过了 Azure DevOps 的CI/CD流程,非常强大。但是本文给大家介绍一个更简单,但是略为基础的发布方式。
实际上 Function 的本质是对 App Service 的进一步包装,所以包括部署在内的大部分 App Service 的功能这里也能用。在 Platform features 里进入 Deployment Center
代码来源选择 GitHub
选择 Kudu 编译
我已将本文的代码上传到 https://github.com/EdiWang/Edi.AzureFunctions
在 Azure 里选择对应的仓库以及分支,并完成配置。
完成配置后,会立即触发一次部署,可以看到详细日志。
部署成功后,刷新左边的 Functions 就能看见我们的两个 API 了
如果你是个土豪,有自己的域名和证书,也可以绑定自定义域名。就像我这样:
最后,就能优雅的通过自己的域名访问 Function 了!