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

使用Microsoft Graph异步方法填充视图时的异常问题

问题:首次调用Microsoft Graph API时POST参数丢失

现象

在ASP.NET Core MVC项目中,通过POST表单提交组名调用ADInquiryAction,首次执行到await _graphServiceClient.Groups.Request().GetAsync()时,系统会跳转到Azure AD获取访问令牌,返回后groupName参数变为null,进入空值分支;第二次执行相同操作时,因令牌已缓存无需重定向,流程正常执行并返回正确数据。

代码背景

控制器代码

public class HomeController : Controller
{
    private readonly GraphServiceClient _graphServiceClient;
    public HomeController(GraphServiceClient graphServiceClient)
    {
        _graphServiceClient = graphServiceClient;
    }   
    [AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
    public async Task<IActionResult> ADInquiry(string groupName)
    {
        var vm = new ViewModel();    
        if (string.IsNullOrWhiteSpace(groupName))
        {
            return View(vm);
        }

        var groupInfo = await _graphServiceClient.Groups.Request()
             .Filter($"displayName eq '{groupName}'")
             .Select("id")
             .GetAsync();

        // Transform groupInfo to populate view model
        return View(vm);
    }
}

视图代码

<form asp-action="ADInquiry" method="post">
    <div class="mb-3 mt-3 row">
        <label for="@Model.GroupName" class="col-2 col-form-label text-end">Username or Group name</label>
        <div class="col-1">
            <input asp-for="@Model.GroupName" type="text" class="form-control col-2" placeholder="Group Name">
        </div>

        <button type="submit" value="Search" class="btn btn-success">
            <i class="fas fa-search" title="Search"> Search</i>
        </button>

    </div>
</form>
<table>
     @* Show data in table *@
</table>

中间件配置

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add services to the container.
        builder.Services.AddControllersWithViews();

        var initialScopes = builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
        builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
        .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"))
                .EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
                    .AddMicrosoftGraph(builder.Configuration.GetSection("DownstreamApi"))
                    .AddInMemoryTokenCaches();

        builder.Services.AddAuthorization(options =>
        {
            // By default, all incoming requests will be authorized according to the default policy.
            options.FallbackPolicy = options.DefaultPolicy;
        });
        builder.Services.AddRazorPages();

        var app = builder.Build();

        // Configure the HTTP request pipeline.
        if (!app.Environment.IsDevelopment())
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();

        app.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");

        app.Run();
    }
}

原因分析

问题根源在于Microsoft Identity Web的令牌获取流程会触发重定向,而原请求为POST方式,重定向后POST参数无法保留:

  1. 首次请求时,系统无有效Graph访问令牌,AuthorizeForScopes会触发重定向到Azure AD进行令牌获取;
  2. 重定向返回后,请求变为GET方式,原POST提交的groupName参数丢失,导致参数为null;
  3. 第二次请求时,令牌已缓存,无需重定向,POST参数正常传递,流程执行正常。

修复方案

方案1:将请求改为GET(推荐)

将表单提交方式改为GET,参数会携带在URL中,重定向后不会丢失:

修改视图代码

<form asp-action="ADInquiry" method="get">
    <!-- 其余内容保持不变 -->
</form>

修改控制器代码(显式指定HttpGet)

[HttpGet]
[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
public async Task<IActionResult> ADInquiry(string groupName)
{
    // 现有代码不变
}

方案2:保留POST,用TempData保存参数

如果必须使用POST,可在首次请求时将参数存入TempData,重定向返回后从TempData中取出:

修改控制器代码

[HttpPost]
[AuthorizeForScopes(ScopeKeySection = "DownstreamApi:Scopes")]
public async Task<IActionResult> ADInquiry(string groupName)
{
    // 重定向回来时从TempData恢复参数
    if (string.IsNullOrWhiteSpace(groupName))
    {
        groupName = TempData["GroupName"] as string;
    }
    else
    {
        // 首次请求时保存参数到TempData
        TempData["GroupName"] = groupName;
    }

    var vm = new ViewModel();    
    if (string.IsNullOrWhiteSpace(groupName))
    {
        return View(vm);
    }

    var groupInfo = await _graphServiceClient.Groups.Request()
         .Filter($"displayName eq '{groupName}'")
         .Select("id")
         .GetAsync();

    // Transform groupInfo to populate view model
    return View(vm);
}

注意:TempData默认依赖会话状态,确保项目已启用会话(ASP.NET Core MVC默认已启用)。

内容的提问来源于stack exchange,提问作者LUAN-I JACKSON

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 05:54:58