ASP.NET 核心反序列化 IEnumerable<KeyValuePair<string,string>>> from Querystring



我正在 ASP.NET Core (3.0(中构建一个RESTful API。每个控制器都有一个用于搜索域对象的方法,该方法接受 List<string、string>> 作为如下所示的查询字符串参数:

    [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

我无法让控制器接受条件参数的值,条件列表始终为零长度。我尝试过对文本进行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的答案 如何在核心Web API中绑定Json查询字符串 asp.net 您不能以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()));
}

相关内容

最新更新