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

Jan*_*ane 6 c# dictionary refit

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

因此,我有一个获取 FormulationParameters 变量的方法。

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

FormulationParameters 类如下所示:

public class FormulationParameters
{
   //other simple properties, e.g. string, int
        
   public Dictionary<string, string> Substitute { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我将一个键作为Substitute[FirstValue]传递,其值作为10

Substitute字典中,我得到一条记录,其中 Key 等于“FirstValue”,其 Value 为10

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

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

[Get("/api/path")]
Task<HttpResponseMessage> GetFormulations([Query] FormulationParameters parameters]
Run Code Online (Sandbox Code Playgroud)

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

我在网上寻找这个问题并找到了一些解决方案。我尝试了所有这些,但对我不起作用。

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

?Codes=Code1,Code2&Type=Type&Language=en&FirstValue=1&SecondValue=10
Run Code Online (Sandbox Code Playgroud)

但是,没有效果,替补还是没有补上。

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

唯一有效的是动作过滤器。我在 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);
        }
Run Code Online (Sandbox Code Playgroud)

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

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

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