You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用MS Graph API在C#中添加共享日历事件的异步任务问题及Azure配置咨询

使用MS Graph API在C#中添加共享日历事件的异步任务问题及Azure配置咨询

我来帮你梳理下当前遇到的问题和解决方案:

一、异步调用导致的状态异常与卡住问题

你现在遇到的两个现象本质上是同一个问题:异步方法在同步上下文里没有被正确处理,加上认证流不适合Web Forms环境。

  1. 直接调用Add()返回WaitingForActivation状态:
    你的btnAdd_Click是同步方法,调用异步的Add()时没有用await,相当于只是启动了一个异步任务但没有等待它完成,所以返回的Task一直处于等待激活的状态,自然拿不到结果。

  2. 改成async await后卡住:
    你用的DeviceCodeCredential是设备代码流,这个认证方式是给桌面/移动端这类交互式应用设计的——它需要在控制台输出验证链接和代码,让用户手动登录验证。但在ASP.NET Web Forms的服务器端环境里,没有控制台可以输出这些信息,用户根本没法完成验证步骤,所以任务会一直卡住等待用户交互。

二、代码层面的修复方案

1. 修正异步事件处理程序

首先把按钮点击事件改成异步的(Web Forms里事件处理程序可以用async void),同时要给页面加上Async="true"属性:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="YourPage.aspx.cs" Inherits="YourNamespace.YourPage" Async="true" %>

然后修改后台代码:

protected async void btnAdd_Click(object sender, EventArgs e)
{
    try
    {
        var t = await Add();
        Response.Write($"Event added successfully, ID: {t.Id}");
    }
    catch (Exception ex)
    {
        clsCommon.LogError(ex);
    }
}

2. 替换适合Web应用的认证方式

放弃DeviceCodeCredential,根据你的场景选择下面两种认证流:

场景A:后台服务,不需要用户登录(适合批量操作)

用客户端凭据流(Client Credentials),这种方式是应用自身完成认证,不需要用户交互:

private async Task<Event> Add()
{
    var scopes = new[] { "https://graph.microsoft.com/.default" };
    var tenantId = "your-tenant-id";
    var clientId = "your-client-id";
    var clientSecret = "your-client-secret"; // 在Azure Portal生成的客户端密钥

    var options = new ClientSecretCredentialOptions
    {
        AuthorityHost = AzureAuthorityHosts.AzurePublicCloud,
    };

    var clientSecretCredential = new ClientSecretCredential(
        tenantId, clientId, clientSecret, options);

    var graphClient = new GraphServiceClient(clientSecretCredential, scopes);
    
    // 剩下的事件创建代码和你原来的一致
    var myEvent = new Event();
    myEvent.Subject = "Test";
    myEvent.Body = new ItemBody() { ContentType = BodyType.Text, Content = "This is test." };
    myEvent.Start = new DateTimeTimeZone() { DateTime = "2026-3-29T12:00:00", TimeZone = "Pacific Standard Time" };
    myEvent.End = new DateTimeTimeZone() { DateTime = "2026-3-29T13:00:00", TimeZone = "Pacific Standard Time" };
    myEvent.Location = new Location() { DisplayName = "TESTLoc" };                 

    var mySyncdEvent = await graphClient.Users["dummy@email.com"].Calendar.Events.Request().AddAsync(myEvent);
    return mySyncdEvent;
}
场景B:需要用户登录操作自己/共享的日历

用授权码流(Authorization Code),需要先引导用户登录获取授权码,再用授权码获取令牌。Web Forms里可以用Microsoft Identity库来简化这个流程。

三、Azure Portal的配置要求

不管用哪种认证流,都需要在Azure AD应用注册里做以下配置:

  • 添加API权限:
    • 如果用客户端凭据流:添加Microsoft Graph的应用权限Calendars.ReadWrite.All,然后需要租户管理员同意这个权限。
    • 如果用授权码流:添加Microsoft Graph的委托权限Calendars.ReadWrite,用户登录时会自动同意(如果是管理员同意过的话)。
  • 客户端凭据流额外配置:生成客户端密钥(在应用注册的“证书和密码”里创建),并确保应用有访问目标用户日历的权限(如果是共享日历,目标用户需要把日历共享给应用的服务主体,或者应用有全局的日历读写权限)。
  • 授权码流额外配置:在应用注册的“身份验证”里添加Web平台的重定向URI,指向你的Web Forms页面。

四、补充说明

如果是访问用户共享的日历,除了权限配置外,还要确保目标用户已经将日历共享给了当前认证的主体:

  • 用授权码流的话,共享给登录的用户;
  • 用客户端凭据流的话,共享给应用的服务主体(可以在Outlook里搜索应用名称来添加共享权限)。

备注:内容来源于stack exchange,提问作者user31876733

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.13 18:38:13