使用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参数无法保留:
- 首次请求时,系统无有效Graph访问令牌,
AuthorizeForScopes会触发重定向到Azure AD进行令牌获取; - 重定向返回后,请求变为GET方式,原POST提交的
groupName参数丢失,导致参数为null; - 第二次请求时,令牌已缓存,无需重定向,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
相关产品推荐
相关产品推荐

