DotNetCoreRazor_MSGraph邮件文件夹结构生成异常及断点失效排查
.NET Core Razor + MS Graph 邮件文件夹结构生成问题
我正在修改DotNetCoreRazor_MSGraph示例项目,目标是先生成邮件文件夹结构,而非直接展示所有不区分文件夹的邮件。目前OnGetAsync方法已被调用且未抛出错误,但页面输出仅为<ul id="myUL"></ul>(标签后带有换行符),folders列表无内容。另外后端代码断点被跳过,仅EmailFolders.cshtml页面的断点可触发,但此时后端逻辑已执行完毕,无法排查问题。
以下是EmailFolders.cshtml.cs的代码:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using DotNetCoreRazor_MSGraph.Graph; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Extensions.Logging; using Microsoft.Graph; using Microsoft.Identity.Web; using Newtonsoft.Json; namespace DotNetCoreRazor_MSGraph.Pages { [AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")] public class EmailFoldersModel : PageModel { private readonly GraphEmailClient _graphEmailClient; private readonly GraphServiceClient _graphServiceClient; private string inboxid = null; private string sentitemsid = null; private string draftsid = null; [BindProperty(SupportsGet = true)] public string NextLink { get; set; } public IEnumerable<Message> Messages { get; private set; } public EmailFoldersModel(GraphEmailClient graphEmailClient, GraphServiceClient graphServiceClient) { _graphEmailClient = graphEmailClient; _graphServiceClient = graphServiceClient; } public StringBuilder sb = new StringBuilder(); public List<MailFolder> folders = new List<MailFolder>(); public async Task OnGetAsync() { MailFolder inbox = await _graphServiceClient.Me.MailFolders.Inbox.Request().GetAsync(); inboxid = inbox.Id; MailFolder sentitems = await _graphServiceClient.Me.MailFolders.SentItems.Request().GetAsync(); sentitemsid = sentitems.Id; MailFolder drafts = await _graphServiceClient.Me.MailFolders.Drafts.Request().GetAsync(); draftsid = drafts.Id; //get all folders on all pages IUserMailFoldersCollectionPage flds = await _graphServiceClient.Me.MailFolders.Request().GetAsync(); folders.AddRange(flds.CurrentPage); while (flds.NextPageRequest != null) { flds = await flds.NextPageRequest.GetAsync(); folders.AddRange(flds.CurrentPage); } //move drafts to the top of the list foreach (MailFolder folder in folders) { if (folder.Id == draftsid) { folders.Remove(folder); folders.Prepend(folder); break; } } //move sentitems to the top of the list foreach (MailFolder folder in folders) { if (folder.Id == sentitemsid) { folders.Remove(folder); folders.Prepend(folder); break; } } //move inbox to the top of the list foreach (MailFolder folder in folders) { if (folder.Id == inboxid) { folders.Remove(folder); folders.Prepend(folder); break; } } //create the HTML <ul> structure sb.AppendLine("<ul id=\"myUL\">"); foreach (MailFolder folder in folders.Where(f => f.ParentFolderId == null)) { if (folder.ChildFolderCount > 0) sb.AppendLine("<li class=\"caret\">"); else sb.AppendLine("<li>"); sb.AppendLine(folder.DisplayName); if (folder.ChildFolderCount > 0) { await CreateList(folder.Id); } sb.AppendLine("</li>"); } sb.AppendLine("</ul>"); await Task.CompletedTask; } //html recursor private async Task CreateList(string MailFolderId) { StringBuilder sb = new StringBuilder(); sb.AppendLine("<ul class=\"nested\">"); foreach (MailFolder folder in folders.Where(f => f.ParentFolderId == MailFolderId)) { if (folder.ChildFolderCount > 0) sb.AppendLine("<li class=\"caret\">"); else sb.AppendLine("<li>"); sb.AppendLine(folder.DisplayName); if (folder.ChildFolderCount > 0) { await CreateList(folder.Id); } sb.AppendLine("</li>"); } sb.AppendLine("</ul>"); } //folder recursor private async Task GetChildFolders(string MailFolderId) { List<MailFolder> childfolders = new List<MailFolder>(); IMailFolderChildFoldersCollectionPage chlds = await _graphServiceClient.Me.MailFolders[MailFolderId].ChildFolders.Request().GetAsync(); childfolders.AddRange(chlds.CurrentPage); while (chlds.NextPageRequest != null) { chlds = await chlds.NextPageRequest.GetAsync(); childfolders.AddRange(chlds.CurrentPage); } folders.AddRange(childfolders); foreach (MailFolder folder in childfolders) { if (folder.ChildFolders.Count > 0) { await GetChildFolders(folder.Id); } } } } }
问题分析与修复方案
1. 核心问题:folders列表无内容的原因
- Outlook/Exchange的邮件文件夹结构中,根文件夹(ParentFolderId为null)仅存在一个顶级目录,收件箱、已发送、草稿等都是它的子文件夹,你直接筛选
f.ParentFolderId == null的文件夹,无法获取到需要展示的实际文件夹。 - 代码中定义了
GetChildFolders递归获取子文件夹的方法,但从未调用过,导致folders仅包含顶层根目录,没有子文件夹数据。 CreateList方法中重新声明了局部StringBuilder sb,覆盖了类级别的sb,导致递归生成的子文件夹HTML没有追加到最终输出中。
2. 修复步骤
(1)调用GetChildFolders加载所有子文件夹
在OnGetAsync方法中,获取完顶层文件夹后,添加递归加载子文件夹的逻辑:
//get all folders on all pages IUserMailFoldersCollectionPage flds = await _graphServiceClient.Me.MailFolders.Request().GetAsync(); folders.AddRange(flds.CurrentPage); while (flds.NextPageRequest != null) { flds = await flds.NextPageRequest.GetAsync(); folders.AddRange(flds.CurrentPage); } // 新增:递归加载所有子文件夹 foreach (var rootFolder in folders.Where(f => f.ParentFolderId == null)) { await GetChildFolders(rootFolder.Id); }
(2)修复CreateList的StringBuilder变量覆盖问题
删除CreateList方法中的局部StringBuilder声明,直接使用类级别的sb:
//html recursor private async Task CreateList(string MailFolderId) { sb.AppendLine("<ul class=\"nested\">"); foreach (MailFolder folder in folders.Where(f => f.ParentFolderId == MailFolderId)) { if (folder.ChildFolderCount > 0) sb.AppendLine("<li class=\"caret\">"); else sb.AppendLine("<li>"); sb.AppendLine(folder.DisplayName); if (folder.ChildFolderCount > 0) { await CreateList(folder.Id); } sb.AppendLine("</li>"); } sb.AppendLine("</ul>"); }
(3)调整文件夹展示逻辑
修改HTML生成逻辑,从根文件夹的子节点开始展示(即收件箱、已发送等实际文件夹):
//create the HTML <ul> structure sb.AppendLine("<ul id=\"myUL\">"); // 找到根文件夹,展示它的子文件夹 var rootFolder = folders.FirstOrDefault(f => f.ParentFolderId == null); if (rootFolder != null) { foreach (MailFolder folder in folders.Where(f => f.ParentFolderId == rootFolder.Id)) { if (folder.ChildFolderCount > 0) sb.AppendLine("<li class=\"caret\">"); else sb.AppendLine("<li>"); sb.AppendLine(folder.DisplayName); if (folder.ChildFolderCount > 0) { await CreateList(folder.Id); } sb.AppendLine("</li>"); } } sb.AppendLine("</ul>");
(4)修复断点无法触发的问题
- 确认
launchSettings.json中ASPNETCORE_ENVIRONMENT的值为Development - 在Visual Studio调试设置中,关闭「仅我的代码」(工具 → 选项 → 调试 → 常规 → 取消勾选「启用仅我的代码」)
- 清理项目并重新生成,重启调试会话
内容的提问来源于stack exchange,提问作者Lisa
相关产品推荐
相关产品推荐

