在 .NET Web 中实现默认参数绑定行为 API
Implement the default parameter binding behavior in .NET Web API
我正在实现一个自定义参数绑定器,它继承了 HttpParameterBinding 并将自定义行为应用于某些参数。在某些情况下,我不想应用自定义行为,在这种情况下,我想遵循 Web API 默认情况下所做的任何事情。此决定将在 ExecuteBindingAsync 中做出。如何在 ExecuteBindingAsync 中实现此默认行为?
我认为这通常是通过在启动期间注册绑定时不应用参数绑定 (换句话说,ParameterBindingRules 集合的处理程序 return null,允许 Web API 将默认绑定绑定到参数)。但是,在我的情况下,我需要决定是否在运行时 应用绑定 ,因此我需要在 ExecuteBindingAsync.
中执行此操作
我希望在我的自定义 HttpParameterBinding 中执行类似以下操作 class:
public override async Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
if (IsCustomBindingNeeded()) {
// apply custom binding logic... call SetValue()... I'm good with this part
}
else {
// ***************************************************************
// This is where I want to use the default implementation.
// Maybe something like this (using a made up class name):
await return new WhateverDefaultParameterBinding().ExecuteBindingAsync(metadataProvider, actionContext, cancellationToken);
// ...or at least be able to call GetValue() and get the correct value and then I can call SetValue()
// ***************************************************************
}
}
我试过调用 GetValue() 但它始终 return 为空。我假设需要执行一些额外的步骤,以便基础 class (HttpParameterBinding) 可以创建值。
我的偏好是直接调用 .NET 框架中包含该默认逻辑的任何方法。我宁愿不必重复该逻辑。
我找到了一个解决方案,虽然我不确定它是否理想。
我发现了 Mono code for DefaultActionValueBinder。 GetParameterBinding 方法似乎包含我正在寻找的逻辑。但是这个方法是受保护的,所以我不能直接调用它。 (我可能会调用 public GetBinding 方法,但我担心这会有点矫枉过正。)所以我必须在我自己的 class 中复制 GetParameterBinding 的逻辑,加上一些来自它引用的 internal TypeHelper class ,这就是为什么我不认为这个解决方案是理想的。我也不确定 Mono 实现的审查情况如何,所以我担心它可能有问题或不支持所有场景。
为了将来参考,这是 DefaultActionValueBinder.GetParameterBinding()...
的当前 Mono 实现
protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter)
{
// Attribute has the highest precedence
// Presence of a model binder attribute overrides.
ParameterBindingAttribute attr = parameter.ParameterBinderAttribute;
if (attr != null)
{
return attr.GetBinding(parameter);
}
// No attribute, so lookup in global map.
ParameterBindingRulesCollection pb = parameter.Configuration.ParameterBindingRules;
if (pb != null)
{
HttpParameterBinding binding = pb.LookupBinding(parameter);
if (binding != null)
{
return binding;
}
}
// Not explicitly specified in global map or attribute.
// Use a default policy to determine it. These are catch-all policies.
Type type = parameter.ParameterType;
if (TypeHelper.IsSimpleUnderlyingType(type) || TypeHelper.HasStringConverter(type))
{
// For simple types, the default is to look in URI. Exactly as if the parameter had a [FromUri] attribute.
return parameter.BindWithAttribute(new FromUriAttribute());
}
// Fallback. Must be a complex type. Default is to look in body. Exactly as if this type had a [FromBody] attribute.
attr = new FromBodyAttribute();
return attr.GetBinding(parameter);
}
...以及 TypeHelper 中引用的方法。
internal static bool IsSimpleType(Type type)
{
return type.IsPrimitive ||
type.Equals(typeof(string)) ||
type.Equals(typeof(DateTime)) ||
type.Equals(typeof(Decimal)) ||
type.Equals(typeof(Guid)) ||
type.Equals(typeof(DateTimeOffset)) ||
type.Equals(typeof(TimeSpan));
}
internal static bool IsSimpleUnderlyingType(Type type)
{
Type underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType != null)
{
type = underlyingType;
}
return TypeHelper.IsSimpleType(type);
}
internal static bool HasStringConverter(Type type)
{
return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string));
}
我正在实现一个自定义参数绑定器,它继承了 HttpParameterBinding 并将自定义行为应用于某些参数。在某些情况下,我不想应用自定义行为,在这种情况下,我想遵循 Web API 默认情况下所做的任何事情。此决定将在 ExecuteBindingAsync 中做出。如何在 ExecuteBindingAsync 中实现此默认行为?
我认为这通常是通过在启动期间注册绑定时不应用参数绑定 (换句话说,ParameterBindingRules 集合的处理程序 return null,允许 Web API 将默认绑定绑定到参数)。但是,在我的情况下,我需要决定是否在运行时 应用绑定 ,因此我需要在 ExecuteBindingAsync.
中执行此操作我希望在我的自定义 HttpParameterBinding 中执行类似以下操作 class:
public override async Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
if (IsCustomBindingNeeded()) {
// apply custom binding logic... call SetValue()... I'm good with this part
}
else {
// ***************************************************************
// This is where I want to use the default implementation.
// Maybe something like this (using a made up class name):
await return new WhateverDefaultParameterBinding().ExecuteBindingAsync(metadataProvider, actionContext, cancellationToken);
// ...or at least be able to call GetValue() and get the correct value and then I can call SetValue()
// ***************************************************************
}
}
我试过调用 GetValue() 但它始终 return 为空。我假设需要执行一些额外的步骤,以便基础 class (HttpParameterBinding) 可以创建值。
我的偏好是直接调用 .NET 框架中包含该默认逻辑的任何方法。我宁愿不必重复该逻辑。
我找到了一个解决方案,虽然我不确定它是否理想。
我发现了 Mono code for DefaultActionValueBinder。 GetParameterBinding 方法似乎包含我正在寻找的逻辑。但是这个方法是受保护的,所以我不能直接调用它。 (我可能会调用 public GetBinding 方法,但我担心这会有点矫枉过正。)所以我必须在我自己的 class 中复制 GetParameterBinding 的逻辑,加上一些来自它引用的 internal TypeHelper class ,这就是为什么我不认为这个解决方案是理想的。我也不确定 Mono 实现的审查情况如何,所以我担心它可能有问题或不支持所有场景。
为了将来参考,这是 DefaultActionValueBinder.GetParameterBinding()...
的当前 Mono 实现 protected virtual HttpParameterBinding GetParameterBinding(HttpParameterDescriptor parameter)
{
// Attribute has the highest precedence
// Presence of a model binder attribute overrides.
ParameterBindingAttribute attr = parameter.ParameterBinderAttribute;
if (attr != null)
{
return attr.GetBinding(parameter);
}
// No attribute, so lookup in global map.
ParameterBindingRulesCollection pb = parameter.Configuration.ParameterBindingRules;
if (pb != null)
{
HttpParameterBinding binding = pb.LookupBinding(parameter);
if (binding != null)
{
return binding;
}
}
// Not explicitly specified in global map or attribute.
// Use a default policy to determine it. These are catch-all policies.
Type type = parameter.ParameterType;
if (TypeHelper.IsSimpleUnderlyingType(type) || TypeHelper.HasStringConverter(type))
{
// For simple types, the default is to look in URI. Exactly as if the parameter had a [FromUri] attribute.
return parameter.BindWithAttribute(new FromUriAttribute());
}
// Fallback. Must be a complex type. Default is to look in body. Exactly as if this type had a [FromBody] attribute.
attr = new FromBodyAttribute();
return attr.GetBinding(parameter);
}
...以及 TypeHelper 中引用的方法。
internal static bool IsSimpleType(Type type)
{
return type.IsPrimitive ||
type.Equals(typeof(string)) ||
type.Equals(typeof(DateTime)) ||
type.Equals(typeof(Decimal)) ||
type.Equals(typeof(Guid)) ||
type.Equals(typeof(DateTimeOffset)) ||
type.Equals(typeof(TimeSpan));
}
internal static bool IsSimpleUnderlyingType(Type type)
{
Type underlyingType = Nullable.GetUnderlyingType(type);
if (underlyingType != null)
{
type = underlyingType;
}
return TypeHelper.IsSimpleType(type);
}
internal static bool HasStringConverter(Type type)
{
return TypeDescriptor.GetConverter(type).CanConvertFrom(typeof(string));
}