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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 14:17:03