C# 如何在不使用Nullable的情况下使用可选值类型(即struct)参数<;T>;在WebApi 2中?

C# 如何在不使用Nullable的情况下使用可选值类型(即struct)参数<;T>;在WebApi 2中?,c#,asp.net-web-api-routing,C#,Asp.net Web Api Routing,我希望action方法具有值类型的可选参数,但不使用Nullable 差不多 public string Test2([FromUri] MyKey x = default) { ... } 当我用/test2?something=42调用这个api时,它是正常的,但当我错过任何参数时,它就会抛出错误 参数字典包含“WebApiTst.Controllers.TestController”中“System.String Test2(WebApiTst.Controllers.M

我希望action方法具有值类型的可选参数,但不使用Nullable 差不多

    public string Test2([FromUri] MyKey x = default)
    { ... }
当我用/test2?something=42调用这个api时,它是正常的,但当我错过任何参数时,它就会抛出错误

参数字典包含“WebApiTst.Controllers.TestController”中“System.String Test2(WebApiTst.Controllers.MyKey)”方法的不可为null类型“WebApiTst.Controllers.MyKey”的参数“x”的null条目。可选参数必须是引用类型、可为空类型或声明为可选参数。

奇怪的是,命名那个参数(同名)会让事情变得更糟

我只是在config.maphttpAttribute()中使用WebApi 2

这是我的测试控制器

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}]";
    }
}
这是什么原因造成的?如何在不使用Nullable的情况下使用值类型可选参数

[编辑:]我正在使用ModelBinder,它将从字符串反序列化MyKey。
我还在Asp.net core webapi中尝试了相同的示例,它很有效。

使用查询字符串制作API是一种非常糟糕的风格。更好的方法是在创建默认值时启动MyKey类:

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

public MyKey()
{
X = "default";
Property1=default1;
Property2=default2;
.....
}
然后你可以用这样的动作

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

如果X为null,则myKey.X仍将具有创建时获得的默认值。

很抱歉,但是什么公共静态myKey为空{get;}=new myKey();手段和目的?我从没见过这样的事。要使结构为空,只需标记public int?ID{get;set;}请查看我最近的更新。请询问您的答案。但是你没有回答我的问题,我不能同意你的看法。如果我想要数据“查询”方面的api,例如GET/api/library/books,带有可选的选择参数,如category、author、title,那么仅仅使用GET/api/library/books/-/-/-/Crowford这样的东西是非常难看的。更好的语义类似于GET/api/library/books?author=Crowford。我的一个参数类似于GPS坐标,我想在GET/api/library/books?location=[64,92]表单中使用它们,所以我使用struct和custom ModelBinder。谢谢您的提问。在本例中,我更喜欢/api/lilbrary/gpslocation/64/92。在您之前的示例中,我将使用api/library/location/Crowford。您可以创建如下api/library/{type}/{param1?}/{param2?}的通用路由。或者你可以做几次具体的溃败,这没什么大不了的。我对API有一些很好的经验,我更喜欢这种语法,因为它更易于使用和测试。你可以检查我的另一个答案。我明白你的意思了…/地点/。。。更好,但我想为api提供这些参数的任意组合,所以可选的命名参数似乎比仅定位参数提供更好的语义。在我的示例中,我希望也可以是/api/library/book?author=Crowford&location=[1,2]等等。如果有15个这样的参数,我们就不清楚了,如果它使用位置参数,比如/api/library/book/-/-/-/-/-/-/-/-/-/[2:4]/-/42/-/-/-/-/scifi,而不是/api/library/book?location=[2,4]?categoryId=42&genre=scifi,那么复杂的url是绝对不会手工创建的。在本例中,我将创建一个包含所有参数的大ViewModel对象,并将其发送到请求正文中的API。在这种情况下,您的api操作将具有以下语法[Route(“~/api/library”)]public IActionResult GetData([FromBody]MyViewModel viewModel){..}