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

.NET Core MVC 6全局共享MS Graph用户信息至导航栏咨询

解决.NET Core MVC 6全局共享用户导航信息的方案

方案一:使用ViewComponent(推荐,组件化设计更易维护)

这种方式把用户信息的获取和渲染封装成独立组件,所有页面都能直接调用,无需每个控制器重复传值。

  1. 创建ViewComponent类
    在项目中新建Components文件夹,添加UserProfileViewComponent.cs:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Graph;

public class UserProfileViewComponent : ViewComponent
{
    private readonly GraphServiceClient _graphClient;

    // 注入已注册的GraphServiceClient
    public UserProfileViewComponent(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }

    public async Task<IViewComponentResult> InvokeAsync()
    {
        // 调用MS Graph获取当前用户核心信息
        var user = await _graphClient.Me.Request()
            .Select(u => new { u.DisplayName, u.MobilePhone, u.Photo })
            .GetAsync();

        // 封装成ViewModel(可根据需求扩展字段)
        var viewModel = new UserProfileViewModel
        {
            Name = user.DisplayName,
            Phone = user.MobilePhone,
            PhotoUrl = user.Photo != null ? Url.Action("GetUserPhoto", "Home") : "/images/default-avatar.png"
        };

        return View(viewModel);
    }
}

// 配套的ViewModel
public class UserProfileViewModel
{
    public string Name { get; set; }
    public string Phone { get; set; }
    public string PhotoUrl { get; set; }
}
  1. 创建ViewComponent视图
    在Views/Shared/Components/UserProfile路径下新建Default.cshtml(路径必须严格对应组件名):
<div class="user-nav-info">
    <img src="@Model.PhotoUrl" alt="用户头像" class="avatar" />
    <div class="user-details">
        <span class="user-name">@Model.Name</span>
        <span class="user-phone">@Model.Phone</span>
    </div>
</div>
  1. 在导航布局中调用组件
    打开_Layout.cshtml(或你的导航所在布局页),替换原_loginPartial的引用为:
@await Component.InvokeAsync("UserProfile")
  1. Program.cs中确保Graph服务注册
    如果还没注册MS Graph服务,在Program.cs中添加:
// 示例:基于Azure AD的Graph服务注册
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
    .EnableTokenAcquisitionToCallDownstreamApi(new[] { "User.Read" })
    .AddMicrosoftGraph(builder.Configuration.GetSection("Graph"))
    .AddInMemoryTokenCaches();

方案二:使用全局ActionFilter(全局注入ViewData)

通过过滤器在所有Action执行后自动把用户信息注入ViewData,实现全局共享。

  1. 创建全局ActionFilter类
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Graph;

public class UserProfileGlobalFilter : IAsyncActionFilter
{
    private readonly GraphServiceClient _graphClient;

    public UserProfileGlobalFilter(GraphServiceClient graphClient)
    {
        _graphClient = graphClient;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        var resultContext = await next();

        // 仅对视图结果注入数据
        if (resultContext.Result is ViewResult viewResult)
        {
            var user = await _graphClient.Me.Request()
                .Select(u => new { u.DisplayName, u.MobilePhone, u.Photo })
                .GetAsync();

            viewResult.ViewData["UserName"] = user.DisplayName;
            viewResult.ViewData["UserPhone"] = user.MobilePhone;
            viewResult.ViewData["UserPhotoUrl"] = user.Photo != null 
                ? resultContext.HttpContext.Request.PathBase + "/Home/GetUserPhoto" 
                : "/images/default-avatar.png";
        }
    }
}
  1. 在Program.cs注册全局过滤器
builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add<UserProfileGlobalFilter>();
});
  1. 导航视图中直接使用ViewData
<div class="user-nav-info">
    <img src="@ViewData["UserPhotoUrl"]" alt="用户头像" class="avatar" />
    <div class="user-details">
        <span class="user-name">@ViewData["UserName"]</span>
        <span class="user-phone">@ViewData["UserPhone"]</span>
    </div>
</div>

补充:用户头像获取接口

如果需要显示用户头像,在Home控制器中添加以下Action:

public async Task<IActionResult> GetUserPhoto()
{
    var graphClient = HttpContext.RequestServices.GetRequiredService<GraphServiceClient>();
    try
    {
        var photoStream = await graphClient.Me.Photo.Content.Request().GetAsync();
        return File(photoStream, "image/jpeg");
    }
    catch
    {
        // 头像获取失败时返回默认图
        return File("/images/default-avatar.png", "image/png");
    }
}

优化建议

为避免频繁调用MS Graph,可添加缓存逻辑(比如内存缓存),将用户信息缓存30分钟左右:

// 在ViewComponent或Filter中注入IDistributedCache
private readonly IDistributedCache _cache;

// 获取缓存或调用Graph
var cacheKey = $"UserProfile_{User.Identity.Name}";
var cachedProfile = await _cache.GetAsync<UserProfileViewModel>(cacheKey);
if (cachedProfile == null)
{
    // 调用Graph获取数据并缓存
    await _cache.SetAsync(cacheKey, viewModel, new DistributedCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)
    });
}
else
{
    viewModel = cachedProfile;
}

记得在Program.cs注册缓存服务:

builder.Services.AddDistributedMemoryCache();

内容的提问来源于stack exchange,提问作者Junior.netare

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 08:35:17