首页 > 解决方案 > 如何通过 Refit 和其他来源在 Web API 应用程序中将字典作为查询参数传递?

问题描述

我在将 Dictionary 作为父对象的一部分作为查询参数传递时遇到了一点问题。

所以,我有一个获取 FormulationParameters 变量的方法。

public async ValueTask<IActionResult> Get([FromQuery] FormulationParameters formulationParameters)
{
     return Ok(await _service.Get(formulationParameters));
}

FormulationParameters 类如下所示:

public class FormulationParameters
{
   //other simple properties, e.g. string, int
        
   public Dictionary<string, string> Substitute { get; set; }
}

当我使用 Postman 传递这些参数时,我像这样填写了“查询参数”表单,一切正常:

Substitute字典中,我得到了 Key 等于"FirstValue"且其值为10的记录。

但是当我尝试通过 Refit 为我的 API 编写一些测试时,我发现这并没有像我预期的那样工作。

所以,我在 Refit 接口中有一个方法:

[Get("/api/path")]
Task<HttpResponseMessage> GetFormulations([Query] FormulationParameters parameters]

我在代码中填写了 FormulationParameters 的所有属性。当我调试我的测试时,我看到在 API 方法(上面定义)中,除了这个 Substitute 字典之外, formationParameters变量的所有属性都被填充了。

我在互联网上寻找这个问题并找到了一些解决方案。我都试过了,但对我没有用。

首先,我尝试为此属性使用[JsonDataExtension]属性。正如我所读到的,这意味着如果您将此属性用于某些属性,则 Request 中没有匹配类成员的所有参数都将写入指定的集合中。因此,我将Dictionary<string, string>更改为Dictionary<string, object>。此外,我更改了通过 Refit 方法发送数据的方式:我将 Substitute 从主类中移出并将其作为单独的参数发送,因此查询字符串如下所示:

?Codes=Code1,Code2&Type=Type&Language=en&FirstValue=1&SecondValue=10

但是,没有任何效果,Substitute仍然没有被填充。

另外,我尝试为这个属性编写一个自定义转换器,但没有效果,它甚至在请求到来时都没有调用。

起作用的一件事是动作过滤器。我在讨论相同问题的 StackOverflow 帖子中找到了这个解决方案。此过滤器的方法如下所示:

        public override void OnActionExecuting(ActionExecutingContext context)
        {
            var notMatchedProperties = new Dictionary<string, string>();
    
            // because in ActionArguments there is only one variable - formulationParameters
            var mainVariableKey = context.ActionArguments.First().Key;
            
            // the content of FormulationParameters class
            var innerParts = context.ActionArguments.First().Value as FormulationParameters;
            
            // conversion from class to dictionary
            // the names of the properties are the keys, and their values are values in the dictionary
            var classAsDictionary = ClassToDictionaryConverter.Convert(innerParts);
            var keys = classAsDictionary.Keys;
    
            
            foreach (var kvp in context.HttpContext.Request.Query)
            {
                if (!keys.Contains(kvp.Key, StringComparer.InvariantCultureIgnoreCase))
                {
                    notMatchedProperties.Add(kvp.Key, kvp.Value);
                }
            }
    
            // fill this dictionary with no matched properties from input
            innerParts!.Substitute = notMatchedProperties;
            
            // rewrite the existing value with the new value
            context.ActionArguments[mainVariableKey] = innerParts;
            base.OnActionExecuting(context);
        }

这也不好,因为当我尝试通过 Postman 传递一些参数时它无法正常工作。例如:Codes[0]=1&Codes[1]=2,但是当我这样写 Codes=1&Codes=2 时它工作正常 - 它被映射到 Codes : {1, 2} 并且它被认为是一键Codes。此外,它不是通用的,它看起来像是一种解决方法。

我不知道是否可以使用此操作过滤器,或者我还没有尝试过其他解决方案(但我不知道它)。如果我可以使用这个过滤器,我和我的用户总是需要记住如何正确传递这些参数。因此,我正在寻找一种更通用的方法来在请求来自不同来源(如 Refit、Swagger、Postman)时解析这些参数。

PS 我正在使用 .NET 5,我的应用程序是 Web API 类型

标签: c#dictionaryrefit

解决方案


推荐阅读