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

使用Microsoft Graph C#创建O365日历事件无报错但失败求助

问题排查:Microsoft Graph创建日历事件无报错但未生成

问题描述

使用管理员账号通过GraphServiceClient为O365用户日历创建会议事件,代码执行无报错,但操作账号及参会者账号中均未生成该事件,已确认Azure门户中用户拥有Calendars.ReadWrite权限。

代码示例

try
{
    var scopes = new[] { "Calendars.ReadWrite.All" };

    // Multi-tenant apps can use "common",
    // single-tenant apps must use the tenant ID from the Azure portal
    var tenantId = "common";

    Configuracoes Dados = new Configuracoes();

    // Values from app registration
    string clientId = Dados.EMailCV.ToString();
    string clientSecret = Dados.PasswordCV.ToString();

    // using Azure.Identity;
    var options = new TokenCredentialOptions
    {
        AuthorityHost = AzureAuthorityHosts.AzurePublicCloud
    };

    // This is the incoming token to exchange using on-behalf-of flow
    var oboToken = "JWT_TOKEN_TO_EXCHANGE";

    var cca = ConfidentialClientApplicationBuilder
        .Create(clientId)
        .WithTenantId(tenantId)
        .WithClientSecret(clientSecret)
        .Build();

    // DelegateAuthenticationProvider is a simple auth provider implementation
    // that allows you to define an async function to retrieve a token
    // Alternatively, you can create a class that implements IAuthenticationProvider
    // for more complex scenarios
    var authProvider = new DelegateAuthenticationProvider(async (request) =>
    {
        // Use Microsoft.Identity.Client to retrieve token
        var assertion = new UserAssertion(oboToken);
        var result = await cca.AcquireTokenOnBehalfOf(scopes, assertion).ExecuteAsync();

        request.Headers.Authorization =
            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
    });

    GraphServiceClient graphClient = new GraphServiceClient(authProvider);

    var @event = new Event
    {
        Subject = "Let's go for lunch",
        Body = new ItemBody
        {
            ContentType = BodyType.Html,
            Content = "Does noon work for you?"
        },
        Start = new DateTimeTimeZone
        {
            DateTime = "2022-11-04T12:00:00",
            TimeZone = "GMT Standard Time"
        },
        End = new DateTimeTimeZone
        {
            DateTime = "2017-04-15T14:00:00",
            TimeZone = "GMT Standard Time"
        },
        // Location = new Location
        // {
        //     displayName = "Harry's Bar"
        // },
        Attendees = new List<Attendee>()
        {
            new Attendee
            {
                EmailAddress = new EmailAddress
                {
                    Address = "p560@esenviseu.net",
                    Name = "Nuno Barros"
                },
                Type = AttendeeType.Required
            }
        },
        AllowNewTimeProposals = true,
        IsOnlineMeeting = true,
        OnlineMeetingProvider = OnlineMeetingProviderType.TeamsForBusiness
    };

    graphClient.Me.Events
        .Request()
        .Header("Prefer", "outlook.timezone=\"GMT Standard Time\"")
        .AddAsync(@event);

}
catch (Exception ex)
{
    lblTexto.Text = "Erros!<br>" + ex.Message;
}
finally
{
    lblTexto.Text = "Sem erros!";
}

核心排查点

1. 异步方法未等待

AddAsync是异步方法,代码中未添加await关键字,导致方法还未执行完成就进入finally块,操作可能被中断。修改方式:

await graphClient.Me.Events
    .Request()
    .Header("Prefer", "outlook.timezone=\"GMT Standard Time\"")
    .AddAsync(@event);

同时确保包含这段代码的方法标记为async。

2. 事件时间逻辑错误

代码中事件的结束时间(2017-04-15)早于开始时间(2022-11-04),这会导致Microsoft Graph API拒绝创建事件。需要修正结束时间为晚于开始时间的合理值。

3. 异常信息被覆盖

finally块直接覆盖了lblTexto.Text的内容,即使catch捕获到异常,用户也看不到错误信息。调整逻辑:

catch (Exception ex)
{
    lblTexto.Text = "Erros!<br>" + ex.Message;
}
finally
{
    // 仅在未捕获异常时显示成功信息
    if (string.IsNullOrEmpty(lblTexto.Text))
    {
        lblTexto.Text = "Sem erros!";
    }
}

4. OBO令牌有效性

oboToken是硬编码的占位符,实际运行时需传入当前用户的有效JWT令牌,且该令牌需包含足够的委托权限。可以使用JWT解析工具验证令牌的scp声明是否包含Calendars.ReadWrite或Calendars.ReadWrite.All。

5. 权限配置确认

  • 确保Azure AD应用注册中添加的是委托权限的Calendars.ReadWrite.All,而非应用权限;
  • 确认已完成管理员同意(针对租户级权限);
  • 如果仅操作当前用户的日历,Calendars.ReadWrite权限已足够,无需使用Calendars.ReadWrite.All。

内容的提问来源于stack exchange,提问作者user3330412

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 11:10:50