ASP.NET Core - ModelBinder - 集合 - 卡在无限/无限循环中
ASP.NET Core - ModelBinder - Collection - stuck in endless / infinite loop
我遇到了自定义 ModelBinder(IModelBinder 实现)的问题。
这是我尝试从查询字符串绑定的模型。示例参数如下所示:
?Where.Name[eq]=Jakub
我尝试绑定的 class 是这样的:
[MetadataFilterBinder]
public class MetadataFilter
{
public string Term { get; set; }
public string Field { get; set; }
public FilterClause Clause { get; set; }
// Where.Name[eq]=Jakub
public static bool TryParse(string s, out MetadataFilter metadataFilter)
{
// commented out for brevity
}
}
我注释此模型活页夹的属性是:
public class MetadataFilterBinderAttribute : ModelBinderAttribute
{
public MetadataFilterBinderAttribute() : base(typeof(MetadataFilterBinder))
{
BindingSource = BindingSource.Query;
}
}
ModelBinder 实现:
public class MetadataFilterBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var modelName = bindingContext.ModelName;
var queryStringKeyName = new string(modelName.Where(char.IsLetter).ToArray());
var whereKeyValue = bindingContext.HttpContext.Request.Query
.FirstOrDefault(q => q.Key.StartsWith($"{queryStringKeyName}.", StringComparison.InvariantCultureIgnoreCase));
if (whereKeyValue.Key == string.Empty)
return Task.CompletedTask;
var valueProviderResult = bindingContext.ValueProvider.GetValue(whereKeyValue.Key);
if (valueProviderResult == ValueProviderResult.None)
return Task.CompletedTask;
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
if (string.IsNullOrEmpty(valueProviderResult.FirstValue))
return Task.CompletedTask;
var result = MetadataFilter.TryParse($"{whereKeyValue.Key}={whereKeyValue.Value}", out var metadataFilter);
if (result)
{
bindingContext.Result = ModelBindingResult.Success(metadataFilter);
}
else
{
bindingContext.ModelState.TryAddModelError(modelName, "Invalid metadata filter value.");
}
return Task.CompletedTask;
}
}
MetadataFilter class 驻留在应从 QueryString 绑定的以下模型中。
public class Metadata : IMetadataPaginable, IMetadataSortable, IMetadataFilterable
{
public MetadataPaging Paging { get; set; }
public MetadataSort Sort { get; set; }
public IReadOnlyCollection<MetadataFilter> Where { get; set; }
}
现在我的代码和 ModelBinder 得到正确执行,所有设置都正确。我设置 ModelBindingResult 并返回 Task.Completed。但是它陷入了无限循环,我不知道如何指示它应该停止。
BindModelAsync 方法被调用无限次,直到达到限制。 ModelName 保持递增 "Where[0]", "Where[1]", "哪里[2]", "哪里[n]".
如何让Binder知道我很好,我已经绑定了我需要的所有项目?
请注意,这不是
的副本
我通过将 ModelBinder 属性 放在模型 属性 上解决了这个问题。所以我的 Binder 不是试图单独绑定每个项目来触发无限循环,而是一次绑定整个集合,那时这个问题就消失了。
最终结果:
我遇到了自定义 ModelBinder(IModelBinder 实现)的问题。
这是我尝试从查询字符串绑定的模型。示例参数如下所示:
?Where.Name[eq]=Jakub
我尝试绑定的 class 是这样的:
[MetadataFilterBinder]
public class MetadataFilter
{
public string Term { get; set; }
public string Field { get; set; }
public FilterClause Clause { get; set; }
// Where.Name[eq]=Jakub
public static bool TryParse(string s, out MetadataFilter metadataFilter)
{
// commented out for brevity
}
}
我注释此模型活页夹的属性是:
public class MetadataFilterBinderAttribute : ModelBinderAttribute
{
public MetadataFilterBinderAttribute() : base(typeof(MetadataFilterBinder))
{
BindingSource = BindingSource.Query;
}
}
ModelBinder 实现:
public class MetadataFilterBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
throw new ArgumentNullException(nameof(bindingContext));
var modelName = bindingContext.ModelName;
var queryStringKeyName = new string(modelName.Where(char.IsLetter).ToArray());
var whereKeyValue = bindingContext.HttpContext.Request.Query
.FirstOrDefault(q => q.Key.StartsWith($"{queryStringKeyName}.", StringComparison.InvariantCultureIgnoreCase));
if (whereKeyValue.Key == string.Empty)
return Task.CompletedTask;
var valueProviderResult = bindingContext.ValueProvider.GetValue(whereKeyValue.Key);
if (valueProviderResult == ValueProviderResult.None)
return Task.CompletedTask;
bindingContext.ModelState.SetModelValue(modelName, valueProviderResult);
if (string.IsNullOrEmpty(valueProviderResult.FirstValue))
return Task.CompletedTask;
var result = MetadataFilter.TryParse($"{whereKeyValue.Key}={whereKeyValue.Value}", out var metadataFilter);
if (result)
{
bindingContext.Result = ModelBindingResult.Success(metadataFilter);
}
else
{
bindingContext.ModelState.TryAddModelError(modelName, "Invalid metadata filter value.");
}
return Task.CompletedTask;
}
}
MetadataFilter class 驻留在应从 QueryString 绑定的以下模型中。
public class Metadata : IMetadataPaginable, IMetadataSortable, IMetadataFilterable
{
public MetadataPaging Paging { get; set; }
public MetadataSort Sort { get; set; }
public IReadOnlyCollection<MetadataFilter> Where { get; set; }
}
现在我的代码和 ModelBinder 得到正确执行,所有设置都正确。我设置 ModelBindingResult 并返回 Task.Completed。但是它陷入了无限循环,我不知道如何指示它应该停止。
BindModelAsync 方法被调用无限次,直到达到限制。 ModelName 保持递增 "Where[0]", "Where[1]", "哪里[2]", "哪里[n]".
如何让Binder知道我很好,我已经绑定了我需要的所有项目?
请注意,这不是
我通过将 ModelBinder 属性 放在模型 属性 上解决了这个问题。所以我的 Binder 不是试图单独绑定每个项目来触发无限循环,而是一次绑定整个集合,那时这个问题就消失了。
最终结果: