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

ASP.NET Core无参构造函数中如何正确获取Session值

问题根因

反序列化流程创建Category实例时,是序列化组件通过反射直接调用无参构造函数生成对象,完全不会走依赖注入容器的实例构建管线,因此任何通过构造注入、属性注入的IHttpContextAccessor实例都会是null,不可能在无参构造中直接通过DI拿到该服务。

另外你的原始代码存在几处编译/运行时问题:

  • Dictionary<"string", "string">属于语法错误,泛型参数不需要包裹双引号,正确写法为Dictionary<string, string>
  • localization属性的泛型嵌套定义和内部取值逻辑不匹配,TryGetValue的输出值类型和字典定义不一致,运行时会抛类型转换异常
  • 没有对localization做null判断,属性未赋值时访问Name会触发空引用异常
解决方案

方案1:实体与Web上下文解耦(推荐)

实体类本身不应该直接依赖Session、HttpContext这类Web层组件,你可以把语言参数的赋值逻辑从构造函数中移出,反序列化完成后,在能正常获取IHttpContextAccessor的Web层代码(比如Controller、应用服务)中手动给实例赋值。

修正后的实体代码:

public class Category
{
    private string _language;
    private string _Name;

    /// <summary>
    /// 供外部调用设置当前语言
    /// </summary>
    /// <param name="language">当前语言编码</param>
    public void SetLanguage(string language)
    {
        _language = language;
    }

    public string Name { 
        get {
                if (!string.IsNullOrEmpty(_language) && localization != null)
                {
                    Dictionary<string, string> dict = null;
                    localization.FirstOrDefault(x => x.TryGetValue(_language, out dict));
                    return dict != null && dict.ContainsKey("name") ? dict["name"] : _Name;
                }
                return _Name;
        }
        set => _Name = value;
    }

    // 修正错误的泛型定义
    public List<Dictionary<string, Dictionary<string, string>>> localization { get; set; }
}

调用示例(在已注入IHttpContextAccessor的Web层代码中):

// 反序列化得到实体实例
var category = JsonSerializer.Deserialize<Category>(jsonContent);
// 从Session取当前语言,默认降级为french
var currentLang = _httpContextAccessor.HttpContext?.Session?.GetString("CurrentLanguage") ?? "french";
// 手动给实体赋值语言
category.SetLanguage(currentLang);

该方案符合分层职责划分,实体类可以脱离Web场景独立运行,单元测试也不需要额外模拟Web上下文,稳定性最高。

方案2:静态服务定位器(仅兼容老代码使用,不推荐)

如果因为历史代码原因必须在无参构造中直接获取Session值,可以通过静态引用保存全局IHttpContextAccessor实例,绕开DI直接访问。
第一步,在Program.cs启动时注册服务并保存静态引用:

var builder = WebApplication.CreateBuilder(args);
// 注册IHttpContextAccessor,默认框架不会自动注册该服务
builder.Services.AddHttpContextAccessor();
var app = builder.Build();
// 构建服务提供者,保存IHttpContextAccessor全局实例
HttpContextStatic.Accessor = app.Services.GetRequiredService<IHttpContextAccessor>();

// 其余中间件配置、路由配置保持不变

第二步,定义静态访问辅助类:

public static class HttpContextStatic
{
    internal static IHttpContextAccessor Accessor { get; set; }
    public static HttpContext Current => Accessor?.HttpContext;
}

第三步,在Category构造函数中直接读取Session:

public Category()
{
    // 非Web请求场景下做默认值降级
    _language = HttpContextStatic.Current?.Session?.GetString("CurrentLanguage") ?? "french";
}

注意:该方案属于服务定位器反模式,会让实体类强依赖ASP.NET Core Web组件,脱离Web宿主无法运行,单元测试需要手动初始化静态配置,仅适合老代码快速兼容,优先选择方案1。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 09:45:38