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

.NET Core 2.x控制器Session测试问题及优化方案咨询

嘿,针对你遇到的这个.NET Core 2.x项目中Session存储Token且测试困难的问题,我给你几个实用的解决方案,帮你轻松搞定跨控制器存数据+易测试的需求:

方案1:用IMemoryCache替代Session(最易测试)

Session本质上也是基于缓存的,但直接用IMemoryCache更轻量,而且天生支持依赖注入,测试时Mock起来特别方便。

步骤:

  1. 注册服务:在Startup.cs的ConfigureServices里添加内存缓存服务:
services.AddMemoryCache();
  1. 控制器注入使用:在Login控制器和其他需要访问Token的控制器中注入IMemoryCache:
private readonly IMemoryCache _memoryCache;

public LoginController(IMemoryCache memoryCache)
{
    _memoryCache = memoryCache;
}
  1. 存储Token:登录成功后直接存入缓存,还可以设置过期时间:
// 存储Token,2小时过期
_memoryCache.Set("UserToken", "your-actual-token", TimeSpan.FromHours(2));
  1. 跨控制器获取Token:在其他控制器中同样注入IMemoryCache,然后取值:
if (_memoryCache.TryGetValue("UserToken", out string token))
{
    // 拿到Token做后续操作
}
  1. 测试时Mock:用Moq轻松模拟IMemoryCache,不需要处理HttpContext:
var mockCache = new Mock<IMemoryCache>();
string testToken = "mock-test-token";
// 模拟TryGetValue的行为
mockCache.Setup(c => c.TryGetValue("UserToken", out It.Ref<string>.IsAny))
         .Returns(true)
         .Callback((object key, out string value) => value = testToken);

// 注入到控制器
var controller = new LoginController(mockCache.Object);
方案2:修复MockHttpSession的实现

如果你坚持要用Session,那问题出在你当前的MockHttpSession没有正确处理字符串的序列化/反序列化。你可以自己实现一个更完善的Mock Session:

自定义TestHttpSession:

public class TestHttpSession : ISession
{
    private readonly Dictionary<string, byte[]> _storage = new Dictionary<string, byte[]>();

    public string Id => "test-session-id";
    public bool IsAvailable => true;
    public IEnumerable<string> Keys => _storage.Keys;

    public void Clear() => _storage.Clear();
    public Task CommitAsync(CancellationToken cancellationToken = default) => Task.CompletedTask;
    public Task LoadAsync(CancellationToken cancellationToken = default) => Task.CompletedTask;
    public void Remove(string key) => _storage.Remove(key);
    public void Set(string key, byte[] value) => _storage[key] = value;
    public bool TryGetValue(string key, out byte[] value) => _storage.TryGetValue(key, out value);

    // 增加方便的字符串读写方法
    public string GetString(string key)
    {
        if (TryGetValue(key, out var bytes))
        {
            return Encoding.UTF8.GetString(bytes);
        }
        return null;
    }

    public void SetString(string key, string value)
    {
        Set(key, Encoding.UTF8.GetBytes(value));
    }
}

测试时使用:

var testSession = new TestHttpSession();
testSession.SetString("UserToken", "mock-token");

// 给控制器设置HttpContext
var controller = new LoginController();
controller.ControllerContext = new ControllerContext
{
    HttpContext = new DefaultHttpContext { Session = testSession }
};

// 现在调用GetString就能拿到正确值了
var token = controller.HttpContext.Session.GetString("UserToken");
方案3:封装自定义会话服务(最推荐,符合DDD)

如果项目规模较大,建议封装一个抽象的会话服务,把存储逻辑和业务代码解耦,这样后续替换存储方式(比如从Session换成Redis)也不用改业务代码,测试也超简单。

步骤:

  1. 定义抽象接口:
public interface IUserSession
{
    string GetUserToken();
    void SetUserToken(string token);
}
  1. 实现基于Session的版本:
public class SessionUserSession : IUserSession
{
    private readonly IHttpContextAccessor _httpContextAccessor;

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

    public string GetUserToken()
    {
        return _httpContextAccessor.HttpContext?.Session.GetString("UserToken");
    }

    public void SetUserToken(string token)
    {
        _httpContextAccessor.HttpContext?.Session.SetString("UserToken", token);
    }
}
  1. 注册服务:在Startup.cs中注册:
services.AddHttpContextAccessor();
services.AddScoped<IUserSession, SessionUserSession>();
  1. 控制器中使用:
private readonly IUserSession _userSession;

public LoginController(IUserSession userSession)
{
    _userSession = userSession;
}

// 存储Token
_userSession.SetUserToken("your-token");

// 其他控制器获取Token
var token = _userSession.GetUserToken();
  1. 测试时Mock:直接写一个测试用的实现,完全不用碰HttpContext:
public class MockUserSession : IUserSession
{
    public string CurrentToken { get; set; }

    public string GetUserToken() => CurrentToken;
    public void SetUserToken(string token) => CurrentToken = token;
}

// 测试时使用
var mockSession = new MockUserSession { CurrentToken = "test-token" };
var controller = new LoginController(mockSession);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:04:41