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

.NET Core DI作用域服务值传递为空:控制器到仓库取值异常

.NET Core 依赖注入(DI)作用域服务值传递问题

问题描述

登录时已成功为ScopService的UserName属性赋值,但跳转到HomeController后,注入的_scopService的UserName始终为null,无法将值传递到HomeRepo中。已将ScopService注册为作用域服务,请教如何正确将值传递到仓库?

代码示例

// ConfigureServices 中的服务注册
ConfigureServices(IServiceCollection services)
{
    services.AddScoped<ScopService>();
}

// LogInController
public class LogInController
{
    private readonly ScopService _userService;

    public LogInController(ScopService userService)
    {
        _userService = userService;
    }

    public ActionResult LogIn()
    {
        // 假设 Userdt 是查询到的数据表
        _userService.UserName = Convert.ToString(Userdt.Rows[0]["UserName"]); // 值设置正确
        return RedirectToAction("Index", "Home");
    }
}

// HomeController
public class HomeController
{
    private readonly HomeRepo _repo;
    public ScopService _userService { get; }

    public HomeController(ScopService ser)
    {
        _userService = ser; // 此处 _userService.UserName 为 null
        this.repo = new HomeRepo(_userService);
    }
}

// HomeRepo
public class HomeRepo : _baseRepo
{
    public ScopService _service { get; }

    public HomeRepo(ScopService service) : base(service) 
    {
        _service = service; // 此处 _service.UserName 为 null
    }

    public void Find()
    {
        string username = _service.UserName;
    }
}

// _baseRepo
public class _baseRepo
{
    protected readonly ScopService _userService;

    public _baseRepo(ScopService userService)
    {
        _userService = userService;
    }
}

注:原问题提及“.NET Core单例服务控制器出现空服务”,但实际注册的是作用域服务。


问题原因与解决方案

核心原因

HTTP请求是无状态的,每个HTTP请求对应一个独立的DI作用域。登录请求是一个作用域,跳转后的Home请求是另一个全新的作用域,两个请求中的ScopService是完全独立的实例,因此登录时设置的值无法跨请求保留。

正确解决方案

方案1:使用Session存储用户信息(简单实用)

  1. 启用Session支持:
    在ConfigureServices中添加Session配置:
services.AddSession(options =>
{
    options.IdleTimeout = TimeSpan.FromMinutes(30); // 设置Session超时时间
    options.Cookie.HttpOnly = true;
    options.Cookie.IsEssential = true;
});
// 注册HttpContextAccessor用于访问Session
services.AddHttpContextAccessor();

在Configure管道中启用Session(注意顺序,需放在路由之后、端点之前):

app.UseRouting();
app.UseSession(); // 启用Session
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "default",
        pattern: "{controller=Home}/{action=Index}/{id?}");
});
  1. 登录时将用户信息存入Session:
public ActionResult LogIn()
{
    string userName = Convert.ToString(Userdt.Rows[0]["UserName"]);
    // 将用户名存入Session
    HttpContext.Session.SetString("UserName", userName);
    return RedirectToAction("Index", "Home");
}
  1. 在HomeController和HomeRepo中读取Session:
    修改HomeController和HomeRepo,通过IHttpContextAccessor获取Session中的用户名:
// HomeController
public class HomeController
{
    private readonly HomeRepo _repo;

    public HomeController(IHttpContextAccessor httpContextAccessor)
    {
        string userName = httpContextAccessor.HttpContext.Session.GetString("UserName");
        _repo = new HomeRepo(userName);
    }
}

// HomeRepo 修改为直接接收用户名
public class HomeRepo : _baseRepo
{
    private readonly string _userName;

    public HomeRepo(string userName) : base(userName)
    {
        _userName = userName;
    }

    public void Find()
    {
        string username = _userName;
    }
}

// 修改_baseRepo
public class _baseRepo
{
    protected readonly string _userName;

    public _baseRepo(string userName)
    {
        _userName = userName;
    }
}

方案2:使用ASP.NET Core认证系统(生产环境首选)

如果是正规的用户登录场景,推荐使用ASP.NET Core Identity或JWT认证,认证成功后用户信息会自动绑定到User对象,无需手动传递:

  1. 配置认证系统后,登录时调用认证API完成登录(例如SignInManager.PasswordSignInAsync)。
  2. 在任意控制器或服务中通过ClaimsPrincipal获取用户信息:
// 在HomeController中直接获取
public ActionResult Index()
{
    string userName = User.Identity.Name;
    return View();
}

// 在HomeRepo中通过IHttpContextAccessor获取
public class HomeRepo
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HomeRepo(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void Find()
    {
        string userName = _httpContextAccessor.HttpContext.User.Identity.Name;
    }
}

方案3:改造ScopService为基于Session的服务

如果一定要保留ScopService的结构,可以将其改造为依赖Session的服务,确保跨请求能读取到同一个值:

public class ScopService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public ScopService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public string UserName 
    { 
        get => _httpContextAccessor.HttpContext.Session.GetString("UserName");
        set => _httpContextAccessor.HttpContext.Session.SetString("UserName", value);
    }
}

注册方式不变,但此时ScopService的UserName会从Session中读写,跨请求也能获取到正确值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 12:04:55