基于 Azure Bot Service 的 Microsoft Teams Bot 开发上手指南

这篇文章本不必要,可惜无论是 Teams Developer platform 还是 Azure Bot Service 的官方文档都不够清晰易懂,容易走弯路。因此无奈在这里做简单小结,帮助读者更快上手。

Bot 的主要目的是接收并理解用户输入的文字信息或指令,并采取行动给予回应。在一些场景下,Bot 能够节省时间,提高效率,或提供更好的使用体验。在 Bot 不擅长的场景,开发并应用 Bot 则可能得不偿失。如非出于学习与研究目的,最好首先全面考察开发维护 Bot 的成本及相应的收益。

Azure Bot Service

Azure Bot Service 是 Microsoft Azure 提供的通用 Bot 服务。它不与特定消息平台频道(Channel)绑定,提供了包括语义理解、图像识别、知识库文档和通用搜索等功能。借助 Azure Bot Service 开发的 Bot 可以介入 Teams、Telegram、Line、WeChat、Facebook 等各种频道。

Microsoft Teams 是一款可扩展的通信平台,支持安装第三方应用。一款 Teams App 可以提供 tabs、bots、connector 和 messaging extension 这四大类功能。这里仅涉及 bot 部分。

两者的文档都提供了大量说明和范例,然而文章组织混乱,不少细节描述不够清晰,快速上手指南也在本地测试后戛然而止,而未作后续说明,对新手反而可能造成误导。这里简单整理。

用 Azure Bot Service 创建一个 Bot,往往意味着创建包含包括 App Service Plan、App Service、Bot Channels Registration/ App Bot 等在内的一系列资源。这些资源会被 Azure Bot Service 一同创建。如果选择 Bot 模板,则 App Service 创建之初就能提供模板描述的 Bot 功能,可以在 Bot Channels Registration/ App Bot 的 Test in Web Chat 菜单中实际体验。例如,选择 Echo Bot 模板,则数分钟后就能在 Test in Web Chat 中与该 Bot 对话并得到复述回答。

Azure Bot Framework ComposorAzure Bot Framework SDK 用于为 Azure Bot Service 开发复杂的 Bot 逻辑并发布。可惜的是 Azure Bot Framework Composor 无论是文档还是工具本身的易用性还都有待改善。创建完成的 Bot 将被发布至相应的 App Service 中。开发者也可以手动发布。如果是基于 NodeJs 的 Bot,直接通过 App Service 的 Editor 编辑 .js 文件,同样可以更改 Bot 的逻辑。基于 .NET 的 Bot 则需要在更改代码后进行编译。

Bot Channels Registration/ App Bot 之所以能够连接到 App Service 并与 Bot 交互,是因为它的配置菜单中提供了 App Service 的 messages API。要运行 Teams 连接至该 Bot,只要在其 Channels 菜单中添加 Teams 频道即可。

此外,除了上述由 Azure Bot Service 创建的 Bot Channels Registration/ App Bot,Azure Bot Framework 也提供了功能相似的替代品,能够创建 Bot 定义、连接频道,并访问由 messages API URL 指定的 Bot 服务。

以上是 Azure Bot Service 的部分。

Microsoft Teams Bot

另一方面,Teams App Bot 这边不提供实际的 Bot 逻辑。从 Teams 的角度来看,只有 App 这个概念,App 可以提供 Bot 功能。因此在 Teams 这边需要做的只有定义 App,更确切地说,准备一个包含了 manifest.json 、 color.png、outline.png 这三个文件的 Zip 文档。该文档可以被用于提交至 Teams 公开 App Store组织内部的 App Center,或者用户自己在自己的 Teams 客户端中上传安装(需要得到 IT 管理员许可才能使用该功能)。上述两个不同用途的图标文件按下不表,在 manifest 文档中会定义该 Teams App 的 Id、名称、描述、Bot 的 Id、范围和支持的命令等信息。

名为 App Studio 的 Teams App 和 Visual Studio Code 扩展 Microsoft Teams Toolkit能够帮助开发者快速创建和准备 Teams App 所需的信息(如 manifest 等)并打包或发布。

