【问题标题】:ASP.NET Core De-serialise IEnumerable<KeyValuePair<string, string>>> from QuerystringASP.NET Core 从 Querystring 反序列化 IEnumerable<KeyValuePair<string, string>>>
【发布时间】:2019-11-22 15:06:06
【问题描述】:

我正在 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

我无法让控制器接受条件参数的值,条件 列表的长度始终为零。我已经尝试过对文本进行 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。这适用于许多不同的控制器。

这可能吗,还是我应该放弃并坚持使用我的字符串参数并自己管理反序列化?

【问题讨论】:

    标签: c# asp.net-core json-deserialization


    【解决方案1】:

    基于 SO How to bind Json Query string in asp.net core web api 上的这个答案,您不能以 json 格式绑定查询参数。您需要编写自己的模型绑定器以反序列化为List&lt;KeyValuePair&lt;string, string&gt;&gt;。

    如果没有进行测试,我想,根据链接的答案,这样的事情应该可以完成:

    创建模型绑定器实现:

    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()));
    }
    

    【讨论】:

    • 谢谢。我在这里阅读了大量有关模型绑定的内容,但设法错过了您链接的问题。自定义模型绑定器看起来不错,我会尝试一下。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-06
    • 1970-01-01
    相关资源
    最近更新 更多