简体   繁体   English

在.NET Web API中实现默认参数绑定行为

[英]Implement the default parameter binding behavior in .NET Web API

I am implementing a custom parameter binder that inherits HttpParameterBinding and will apply custom behavior to certain parameters. 我正在实现一个继承HttpParameterBinding的自定义参数绑定程序,并将自定义行为应用于某些参数。 In some cases I do not want to apply the custom behavior in which case I want to follow whatever Web API does by default. 在某些情况下,我不想应用自定义行为,在这种情况下,我想遵循Web API的默认设置。 This decision would be made in ExecuteBindingAsync. 该决定将在ExecuteBindingAsync中做出。 How do I implement this default behavior in ExecuteBindingAsync? 如何在ExecuteBindingAsync中实现此默认行为?

I believe this is typically done by simply not applying the parameter binding when registering the binding during startup (in other words the handler to the ParameterBindingRules collection would return null, allowing Web API to bind the default binding to the parameter). 我相信通常可以通过在启动过程中注册绑定不应用参数绑定来完成此操作(换句话说,ParameterBindingRules集合的处理程序将返回null,从而允许Web API将默认绑定绑定到参数)。 However in my case I need to decide whether to apply the binding at runtime , so I need to do this in ExecuteBindingAsync. 但是,就我而言,我需要确定是否在运行时应用绑定,因此我需要在ExecuteBindingAsync中执行此操作。

I am looking to do something like the following in my custom HttpParameterBinding class: 我正在我的自定义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()
        // ***************************************************************
    }
}

I've tried calling GetValue() but it always returns null. 我尝试调用GetValue(),但它始终返回null。 I assume there is some additional step that needs to be performed so that the base class (HttpParameterBinding) can create the value. 我假设需要执行一些附加步骤,以便基类(HttpParameterBinding)可以创建值。

My preference is to directly call whatever method within the .NET framework contains that default logic. 我的喜好是直接调用.NET框架中包含该默认逻辑的任何方法。 I would prefer not to have to duplicate that logic. 我希望不必重复这种逻辑。

I found a solution although I'm not sure if it is ideal. 我不确定是否是理想的解决方案。

I discovered the Mono code for DefaultActionValueBinder . 我发现了DefaultActionValueBinderMono代码 The GetParameterBinding method seems to contain the logic I'm looking for. GetParameterBinding方法似乎包含我正在寻找的逻辑。 However this method is protected so I can't call it directly. 但是此方法受保护,因此无法直接调用它。 (I could probably call the public GetBinding method but I'm worried that would be overkill.) So I would have to duplicate the logic from GetParameterBinding in my own class, plus some of the methods from the internal TypeHelper class which it references, which is why I don't think this solution is ideal. (我可能会调用公共GetBinding方法,但我担心这会太过分了。)因此,我必须在自己的类中复制GetParameterBinding的逻辑,再加上它引用的内部TypeHelper类的一些方法,这就是为什么我认为此解决方案不理想的原因。 I'm also not sure how well vetted the Mono implementation is so I'm concerned it could be buggy or not support all scenarios. 我也不确定Mono实现的审查情况如何,因此我担心它可能有问题或无法支持所有情况。

For future reference, this is the current Mono implementation of DefaultActionValueBinder.GetParameterBinding()... 供将来参考,这是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);
    }

...and the referenced methods from TypeHelper. ...以及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));
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM