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

.NET Core 2.1升级3.1遇OptionsValidationException报错求助

问题概述

将ASP.NET Core 2.1应用升级至3.1后,首次加载项目时触发OptionsValidationException: Cookie.Expiration is ignored, use ExpireTimeSpan instead错误,场景为未登录用户访问默认路由的UserProfiles控制器,被重定向到登录页时触发异常。

原因分析

  1. API弃用:ASP.NET Core 3.0及以上版本中,CookieAuthenticationOptions.Cookie.Expiration属性已被官方弃用,框架要求使用ExpireTimeSpan属性配置Cookie过期时间,继续使用旧属性会触发验证异常。
  2. 配置冲突:代码中同时通过AddCookie和ConfigureApplicationCookie配置Cookie过期时间,导致配置优先级冲突,加重异常触发概率。
  3. 中间件顺序错误:会话中间件(UseSession)的位置在认证中间件(UseAuthentication)之后,违反ASP.NET Core中间件执行顺序规范,加剧认证流程中的异常。
  4. 控制器未做登录校验:UserProfiles控制器的Index方法未先验证用户是否登录,直接尝试解析User.Identity.Name,未登录时会引发额外异常。

解决方案

1. 替换弃用的Cookie过期配置

移除AddCookie中的options.Cookie.Expiration配置,改用options.ExpireTimeSpan统一设置Cookie过期时间。

2. 统一Cookie配置优先级

删除重复的ConfigureApplicationCookie配置(或保持与AddCookie配置一致),避免配置冲突。

3. 调整中间件执行顺序

按照ASP.NET Core官方规范调整中间件顺序,确保UseSession在UseAuthentication之前执行,同时添加必要的UseAuthorization中间件。

4. 完善控制器登录校验逻辑

在控制器方法开头先验证用户是否已登录,避免未登录时解析无效的User.Identity.Name。

修改后代码示例

Startup.cs ConfigureServices 方法修改

public void ConfigureServices(IServiceCollection services)
{
    var connection = Configuration.GetConnectionString("DentalDBconnection");
    services.AddDbContext<HoshmandDBContext>(option => option.UseSqlServer(connection));
    services.AddAuthentication(option =>
    {
        option.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        option.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        option.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })
    .AddCookie(options =>
    {
        options.LoginPath = "/Logins/UserLogin/";
        options.AccessDeniedPath = "/AccessDenied";
        // 替换弃用的Cookie.Expiration,改用ExpireTimeSpan
        options.ExpireTimeSpan = TimeSpan.FromHours(10);
    });

    services.AddDistributedMemoryCache();
    services.AddSession(options =>
    {
        options.IdleTimeout = TimeSpan.FromHours(2);
        options.Cookie.HttpOnly = true;
        options.Cookie.IsEssential = true;
    });

    // 移除重复的ConfigureApplicationCookie配置,避免冲突
    // services.ConfigureApplicationCookie(option =>
    // {
    //     option.ExpireTimeSpan = TimeSpan.FromMinutes(540);
    // });

    services.AddAuthorization(options =>
    {
        options.AddPolicy("HasAccess", policy => policy.AddRequirements(new HasAccessRequirment()));
    });
    services.AddTransient<IAuthorizationHandler, HasAccessHandler>();
    services.AddTransient<IMvcControllerDiscovery, MvcControllerDiscovery>();
    services.AddMvc();
}

Startup.cs Configure 方法修改

public void Configure(IApplicationBuilder app)
{
    if (Environment.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    var cachePeriod = Environment.IsDevelopment() ? "600" : "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            ctx.Context.Response.Headers.Append("Cache-Control", $"public, max-age={cachePeriod}");
        }
    });
    app.UseHttpsRedirection();
    // 移除重复的UseStaticFiles调用
    // app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseSession();
    app.UseRouting();
    app.UseCors();
    app.UseAuthentication();
    app.UseAuthorization(); // 添加必要的授权中间件
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=UserProfiles}/{action=Index}/{id?}");
    });
}

UserProfilesController.cs Index 方法修改

public async Task<IActionResult> Index(bool? passIsChanged = null)
{
    if (passIsChanged != null)
    {
        ViewBag.isSuccessed = passIsChanged;
    }

    // 先验证用户是否已登录
    if (!User.Identity.IsAuthenticated)
    {
        return RedirectToAction("UserLogin", "Logins");
    }

    // 安全解析用户ID
    if (!int.TryParse(User.Identity.Name, out int id))
    {
        return RedirectToAction("UserLogin", "Logins");
    }

    var user = _context.UserAccountTbs.FirstOrDefault(a => a.UserId == id);
    if (user == null)
    {
        return RedirectToAction("UserLogin", "Logins");
    }

    // 返回视图(原代码缺失,需补充)
    return View(user);
}

验证步骤

  1. 启动应用,访问默认路由
  2. 未登录状态下会自动重定向到登录页,此时不再触发OptionsValidationException
  3. 登录后正常访问UserProfiles控制器的Index页面

内容的提问来源于stack exchange,提问作者Hedayat Hoshmand

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 04:55:18