首页 > 解决方案 > 检测自定义模型绑定中的可用键

问题描述

当前使用 ASP.NET Core 2.2.0

我有一个控制器操作 (POST),它需要支持具有多个任意命名的输入参数的客户端请求(我事先不知道有多少键或它们的名称)。我的想法是这些参数应该绑定到集合参数,例如Dictionary<string,object>控制器操作中的 a ,但如果有其他方法,我会很灵活。

我正在尝试自定义模型绑定来执行此操作。绑定上下文中值提供者的可用公共接口似乎要求我知道键名才能获取值,例如

valueProviderResult = bindingContext.ValueProvider.GetValue("keyName");

当然,这无助于满足规定的要求。

在调试时,我发现密钥就在那里,隐藏在价值提供者的私人部分中,尽管我还没有找到一种优质的方法来利用它。

bindingContext.ValueProvider[1]._values.Keys
//_values is private
  1. 是否有一些我错过的现有活页夹可以做到这一点?
  2. 是否有一些公开的方式来访问密钥?
  3. 是否有某些原因将键完全隐藏在设计中?

标签: c#asp.net-coremodel-binding

解决方案


我确实为此找到了适当的解决方案。对于其他对发现输入参数名称感兴趣的人,我的关键是注意(在调试时)虽然bindingContext.ValueProvider声明为IValueProvider,但它在运行时实现的类型(至少在我的示例中)是CompositeValueProvider,这确实添加了一个有用的方法。(这方面的 MS 文档相对没有帮助,我的搜索没有找到一个有启发性的例子)

对于一些支持背景,CompositeValueProvider支持名称中带有前缀的输入参数的概念,尽管您不需要使用前缀来实现我的既定目标。支持两个版本的语法,prefix.name并且prefix[name].

所以我做了如下的事情:

using Microsoft.AspNetCore.Mvc.ModelBinding;
using System.Collections.Generic;
using System.Threading.Tasks;

// in my custom binder class derived from IModelBinder
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
  var compositeValueProvider = bindingContext.ValueProvider as CompositeValueProvider;

  // For unprefixed names:
  // This also returns prefixes of prefixed names so you can recursively find the names
  var callerProvidedKeys = compositeValueProvider.GetKeysFromPrefix(""); 

  // or for a known prefix name
  //var callerProvidedKeys = compositeValueProvider.GetKeysFromPrefix(somePrefix);

  foreach (KeyValuePair<string, string> kvp in callerProvidedKeys) {
    // You can but don't have to access values through `CompositeValueProvider`
    var valueProviderResult = bindingContext.ValueProvider.GetValue(kvp.Value);
    ...
  }

  ...
}

GetKeysFromPrefix返回IDictionary<string,string>其中键仅是名称部分,值是包含前缀的完整参数名称。然后可以使用全名来提取参数值。


推荐阅读