使用WebClient调用接口时控制器string参数为空的问题排查
问题原因分析
这个问题我之前也碰到过,本质是ASP.NET Web API默认的JSON媒体格式化器对[FromBody]修饰的string类型参数有特殊的解析规则:
- 当你传入纯数字内容(比如"123")时,格式化器会把它当作JSON数字类型,自动隐式转换为string,所以参数能正常接收;
- 但当你传入带字母的内容(比如"A123")时,没有外层双引号的话,它不是合法的JSON字符串(JSON规范里字符串必须用双引号包裹),格式化器无法解析,就会导致参数为空,触发
ModelState.IsValid失败。
解决办法
下面给你几个可行的方案,按推荐程度排序:
方案1:将上传的字符串序列化为标准JSON格式
在调用UploadString之前,把你的字符串参数序列化为符合JSON规范的字符串(也就是给它加上外层双引号)。可以用Newtonsoft.Json(大部分.NET项目都自带)来做:
using Newtonsoft.Json; // ... using (WebClient client = new WebClient()) { client.BaseAddress = "http://localhost/"; client.Headers.Add("Content-Type", "application/json"); // 序列化为标准JSON字符串 string jsonParameter = JsonConvert.SerializeObject(stringParameter); client.UploadString("api/test", HttpMethod.Put.ToString(), jsonParameter); }
这样不管你的参数是纯数字还是带字母的内容,都会被格式化为合法的JSON字符串,Web API能正确解析。
方案2:用DTO类包装参数
创建一个简单的数据传输对象(DTO)来包装你的字符串参数,这样Web API会按照JSON对象的规则解析,避免单个string参数的解析问题:
第一步:定义DTO类
public class TestRequest { public string StringParameter { get; set; } }
第二步:修改控制器方法
[Route("api/test")] [HttpPut] public async Task<IHttpActionResult> Test([FromBody] TestRequest request) { if (!ModelState.IsValid || string.IsNullOrEmpty(request.StringParameter)) { return BadRequest(ModelState); } // 使用request.StringParameter进行后续处理 // ... }
第三步:修改WebClient调用代码
using Newtonsoft.Json; // ... using (WebClient client = new WebClient()) { client.BaseAddress = "http://localhost/"; client.Headers.Add("Content-Type", "application/json"); var requestObj = new { StringParameter = stringParameter }; string jsonParameter = JsonConvert.SerializeObject(requestObj); client.UploadString("api/test", HttpMethod.Put.ToString(), jsonParameter); }
这种方案更符合REST API的设计规范,后续如果需要增加参数也更方便扩展。
方案3:修改Web API的格式化器配置(不推荐)
如果你不想修改调用代码和控制器,可以配置Web API的JsonMediaTypeFormatter,让它支持解析不带引号的字符串,但这种方式不符合JSON规范,可能会带来其他潜在问题,所以只作为备选:
在WebApiConfig.cs的Register方法中添加:
config.Formatters.JsonFormatter.SerializerSettings.StringEscapeHandling = StringEscapeHandling.EscapeNonAscii; config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new StringConverter());
其中StringConverter是自定义的转换器:
public class StringConverter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(string); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.String) { return reader.Value.ToString(); } // 如果是其他类型(比如数字、布尔),转成string return reader.Value?.ToString(); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { writer.WriteValue(value.ToString()); } }
内容的提问来源于stack exchange,提问作者S. Cheng
相关产品推荐
相关产品推荐

