ASP.NET 核心反序列化 IEnumerable<KeyValuePair<string, string>>> 来自 Querystring
ASP.NET Core De-serialise IEnumerable<KeyValuePair<string, string>>> from Querystring
我正在 ASP.NET Core (3.0) 中构建 RESTful API。每个控制器都有一个用于搜索域对象的方法,该方法接受 List> 作为定义如下的查询字符串参数:
[HttpGet]
[ProducesResponseType(200)]
public ActionResult<IEnumerable<Service.Models.Asset>> Get(
[FromQuery(Name = "criteria")] List<KeyValuePair<string, string>> criteria,
[FromQuery] int? page = 0,
[FromQuery] int? size = null)
{
var dtoList = _assetService.SearchPaged(criteria, page, size);
return Ok(dtoList);
}
我将条件作为 JSON 序列化字符串传递,请求 URI 是:
http://api/asset?criteria=[{"key":"uprn","value":"h1"},{"key":"uprn","value":"h2"}]&page=0&size=100
我无法让控制器接受 criteria 参数的值,criteria 列表始终为零长度。我已经尝试 URL 对文本进行编码,没有任何区别。
如果我将参数更改为字符串,我可以使用 JsonConvert 成功反序列化参数(相同的 URI)。
[HttpGet]
[ProducesResponseType(200)]
public ActionResult<IEnumerable<Service.Models.Asset>> Get(
[FromQuery(Name = "criteria")] string criteriaString,
[FromQuery] int? page = 0,
[FromQuery] int? size = null)
{
var criteria = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, string>>>(criteriaString);
var dtoList = _assetService.SearchPaged(criteria, page, size);
return Ok(dtoList);
}
我不想对强类型参数对象使用模型绑定,因为我有一个通用参数转换器,它根据条件列表构建表达式以应用于我的 EF DbSet。这适用于许多不同的控制器。
这可能吗,还是我应该放弃并坚持使用我的字符串参数并自己管理反序列化?
基于对 SO 的回答,您无法以 json 格式绑定查询参数。您需要编写自己的模型绑定器以反序列化为 List<KeyValuePair<string, string>>
.
我猜,根据链接的答案,在没有进行测试的情况下,这样的事情应该可以完成工作:
创建模型活页夹实现:
public class KeyValueListModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var key = bindingContext.ModelName;
var jsonString = bindingContext.ValueProvider.GetValue(key).FirstValue;
MyCustomModel result = JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, string>>>(jsonString);
bindingContext.Result = ModelBindingResult.Success(result);
return Task.CompletedTask;
}
}
创建提供商:
public class KeyValueListModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(List<KeyValuePair<string, string>>))
return new KeyValueListModelBinder();
return null;
}
}
在启动时注册提供商:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(config => config.ModelBinderProviders.Insert(0, new KeyValueListModelBinderProvider()));
}
我正在 ASP.NET Core (3.0) 中构建 RESTful API。每个控制器都有一个用于搜索域对象的方法,该方法接受 List
[HttpGet]
[ProducesResponseType(200)]
public ActionResult<IEnumerable<Service.Models.Asset>> Get(
[FromQuery(Name = "criteria")] List<KeyValuePair<string, string>> criteria,
[FromQuery] int? page = 0,
[FromQuery] int? size = null)
{
var dtoList = _assetService.SearchPaged(criteria, page, size);
return Ok(dtoList);
}
我将条件作为 JSON 序列化字符串传递,请求 URI 是:
http://api/asset?criteria=[{"key":"uprn","value":"h1"},{"key":"uprn","value":"h2"}]&page=0&size=100
我无法让控制器接受 criteria 参数的值,criteria 列表始终为零长度。我已经尝试 URL 对文本进行编码,没有任何区别。
如果我将参数更改为字符串,我可以使用 JsonConvert 成功反序列化参数(相同的 URI)。
[HttpGet]
[ProducesResponseType(200)]
public ActionResult<IEnumerable<Service.Models.Asset>> Get(
[FromQuery(Name = "criteria")] string criteriaString,
[FromQuery] int? page = 0,
[FromQuery] int? size = null)
{
var criteria = Newtonsoft.Json.JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, string>>>(criteriaString);
var dtoList = _assetService.SearchPaged(criteria, page, size);
return Ok(dtoList);
}
我不想对强类型参数对象使用模型绑定,因为我有一个通用参数转换器,它根据条件列表构建表达式以应用于我的 EF DbSet。这适用于许多不同的控制器。
这可能吗,还是我应该放弃并坚持使用我的字符串参数并自己管理反序列化?
基于对 SO List<KeyValuePair<string, string>>
.
我猜,根据链接的答案,在没有进行测试的情况下,这样的事情应该可以完成工作:
创建模型活页夹实现:
public class KeyValueListModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
var key = bindingContext.ModelName;
var jsonString = bindingContext.ValueProvider.GetValue(key).FirstValue;
MyCustomModel result = JsonConvert.DeserializeObject<IEnumerable<KeyValuePair<string, string>>>(jsonString);
bindingContext.Result = ModelBindingResult.Success(result);
return Task.CompletedTask;
}
}
创建提供商:
public class KeyValueListModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context.Metadata.ModelType == typeof(List<KeyValuePair<string, string>>))
return new KeyValueListModelBinder();
return null;
}
}
在启动时注册提供商:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(config => config.ModelBinderProviders.Insert(0, new KeyValueListModelBinderProvider()));
}