使用 Microsoft Graph 动态创建Microsoft Teams 会议

在本练习中,你将使用 Azure Functions 和 Microsoft Graph 自动创建 Microsoft Teams 会议链接并传递给 ACS 的过程。

创建 Teams 会议

  1. 需要为守护程序应用身份验证创建Microsoft Entra ID 应用。 在此步骤中,将使用 应用凭据在后台处理身份验证,Microsoft Entra ID 应用将使用应用程序权限进行Microsoft图形 API 调用。 Microsoft Graph 将用于动态创建 Microsoft Teams 会议并返回 Teams 会议 URL。

  2. 执行以下步骤创建Microsoft Entra ID 应用:

    1. 转到 Azure 门户 并选择 Microsoft Entra ID
    2. 选择 “应用注册 ”选项卡,后跟 “+ 新建注册”。
    3. 填写新的应用注册表单详细信息,如下所示,然后选择 “注册” :
      • 名称:ACS Teams 互操作应用
      • 支持的帐户类型: 任何组织目录中的帐户(任何Microsoft Entra ID 目录 - 多租户)和个人Microsoft帐户(例如 Skype、Xbox)
      • 重定向 URI:将此保留为空
    4. 注册应用后,转到 API 权限 并选择“ + 添加权限”。
    5. 选择 Microsoft Graph,然后选择 应用程序权限
    6. 选择权限 Calendars.ReadWrite ,然后选择“ 添加”。
    7. 添加权限后,为YOUR_ORGANIZATION_NAME<选择“授予管理员许可>”。
    8. 转到“ 证书和机密 ”选项卡,选择“ + 新建客户端密码”,然后选择“ 添加”。
    9. 将机密的值复制到本地文件中。 你将在本练习后续部分使用此值。
    10. 转到“ 概述 ”选项卡,将 Application (client) IDDirectory (tenant) ID 值复制到上一步中使用的同一本地文件中。

创建 local.settings.json 文件

  1. 在 Visual Studio 中打开samples/acs-to-teams-meeting/server/csharp/GraphACSFunctions.sln或在 Visual Studio Code 中打开GraphACSFunctions文件夹。

  2. 转到 GraphACSFunctions 项目并创建具有以下 local.settings.json 值的文件:

    {
        "IsEncrypted": false,
        "Values": {
            "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
            "TENANT_ID": "",
            "CLIENT_ID": "",
            "CLIENT_SECRET": "",
            "USER_ID": "",
            "ACS_CONNECTION_STRING": ""
        },
        "Host": {
            "LocalHttpPort": 7071,
            "CORS": "*",
            "CORSCredentials": false
        },
        "watchDirectories": [
            "Shared"
        ]
    }
    
    • 使用在前面的练习中复制到本地文件中的值,来更新TENANT_IDCLIENT_IDCLIENT_SECRET 的值。
    • 使用要创建 Microsoft Teams 会议的用户 ID 进行定义 USER_ID

    可以从 Azure 门户获取用户 ID。

    • 使用 Microsoft 365 开发人员租户管理员帐户登录。
    • 选择 Microsoft Entra ID
    • 导航到侧栏上的“ 用户 ”选项卡。
    • 搜索用户名并选择它以查看用户详细信息。
    • 在用户详细信息中,Object ID表示User ID。 将 Object ID 的值复制并用于 USER_ID 中的 值。

    从 Microsoft Entra ID 获取用户 ID

    注释

    ACS_CONNECTION_STRING 将在下一个练习中使用,因此你尚不需要更新它。

  3. 打开 GraphACSFunctions.sln 位于 acs-to-teams-meeting/server/csharp 文件夹中,并请注意,它包含以下 Microsoft Graph 和身份验证包:

    <PackageReference Include="Azure.Communication.Identity" Version="1.3.1" />
    <PackageReference Include="Azure.Identity" Version="1.11.2" />
    <PackageReference Include="Microsoft.Graph" Version="5.51.0" />
    
  4. 转到 Program.cs ,并在方法中 ConfigureServices 记下以下代码:

        var host = new HostBuilder()
            .ConfigureFunctionsWebApplication()
            .ConfigureServices(services => {
                services.AddApplicationInsightsTelemetryWorkerService();
                services.ConfigureFunctionsApplicationInsights();
                services.AddSingleton(static p =>
                {
                    var config = p.GetRequiredService<IConfiguration>();
                    var clientSecretCredential = new ClientSecretCredential(
                        config.GetValue<string>("TENANT_ID"),
                        config.GetValue<string>("CLIENT_ID"),
                        config.GetValue<string>("CLIENT_SECRET")
                    );
    
                    return new GraphServiceClient(
                        clientSecretCredential,
                        ["https://graph.microsoft.com/.default"]
                    );
                });
    
                ...
    
                services.AddSingleton<IGraphService, GraphService>();
            })
            .Build();
    }
    
    • 此代码创建一个GraphServiceClient对象,可用于从 Azure Functions 调用 Microsoft Graph。 它是一个单一实例,可以注入到其他类中。
    • 可以通过将一个值作为参数传递给构造函数,并使用ClientSecretCredential(例如GraphServiceClient)来调用Microsoft Graph API。 ClientSecretCredential 使用 Microsoft Entra ID 应用中的 Tenant IdClient IdClient Secret 值。
  5. 打开 服务/GraphService.cs

  6. 花点时间探索 CreateMeetingEventAsync 方法:

    using System;
    using System.Threading.Tasks;
    using Microsoft.Graph;
    using Microsoft.Extensions.Configuration;
    
    namespace GraphACSFunctions.Services;
    
    public class GraphService : IGraphService
    {
        private readonly GraphServiceClient _graphServiceClient;
        private readonly IConfiguration _configuration;
    
        public GraphService(GraphServiceClient graphServiceClient, IConfiguration configuration)
        {
            _graphServiceClient = graphServiceClient;
            _configuration = configuration;
        }
    
        public async Task<string> CreateMeetingAsync()
        {
            var userId = _configuration.GetValue<string>("USER_ID");
            var newMeeting = await _graphServiceClient
                .Users[userId]
                .Calendar
                .Events
                .PostAsync(new()
                {
                    Subject = "Customer Service Meeting",
                    Start = new()
                    {
                        DateTime = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ss"),
                        TimeZone = "UTC"
                    },
                    End = new()
                    {
                        DateTime = DateTime.UtcNow.AddHours(1).ToString("yyyy-MM-ddTHH:mm:ss"),
                        TimeZone = "UTC"
                    },
                    IsOnlineMeeting = true
                });
            return newMeeting.OnlineMeeting.JoinUrl;
        }
    }
    
    • GraphServiceClientIConfiguration 对象将注入构造函数并分配给字段。
    • CreateMeetingAsync() 函数将数据发布到 Microsoft Graph 日历事件 API,该 API 在用户的日历中动态创建事件并返回联接 URL。
  7. 打开 TeamsMeetingFunctions.cs 并花点时间检查它的构造函数。 GraphServiceClient 您之前查看的内容被注入并分配给_graphService字段。

    private readonly IGraphService _graphService;
    
    public TeamsMeetingFunction(IGraphService graphService) => _graphService = graphService;
    
  8. 定位Run方法:

    [Function("HttpTriggerTeamsUrl")]
    public async Task<HttpResponseData> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequestData req,
        ILogger log)
    {
        var response = req.CreateResponse(HttpStatusCode.OK);
        await response.WriteStringAsync(await _graphService.CreateMeetingAsync());
        return response;
    }
    
    • 它定义可以使用 HTTP GET 请求调用的 HttpTriggerTeamsUrl 函数名称。
    • 它调用 _graphService.CreateMeetingAsync(),这将创建新事件并返回联接 URL。
  9. 在 Visual Studio 中按 F5 或选择 “调试”来运行程序 -> 从菜单中选择“开始调试 ”。 此作将启动 Azure Functions 项目并使其 ACSTokenFunction 可供调用。

