【问题标题】:Implement the default parameter binding behavior in .NET Web API在 .NET Web API 中实现默认参数绑定行为
【发布时间】:2018-06-01 17:16:25
【问题描述】:

我正在实现一个自定义参数绑定器,它继承 HttpParameterBinding 并将自定义行为应用于某些参数。在某些情况下,我不想应用自定义行为,在这种情况下,我想遵循默认情况下 Web API 所做的任何事情。这个决定将在 ExecuteBindingAsync 中做出。如何在 ExecuteBindingAsync 中实现此默认行为?

我相信这通常是通过简单地不应用参数绑定来完成的绑定到参数)。但是在我的情况下,我需要决定是否在运行时应用绑定,所以我需要在 ExecuteBindingAsync 中执行此操作。

我希望在我的自定义 HttpParameterBinding 类中执行以下操作:

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(),但它总是返回 null。我假设需要执行一些额外的步骤,以便基类 (HttpParameterBinding) 可以创建值。

我的偏好是直接调用 .NET 框架中包含该默认逻辑的任何方法。我宁愿不必重复该逻辑。

【问题讨论】:

    标签: .net asp.net-web-api asp.net-web-api2 parameterbinding


    【解决方案1】:

    我找到了一个解决方案,虽然我不确定它是否理想。

    我发现了Mono code for DefaultActionValueBinder。 GetParameterBinding 方法似乎包含我正在寻找的逻辑。但是这个方法是受保护的,所以我不能直接调用它。 (我可能会调用公共 GetBinding 方法,但我担心这会有点过头了。)所以我必须在我自己的类中复制 GetParameterBinding 的逻辑,以及它引用的内部 TypeHelper 类中的一些方法,其中这就是为什么我不认为这个解决方案是理想的。我也不确定 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));
        }
    

    【讨论】:

      猜你喜欢
      • 2021-11-08
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      • 1970-01-01
      • 2016-12-31
      • 2020-03-07
      • 2012-04-24
      • 1970-01-01
      相关资源
      最近更新 更多