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

.NET 6环境下Microsoft Forms认证及响应读取故障排查求助

排查Microsoft Forms Graph API访问问题

一、先确认认证与权限是否有效

  • 单独测试Token获取:在GetToken方法里添加Console.WriteLine(token);,把输出的Token复制到jwt.ms解析,检查:
    • aud字段必须是https://graph.microsoft.com
    • roles字段必须包含Forms.Read.All或Forms.ReadWrite.All(没有的话就是权限配置错误)
  • 检查Azure AD应用配置:
    • 必须添加应用权限(而非委托权限),权限选择Forms.Read.All或更高等级
    • 必须完成管理员同意(client_credentials流必须管理员同意才能生效)
    • 确认表单属于当前租户,个人Microsoft账户的表单不支持Graph API访问

二、代码问题修正

1. 模型类不匹配Graph API响应结构

原代码的FormResponse、QuestionResponse和Graph实际返回的JSON结构不符,以下是正确的模型类:

using System.Text.Json.Serialization;

class FormResponseCollection
{
    public List<FormResponse> Value { get; set; }
}

class FormResponse
{
    public string Id { get; set; }
    public DateTimeOffset SubmittedDateTime { get; set; }
    public List<FormAnswer> Answers { get; set; }
}

class FormAnswer
{
    public string QuestionId { get; set; }
    public string QuestionText { get; set; }
    public AnswerValue AnswerValue { get; set; }
}

class AnswerValue
{
    public List<string> Choices { get; set; }
    public string Text { get; set; }
    public int? Rating { get; set; }
    // 根据你的表单类型添加其他字段,比如日期、文件等
}

class TokenResponse
{
    [JsonPropertyName("access_token")]
    public string AccessToken { get; set; }
}

2. 添加错误捕获与调试信息

原代码无异常处理,无法定位具体错误,修改GetFormResponses方法:

private static async Task<IList<FormResponse>> GetFormResponses()
{
    var clientId = "<your-client-id>";
    var tenantId = "<your-tenant-id>";
    var clientSecret = "<your-client-secret>";
    var formId = "<your-form-id>";

    try
    {
        var token = await GetToken(clientId, tenantId, clientSecret);
        Console.WriteLine($"获取到的Token前缀: {token.Substring(0, 50)}..."); // 输出前50位用于验证

        using var httpClient = new HttpClient();
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        var response = await httpClient.GetAsync($"https://graph.microsoft.com/v1.0/forms/{formId}/responses");
        try
        {
            response.EnsureSuccessStatusCode();
        }
        catch (HttpRequestException ex)
        {
            var errorContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine($"API请求失败: {ex.Message}");
            Console.WriteLine($"错误详情: {errorContent}");
            throw;
        }

        var content = await response.Content.ReadAsStringAsync();
        var options = new JsonSerializerOptions
        {
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        };

        var formResponses = JsonSerializer.Deserialize<FormResponseCollection>(content, options).Value;
        return formResponses;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"流程执行错误: {ex.Message}");
        throw;
    }
}

3. 调整打印逻辑

因为答案结构变化,修改PrintResponses方法适配新模型:

private static void PrintResponses(IList<FormResponse> responses)
{
    foreach (var response in responses)
    {
        Console.WriteLine($"Response ID: {response.Id}");
        Console.WriteLine($"提交时间: {response.SubmittedDateTime}");
        Console.WriteLine("回答内容:");

        foreach (var answer in response.Answers)
        {
            Console.WriteLine($"  问题: {answer.QuestionText}");
            string answerContent = "";
            if (answer.AnswerValue.Choices != null && answer.AnswerValue.Choices.Count > 0)
            {
                answerContent = string.Join(", ", answer.AnswerValue.Choices);
            }
            else if (!string.IsNullOrEmpty(answer.AnswerValue.Text))
            {
                answerContent = answer.AnswerValue.Text;
            }
            else if (answer.AnswerValue.Rating.HasValue)
            {
                answerContent = answer.AnswerValue.Rating.Value.ToString();
            }
            Console.WriteLine($"  回答: {answerContent}");
        }

        Console.WriteLine();
    }
}

三、常见错误对应解决方案

  • 401 Unauthorized:Token无效,检查client_id/tenant_id/client_secret是否正确,或Token解析后的aud和roles是否符合要求
  • 403 Forbidden:权限不足,确认Azure应用的Forms权限已添加并完成管理员同意
  • 404 Not Found:表单ID错误,或表单不属于当前租户(个人表单无法访问)
  • 模型解析失败:打印返回的JSON内容,调整模型类字段与实际结构匹配

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 22:23:07