注释

如果使用 VS Code,可以在 GraphACSFunctions 文件夹中打开终端窗口并运行 func start。 这假定已在计算机上安装 了 Azure Functions Core Tools

从 React 调用 Azure 函数

  1. 现在,函数 httpTriggerTeamsUrl 已准备好使用,接下来让我们从 React 应用调用它。

  2. 展开 客户端/react 文件夹。

  3. 使用以下值将 .env 文件添加到文件夹中:

    REACT_APP_TEAMS_MEETING_FUNCTION=http://localhost:7071/api/httpTriggerTeamsUrl
    REACT_APP_ACS_USER_FUNCTION=http://localhost:7071/api/httpTriggerAcsToken
    

    这些值将在生成时传递到 React 中,以便在生成过程中根据需要轻松更改它们。

  4. 在 VS Code 中打开 client/react/App.tsx 文件。

  5. teamsMeetingLink 组件中找到状态变量。 删除硬编码的团队链接,并将其替换为空引号:

    const [teamsMeetingLink, setTeamsMeetingLink] = useState<string>('');
    
  6. 找到函数 useEffect 并将其更改为如下所示。 这将处理调用你之前查看的 Azure 函数,该函数用于创建 Teams 会议并返回会议的加入链接。

    useEffect(() => {
        const init = async () => {
            /* Commenting out for now
            setMessage('Getting ACS user');
            //Call Azure Function to get the ACS user identity and token
            const res = await fetch(process.env.REACT_APP_ACS_USER_FUNCTION as string);
            const user = await res.json();
            setUserId(user.userId);
            setToken(user.token);
            */
    
            setMessage('Getting Teams meeting link...');
            //Call Azure Function to get the meeting link
            const resTeams = await fetch(process.env.REACT_APP_TEAMS_MEETING_FUNCTION as string);
            const link = await resTeams.text();
            setTeamsMeetingLink(link);
            setMessage('');
            console.log('Teams meeting link', link);
    
        }
        init();
    
    }, []);
    
  7. 保存文件,然后再继续。

  8. 打开终端窗口, cd 进入 *react 文件夹,然后运行 npm start 以生成和运行应用程序。

  9. 应用程序生成并加载后,应会看到显示 ACS 调用 UI,然后可以调用由 Microsoft Graph 动态创建的 Teams 会议。

  10. 通过在终端窗口中输入 Ctrl + C 来停止终端进程。

  11. 停止 Azure Functions 项目。

下一步

注释

请访问 Azure 通信服务文档,详细了解如何以其他方式 扩展 Microsoft Teams 会议