Teams Toolkit 能快速创建 Bot 的定义并生成基本的 Bot 模板。被创建的 Bot 模板可以在之后发布到服务器作为 Bot 的实际逻辑。同时,Teams Toolkit 还能直接访问 Azure Bot Framework,读取已创建的 Bot 定义,并更新 messages API 的 URL。

即使没有 App Studio,根据文档手动创建 App 的 manifest 也并不麻烦。但 App Studio 提供了更方便的管理功能,推荐使用。

即使没有 Teams Toolkit,也可以直接访问 Azure Bot Framework 站点并登录,在网站上创建 Bot 定义,并更新各类信息,或添加频道支持。Toolkit 自动生成的 Bot 逻辑也可以通过 Azure Bot Service 自动创建。

小结

综上,为了让 Teams 能够安装一个提供了 Bot 功能的 App,需要完成以下工作:

  • 准备 manifest.json 、 color.png、outline.png 并打包成 Zip 文档(可借助 App Studio )
  • 创建 Bot 定义(经有 Azure Bot Service 或者 Azure Bot Framework),并将 Bot Id 填入 App manifest (可借助 Teams Toolkit)。Bot 定义中的 messaging api 需要指向一个实际可用的服务,如本文介绍的 Azure Bot Service 提供 App Service 的 messages API 接口

需要注意,Teams Bot 和 Azure Bot Service 的 Bot 功能有若干差异,在阅读文档时需要注意辨别。Bot Serivce 中的功能有时不一定能在 Teams 中正常工作。

以上便是基于 Azure Bot Service 的 Microsoft Teams Bot 开发上手指南。想必还没有实际开始,就能感受到这套框架的设计有多么地复杂与含糊。愿本文可以帮助对 Bot 开发感兴趣地读者节省一些时间,更愉快地开发出自己的第一个 Bot。

Angular on Azure Web App Service (IIS)

部署于 Azure App Service 的 Web App 事实上运行于 IIS (Internet Information Services),因此也可以通过 web.config 文件来配置它的行为。

由于 Angular 是一种 SPA Web 框架,需要对 IIS 做一些额外的 URL Rewrite 配置,才能在浏览器刷新页面时依然成功载入内容,参见以下代码。

规则 Index Rule 的作用是把所有匹配的 HTTP 请求全都重定向至 “/” 路径,之后 Angular 自己的路由(Routes)将会继续工作,完成内容的载入和跳转。可以参考此处了解如何实现 lazy loading 。

staticContent 节点则定义了允许的 mimeType,否则直接访问 contentType 为 application/json 等类型的请求将返回 404 Not Found。

AngularGo —— 一个开源 Angular SPA 模板

在接触 Angular 后,这些年工作业余也用 Angular 做了若干实际项目。不过,由于 Angular 在国内的流行度不高,各种原创内容和参考资料也相对较少。虽然网络上也能找到各种各样的技术文章,官方的文档也很全面,但总的来讲,信息还是有些分散。

很惭愧,几年里没有做什么特别有技术含量的工作。 只是提炼出一个很基础的模板,帮助开发者快速创建一个 SPA(Single Page Application)站点,或是供对 Android 感兴趣的读者了解 Android 的语法和基本的框架机制。该模板先分享于此 —— AngularGo on GitHub

该模板基于目前最新的 Angular 8,且会持续跟进更新。在 Angular CLI 自动创建的范例项目的基础上,目前版本的 AngularGo 还包含以下内容:

  • Angular 8 以及相关依赖的最新版本配置
  • 一种可能的源文件结构示例
  • 一种与 Cordova 共享代码库的可能方式
  • 基础 Angular 组件及依赖注入的使用范例
  • 基础 Angular Material 控件的使用范例
  • 支持桌面和移动设备的抽屉式侧滑菜单
  • 支持 lazy loading 的 app-routing 全局路由
  • 支持 authentication guard 的模块路由
  • 支持 bearer token 验证的 Restangular 初始化及 service 用例
  • 基于 HttpClient 的用户注册与登录 API 调用
  • 基于 scss 的 Angular Material 样式(尚未采用 BEM 命名规则)
  • Azure Application Insights 集成
  • 适用于 Windows server/ Azure App Service 的 web.config 配置

