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

.NET C#测试中POST请求无法命中带授权的控制器方法问题

问题分析与解决方案

你的核心问题是测试代码中两次请求使用了独立的HttpClient实例,导致登录后的会话凭证(Cookie/Token)无法共享,进而触发[Authorize]拦截,请求未进入目标方法逻辑就返回了200(可能是授权失败后的跳转或默认响应)。以下是具体修复方案:


关键修复点

1. 复用同一个HttpClient实例

HttpClient设计为可复用对象,每次创建新实例会重置会话上下文,导致登录状态丢失。将整个测试流程放在同一个HttpClient的using块中。

2. 修正请求发送方式

  • 登录接口如果接收表单数据,需用PostAsync+FormUrlEncodedContent,而非PostAsJsonAsync(后者会把表单内容序列化为JSON,不符合接口预期)。
  • 目标接口的参数传递需匹配控制器方法的绑定规则:id未加修饰符时,ASP.NET Core默认从表单或请求体绑定,需保证请求格式正确。

3. 避免async void的测试方法

测试方法使用async void会导致测试框架无法正确等待异步操作完成,改为async Task。


修复后的测试代码(Cookie认证场景)

[Fact]
public async Task Modelo761_001()
{
    // 复用同一个HttpClient,保留会话凭证
    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.BaseAddress = new Uri("https://localhost:7117/"); // 设置基础地址,简化后续路径

        #region 登录获取会话
        var loginUrl = "Login/Acceder";
        var loginParams = new List<KeyValuePair<string, string>>()
        {
            new KeyValuePair<string, string>("UserName","XXX"),
            new KeyValuePair<string, string>("Password","XXX")
        };
        var loginContent = new FormUrlEncodedContent(loginParams);

        // 发送表单格式的登录请求
        HttpResponseMessage loginResponse = await client.PostAsync(loginUrl, loginContent);
        loginResponse.EnsureSuccessStatusCode(); // 确保登录成功,否则抛出异常
        #endregion

        #region 调用带授权的目标接口
        try
        {
            var ejecutarModeloUrl = "Pools/Management/EjecutarModeloProgramado?anyo=2023&mes=6"; 
            var modeloParams = new List<KeyValuePair<string, string>>()
            {
                new KeyValuePair<string, string>("id","4b4516a4-c0a5-493e-9bd1-08dbe9c20c33")
            };
            var modeloContent = new FormUrlEncodedContent(modeloParams);

            // 复用登录后的HttpClient发送请求
            HttpResponseMessage response = await client.PostAsync(ejecutarModeloUrl, modeloContent);
            response.EnsureSuccessStatusCode();
            
            // 可选:读取响应内容验证结果
            var responseContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseContent);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        #endregion
    }
}

若使用JWT认证场景的适配

如果你的系统用JWT Token认证,需从登录响应中提取Token并添加到请求头:

[Fact]
public async Task Modelo761_001()
{
    using (HttpClient client = new HttpClient())
    {
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        client.BaseAddress = new Uri("https://localhost:7117/");

        #region 登录获取JWT Token
        var loginUrl = "Login/Acceder";
        var loginParams = new 
        {
            UserName = "XXX",
            Password = "XXX"
        };

        HttpResponseMessage loginResponse = await client.PostAsJsonAsync(loginUrl, loginParams);
        loginResponse.EnsureSuccessStatusCode();
        
        // 从响应中解析Token(根据实际响应结构调整)
        var loginResult = await loginResponse.Content.ReadFromJsonAsync<dynamic>();
        string token = loginResult.token;

        // 添加Authorization头到HttpClient默认配置
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
        #endregion

        #region 调用目标接口
        try
        {
            var ejecutarModeloUrl = "Pools/Management/EjecutarModeloProgramado?anyo=2023&mes=6"; 
            // 若id是[FromBody]绑定,用JSON格式传递
            var modeloRequest = new { id = Guid.Parse("4b4516a4-c0a5-493e-9bd1-08dbe9c20c33") };
            
            HttpResponseMessage response = await client.PostAsJsonAsync(ejecutarModeloUrl, modeloRequest);
            response.EnsureSuccessStatusCode();
            
            var responseContent = await response.Content.ReadAsStringAsync();
            Console.WriteLine(responseContent);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
        #endregion
    }
}

额外注意事项

  • 确保登录用户的角色属于Admin, Alto, Medio中的某一个,否则会返回403 Forbidden。
  • 控制器方法中Mediator.Send(...).Result会阻塞线程,建议改为await Mediator.Send(...)避免死锁风险。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 10:57:46