简体   繁体   中英

How to use optional value type (i.e. struct) parameters without using Nullable<T> in WebApi 2?

I want action method with optional parameters of value type, but without using Nullable something like

    public string Test2([FromUri] MyKey x = default)
    { ... }

When i call this api with /test2?something=42, it is ok, but when I miss any parameter, it throws error

The parameters dictionary contains a null entry for parameter 'x' of non-nullable type 'WebApiTst.Controllers.MyKey' for method 'System.String Test2(WebApiTst.Controllers.MyKey)' in 'WebApiTst.Controllers.TestController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.

It is strange, that naming that parameter (with same name) makes things even worse...

I am using WebApi 2 with just config.MapHttpAttributeRoutes()

This is my test controller

public class TestController : ApiController
{
    // OK - https://localhost:44302/test2?something=22
    // NOK - https://localhost:44302/test2
    [Route("test2")]
    [HttpGet]
    public string Test2([FromUri] MyKey x = default)
    {
        return "TEST2:" + x;
    }

    // NOK - https://localhost:44302/test3?something=22
    // NOK - https://localhost:44302/test3
    [Route("test3")]
    [HttpGet]
    public string Test3([FromUri(Name = "x")] MyKey x = default)
    {
        return "TEST3:" + x;
    }
}

public struct MyKey
{
    public static MyKey Empty { get; } = new MyKey();
    public int ID { get; set; }
    public override string ToString()
    {
        return $"[ID={ID}]";
    }
}

What is causing this? How to use value-type optional parameters without using Nullable ?

[Edited:] I am using ModelBinder, which will deserialize MyKey from string. I also tried same example in Asp.net core webapi and it works.

It is a very bad style to make API with query string. MUCH BETTER way is to initiate your MyKey class on creation by default values:

public class MyKey
{
public string X {get; set;}
public Property1 {get; set;}
public Property2 {get; set;}

public MyKey()
{
X = "default";
Property1=default1;
Property2=default2;
.....
}

and then you can use the action like this

 [Route("Test2/{X?}")]
public string Test2(MyKey myKey )
{
return "TEST2: " + myKey.X;
}

if X is null, myKey.X will still have a default value it got on creation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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