如何在.NET Web API中结合HttpParameterBinding使用默认参数值?

时间:2016-04-19 17:39:17

标签: c# asp.net-web-api

我在.NET Web API中使用参数绑定(参见下面的类)。在我的控制器操作中,我有三个参数,每个参数都是可选的(我在方法参数列表中有默认值)。但是,我无法弄清楚如何使我的HttpParameterBinding类忽略缺少的参数。如果我使用以下网址发出请求:

http://localhost:3208/api/fruit?query=gr&start=0&limit=10

......一切正常。但是如果我使用以下URL(没有limit参数):

http://localhost:3208/api/fruit?query=gr&start=0

...我收到以下错误:

The parameters dictionary contains a null entry for parameter 'limit' of non-nullable type 'System.Int32' for method 'System.Collections.Generic.IEnumerable`1[System.String] Get(System.String, Int32, Int32)' in 'WebAPITest.Controllers.Apis.TestController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

如果Descriptor.ParameterNameQuery String未显示,我尝试在HttpParameterBinder中设置一个值,但这会产生与上面相同的错误。如果在请求数据中找不到相应的值,我怎么能让HttpParameterBinding只将值传递给action方法?

我的Web API控制器如下所示:

[TestApi]
[RoutePrefix("api")]
public class TestController : ApiController
{
    [HttpGet]
    [Route("fruit")]
    public IEnumerable<string> Get(string query = "", int start = 0, int limit = Int32.MaxValue)
    {
        IEnumerable<string> fruits = new string[] {
            "Apple",
            "Banana",
            "Cherry",
            "Dragonfruit",
            "Elderberry",
            "Fig",
            "Grape",
            "Honeydew",
            "Watermelon"
        };

        return fruits.Where(f => f.ToLower().Contains(query.ToLower())).Skip(start).Take(limit);
    }
}

我的类型绑定器如下所示:

public class TestTypeBinder : HttpParameterBinding
{
    public TestTypeBinder(HttpParameterDescriptor descriptor) : base(descriptor) {}

    public override Task ExecuteBindingAsync(System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken)
    {
        object paramValue = ReadTypeFromRequest(actionContext);
        SetValue(actionContext, paramValue);
        TaskCompletionSource<AsyncVoid> tcs = new TaskCompletionSource<AsyncVoid>();
        tcs.SetResult(default(AsyncVoid));
        return tcs.Task;
    }

    private object ReadTypeFromRequest(HttpActionContext actionContext)
    {
        string dataValue = HttpUtility
            .ParseQueryString(actionContext.Request.RequestUri.Query)
            .Get(Descriptor.ParameterName);
        if (!string.IsNullOrEmpty(dataValue)) {
            if (Descriptor.ParameterType == typeof(int))
                return Convert.ToInt32(dataValue);
            else if (Descriptor.ParameterType == typeof(string))
                return dataValue;
        }
        return null;
    }
}

public struct AsyncVoid { }

最后,我的属性类看起来像这样:

[AttributeUsage(AttributeTargets.Class)]
public class TestApiAttribute : Attribute, IControllerConfiguration
{
    public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
    {
        Func<HttpParameterDescriptor, HttpParameterBinding> tvParameterBinder = param => new TestTypeBinder(param);

        controllerSettings.ParameterBindingRules.Insert(0, typeof(string), tvParameterBinder);
        controllerSettings.ParameterBindingRules.Insert(0, typeof(int), tvParameterBinder);
    }
}

1 个答案:

答案 0 :(得分:1)

在函数参数中使用nullable int(int?)而不仅仅是int类型。