如何在Get方法中获取Post提交的基金名称以切换数据库连接
问题描述
数据库连接需根据用户所属基金确定:
- 普通用户通过Claims中的
caisse值获取对应ConnectionString - 管理员可选择目标基金,通过Post提交基金名称到API,需要在Get方法中获取该名称,匹配对应ConnectionString执行SQL查询
当前无法实现Post到Get方法间的参数传递。
现有配置(appsettings.json)
{ "ConnectionStrings": { "DefaultConnection": "Server=.\\SQLEXPRESS; Database=Ctisn; Trusted_Connection=True; MultipleActiveResultSets=True;", "MECLESINE": "Server=myserver; Database=aicha_meclesine; User ID=***; Password=***;", "FONEES": "Server=myserver; Database=aicha_fonees; User ID=***; Password=***;", "MECFP": "Server=myserver; Database=aaicha_mecfp; User ID=***; Password=***;", "MECCT": "Server=myserver; Database=aicha_ct; User ID=***; Password=***;", "JSR": "Server=myserver; Database=aicha_jsr; User ID=***; Password=***;" } }
现有控制器代码
[Authorize] [Route("api/[controller]")] [ApiController] public class TopClientsController : ControllerBase { private readonly IConfiguration _configuration; public TopClientsController(IConfiguration configuration) { _configuration = configuration; } [HttpPost("{AdminValue}")] public JsonResult Post(string AdminValue) { return new JsonResult(new { data = AdminValue }); } [HttpGet] public JsonResult Get() { string query = @" -------------------My sql requet----------------- "; var iden; if (User.IsInRole("Administrator")) { // iden = The result of the post methode ; } else { iden=((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst("caisse").Value; } DataTable table = new DataTable(); string sqlDataSource = _configuration.GetConnectionString($"{iden}"); MySqlDataReader myReader; using (MySqlConnection mycon = new MySqlConnection(sqlDataSource)) { mycon.Open(); using (MySqlCommand myCommand = new MySqlCommand(query, mycon)) { myReader = myCommand.ExecuteReader(); table.Load(myReader); myReader.Close(); mycon.Close(); } } return new JsonResult(table); } }
解决方案
API本身是无状态的,Post和Get是两个独立请求,无法直接传递内存中的值。以下是几种可行的实现方式:
方式1:修改Get接口,通过查询参数传递基金名称
直接调整Get方法,允许管理员传入基金名称作为查询参数,普通用户仍使用Claims值,这是最符合RESTful设计的方案:
[HttpGet] public JsonResult Get([FromQuery] string? fundName = null) { string query = @" -------------------My sql requet----------------- "; string iden; if (User.IsInRole("Administrator")) { // 管理员需指定基金名称,同时校验合法性 if (string.IsNullOrEmpty(fundName)) { return new JsonResult("管理员需指定基金名称") { StatusCode = 400 }; } if (!_configuration.GetSection("ConnectionStrings").GetChildren().Any(c => c.Key == fundName)) { return new JsonResult("无效的基金名称") { StatusCode = 400 }; } iden = fundName; } else { iden = ((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst("caisse").Value; } // 后续数据库操作逻辑保持不变 DataTable table = new DataTable(); string sqlDataSource = _configuration.GetConnectionString($"{iden}"); MySqlDataReader myReader; using (MySqlConnection mycon = new MySqlConnection(sqlDataSource)) { mycon.Open(); using (MySqlCommand myCommand = new MySqlCommand(query, mycon)) { myReader = myCommand.ExecuteReader(); table.Load(myReader); myReader.Close(); mycon.Close(); } } return new JsonResult(table); }
管理员直接通过GET /api/TopClients?fundName=MECLESINE请求数据即可,原Post方法可删除。
方式2:使用Cookie存储管理员选择的基金名称
若必须保留Post提交逻辑,可在Post方法中将基金名称写入Cookie,Get方法读取该Cookie:
[HttpPost("{AdminValue}")] public JsonResult Post(string AdminValue) { // 先校验基金名称合法性 if (!_configuration.GetSection("ConnectionStrings").GetChildren().Any(c => c.Key == AdminValue)) { return new JsonResult("无效的基金名称") { StatusCode = 400 }; } // 设置Cookie,配置安全属性 Response.Cookies.Append("SelectedFund", AdminValue, new CookieOptions { HttpOnly = true, Secure = true, SameSite = SameSiteMode.Strict, Expires = DateTimeOffset.UtcNow.AddHours(1) }); return new JsonResult(new { data = AdminValue }); } [HttpGet] public JsonResult Get() { string query = @" -------------------My sql requet----------------- "; string iden; if (User.IsInRole("Administrator")) { // 从Cookie读取基金名称 if (!Request.Cookies.TryGetValue("SelectedFund", out string? fundName) || string.IsNullOrEmpty(fundName)) { return new JsonResult("管理员需先选择基金") { StatusCode = 400 }; } iden = fundName; } else { iden = ((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst("caisse").Value; } // 后续数据库操作逻辑保持不变 DataTable table = new DataTable(); string sqlDataSource = _configuration.GetConnectionString($"{iden}"); MySqlDataReader myReader; using (MySqlConnection mycon = new MySqlConnection(sqlDataSource)) { mycon.Open(); using (MySqlCommand myCommand = new MySqlCommand(query, mycon)) { myReader = myCommand.ExecuteReader(); table.Load(myReader); myReader.Close(); mycon.Close(); } } return new JsonResult(table); }
Cookie与用户会话绑定,单用户场景下不会互相干扰,适合单机部署的系统。
方式3:使用分布式缓存存储管理员选择的基金
若系统为多服务器部署,Cookie无法跨节点共享,可使用Redis等分布式缓存:
首先注入IDistributedCache:
private readonly IConfiguration _configuration; private readonly IDistributedCache _distributedCache; public TopClientsController(IConfiguration configuration, IDistributedCache distributedCache) { _configuration = configuration; _distributedCache = distributedCache; }
然后修改Post和Get方法:
[HttpPost("{AdminValue}")] public async Task<JsonResult> Post(string AdminValue) { if (!_configuration.GetSection("ConnectionStrings").GetChildren().Any(c => c.Key == AdminValue)) { return new JsonResult("无效的基金名称") { StatusCode = 400 }; } // 用用户ID作为缓存键,确保每个管理员的选择独立 string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? throw new UnauthorizedAccessException(); await _distributedCache.SetStringAsync($"AdminSelectedFund:{userId}", AdminValue, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1) }); return new JsonResult(new { data = AdminValue }); } [HttpGet] public async Task<JsonResult> Get() { string query = @" -------------------My sql requet----------------- "; string iden; if (User.IsInRole("Administrator")) { string userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value ?? throw new UnauthorizedAccessException(); string? fundName = await _distributedCache.GetStringAsync($"AdminSelectedFund:{userId}"); if (string.IsNullOrEmpty(fundName)) { return new JsonResult("管理员需先选择基金") { StatusCode = 400 }; } iden = fundName; } else { iden = ((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst("caisse").Value; } // 后续数据库操作逻辑保持不变 DataTable table = new DataTable(); string sqlDataSource = _configuration.GetConnectionString($"{iden}"); MySqlDataReader myReader; using (MySqlConnection mycon = new MySqlConnection(sqlDataSource)) { mycon.Open(); using (MySqlCommand myCommand = new MySqlCommand(query, mycon)) { myReader = myCommand.ExecuteReader(); table.Load(myReader); myReader.Close(); mycon.Close(); } } return new JsonResult(table); }
这种方式适合分布式部署的系统,但需要提前配置好分布式缓存服务。
内容的提问来源于stack exchange,提问作者Mouhamed Diop
相关产品推荐
相关产品推荐

