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

在C#中使用Microsoft Graph获取组织所有用户头像

解决.NET Core 6中使用Microsoft Graph SDK(App-Only令牌)获取用户头像并保存为JPG的问题

代码核心问题修正

你当前的代码存在两个关键问题:

  • 返回类型冗余:Task<Task<ProfilePhoto?>> 是嵌套任务,应直接返回 Task<Stream?>(我们需要的是头像二进制流,而非ProfilePhoto元数据对象)
  • 获取对象错误:Photo.GetAsync() 仅获取头像的属性信息(如尺寸),并非实际图片内容,需调用 Content.GetAsync() 获取二进制数据流

修正后的头像流获取方法:

public static async Task<Stream?> GetUserPhotoStream(string userId)
{
    _ = _appClient ?? throw new NullReferenceException("Graph客户端未完成初始化");
    
    try
    {
        // 获取头像的二进制内容流
        return await _appClient.Users[userId].Photo.Content.GetAsync();
    }
    catch (ODataError odataError)
    {
        // 输出完整错误信息便于排查
        Console.WriteLine($"错误代码: {odataError.Error.Code}");
        Console.WriteLine($"错误描述: {odataError.Error.Message}");
        Console.WriteLine($"请求ID: {odataError.Error.RequestId}");
        return null;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"未知异常: {ex.Message}");
        return null;
    }
}

应用权限确认

确保你的Azure AD应用注册已配置正确的应用权限:

  • 添加 User.Read.All 或 Directory.Read.All(优先选择User.Read.All,权限范围更精准)
  • 必须由租户管理员完成权限同意,App-Only令牌才能正常访问用户数据

保存为JPG文件的实现

拿到头像流后,直接写入本地文件即可:

public static async Task SavePhotoToFile(string userId, string savePath)
{
    var photoStream = await GetUserPhotoStream(userId);
    if (photoStream == null)
    {
        Console.WriteLine($"用户 {userId} 无头像或获取失败");
        return;
    }
    
    using var fileStream = new FileStream(savePath, FileMode.Create, FileAccess.Write);
    await photoStream.CopyToAsync(fileStream);
    Console.WriteLine($"头像已保存至: {savePath}");
}

批量获取组织内所有用户头像

若要批量获取所有用户头像,可先枚举用户列表,再逐个调用上述方法:

public static async Task GetAllUserPhotos(string saveDirectory)
{
    // 确保保存目录存在
    Directory.CreateDirectory(saveDirectory);
    
    try
    {
        // 分页获取用户列表(仅返回必要字段)
        var usersPage = await _appClient.Users.GetAsync(requestConfig => 
            requestConfig.QueryParameters.Select = new[] { "id", "userPrincipalName" });
        
        foreach (var user in usersPage.Value)
        {
            var savePath = Path.Combine(saveDirectory, $"{user.UserPrincipalName}.jpg");
            await SavePhotoToFile(user.Id, savePath);
        }
        
        // 处理分页(用户数量超过默认页大小时)
        while (usersPage.OdataNextLink != null)
        {
            usersPage = await _appClient.Users.WithUrl(usersPage.OdataNextLink).GetAsync();
            foreach (var user in usersPage.Value)
            {
                var savePath = Path.Combine(saveDirectory, $"{user.UserPrincipalName}.jpg");
                await SavePhotoToFile(user.Id, savePath);
            }
        }
    }
    catch (ODataError odataError)
    {
        Console.WriteLine($"批量获取用户失败: {odataError.Error.Message}");
    }
}

常见错误排查

  • ResourceNotFound:用户未设置头像,或传入的用户ID无效
  • Authorization_RequestDenied:应用权限未配置,或未获得管理员同意
  • AccessDenied:令牌权限不足,检查是否添加了正确的应用权限

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 06:05:11