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
相关产品推荐
相关产品推荐