AngularGo 还很初步,很多细节因水平有限和时间限制写得也比较粗糙,想必会有其他优秀的开源模板提供了更好的实现。从某种意义上来讲,该模板一方面是对自己经验得一个整理,同时期望能起到一个抛砖引玉的作用。希望对读者有帮助,也欢迎批评指教。

Angular、.NET Web Api 验证(Authentication)与跨来源资源共享(Cors)

验证是任何 Web 服务都必须考虑的基础问题。关于 .NET 平台的验证与授权,按理说微软已经提供了相当充分的文档与示例代码。

.NET Identity 框架提供了现成的数据库结构以及一系列接口,可以实现用户注册、登录登出、口令生成、邮箱的确认、密码重置等基本功能,也可以与社交媒体账户集成实现用户注册与登陆。

需要注意的是,.NET MVC 与 .NET Core 所使用的接口代码和 .NET Web Api 有所不同,如果混合阅读文档与代码,可能会造成混淆与理解上的困扰。不同版本的文档对邮箱验证等功能的处理逻辑也有差别,不可简单合并使用。

后端若部署至 Azure 等云平台,口令的生成也可能会遇到在本地不会发生的问题,报错“ The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread’s user context, which may be the case when the thread is impersonating.”。例如,.NET MVC 版示例代码在用户登录并验证邮箱后生成口令时会试图调用 /Token 接口,触发错误。网上针对此问题有一些解决方案,却都不太有效。事实上,可暂时忽略对邮箱是否得到验证的检查,直接前台调用 /Token 接口,就能避免该错误。对邮箱的确认可以在之后实际执行处理时按需进行。

微软官方的示例代码都没有涉及 Cors(cross origin resource sharing) 问题,即使是 Angular 项目模板,由于前端默认与后端共存于同一个解决方案,也不存在这一问题。然而,如果前后端分离,前端 Angular 程序的域名很可能与后端不同。

微软针对 .NET Web Api 的 Cors 有一些文档,但很遗憾,如果有接口通过 bearer token 进行验证与授权,那些文档中的解决方案很可能会引发新的问题。

  • .NET Web Api 中对 允许跨源访问:介绍多种允许 Cross origin request 的方式

由于 Chrome 等一些浏览器在一定条件下出于安全原因为首先发送 OPTIONS method 的 HTTP 请求(如 headers 中指定 “Content-Type”: “application/x-www-form-urlencoded” 时),情况变得更加复杂。

如果 OPTIONS method 没有被允许,则会遇到 405 错误代码。不当的设置可能会在允许跨源访问资源时却阻碍了用户登录等验证 API。又或是无意中重复允许 Cors origin 设置,会提示 The ‘Access-Control-Allow-Origin’ header contains multiple values 错误而无法获得资源。

网络上简单明了且实际有效的解决方案并不好找,经过反复尝试与分析,要避免所有这类问题,采用全局设置恐怕是最简单的方法之一。

  • 不要像下面这样通过 Web.config 来设置 Cors

  • 不要像下面这样通过 ApiController 属性来设置 Cors

  • 不要在 WebApiConfig 等类中通过诸如 config.EnableCors(); 等代码方式设置 Cors
  • 安装 Microsoft.Owin.Cors 的 NuGet 包
  • 在 startup.cs 的 ConfigureAuth 方法开始时调用语句 app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
  • Angular 前端发送请求时, headers 中只需指定 “Content-Type”: “application/x-www-form-urlencoded” 一项即可
  • 如果使用 RestAngular 获取资源,只需按如下方式设置 Content-Type 与 Authorization 即可

至此,运行于 Azure App Service 的后端 .NET Web Api 将可以与非同源的 Angular 程序交互,实现本地用户账号的注册登陆等操作,可以通过 bearer token 实现资源请求过程中的验证与授权。

写给程序员的 AngularJS 语法快速入门

基本示例

index.html

使用控件

index.html

todo.js

todo.css

 

未完待续

Web 开发笔记

作为分类目录的一个补充,在这里按照功能类别对 Web 开发中的一点心得和笔记作一个索引。其中部分是根据自己在查找网络资料时找到的内容的整理与演绎,在此感谢所有那些无私分享经验的人们。

HTML & CSS
Angular
Web App
JavaScript & jQuery & JSON & AngularJS
Python
PHP
正则表达式