C# WebApi属性路由-将路由参数绑定到GETs的对象

C# WebApi属性路由-将路由参数绑定到GETs的对象,c#,asp.net-web-api,asp.net-web-api-routing,C#,Asp.net Web Api,Asp.net Web Api Routing,目前,对于每个GET,我都必须根据路由参数手动创建一个查询对象 是否可以直接绑定到查询对象 因此,不是: [Route("{id:int}")] public Book Get(int id) { var query = new GetBookByIdQuery { Id = id }; // execute query and return result } 我可以这样做: [Route("{id:int}")] public Book Get(G

目前,对于每个GET,我都必须根据路由参数手动创建一个查询对象

是否可以直接绑定到查询对象

因此,不是:

[Route("{id:int}")]
public Book Get(int id) {

    var query = new GetBookByIdQuery {
        Id = id
    };

    // execute query and return result
}
我可以这样做:

[Route("{id:int}")]
public Book Get(GetBookByIdQuery query) {
    // execute query and return result
}
其中
GetBookByIdQuery
看起来像:

public class GetBookByIdQuery {
    public int Id { get; set;}
}
public class ValuesController : ApiController
{
    // GET api/values/5
    [Route( "api/values/{id}" )]
    public string Get([CustomParameterBinding] string id )
    {
        return id;
    }       
}

您可以将该类用作参数,但由于id不再是方法定义中的参数,因此它不能包含在路由中

public class LibraryController : ApiController
{
    [HttpGet]  
    public Book Get(GetBookByIdQuery query)
    {
        // Process query... & return
    }
}
您可以通过以下链接调用它:

http://localhost:54556/api/Library?id=12

答案是定义您自己的
HttpParameterBinding

这是我举的一个例子

首先,我创建了我的
CustomParameterBinding

public class CustomParameterBinding : HttpParameterBinding
{
    public CustomParameterBinding( HttpParameterDescriptor p ) : base( p ) { }

    public override System.Threading.Tasks.Task ExecuteBindingAsync( System.Web.Http.Metadata.ModelMetadataProvider metadataProvider, HttpActionContext actionContext, System.Threading.CancellationToken cancellationToken )
    {

        // Do your custom logic here
        var id = int.Parse( actionContext.Request.RequestUri.Segments.Last() );

        // Set transformed value
        SetValue( actionContext, string.Format( "This is formatted ID value:{0}", id ) );

        var tsc = new TaskCompletionSource<object>();
        tsc.SetResult(null );
        return tsc.Task;
    }
}
最后,现在控制器看起来像:

public class GetBookByIdQuery {
    public int Id { get; set;}
}
public class ValuesController : ApiController
{
    // GET api/values/5
    [Route( "api/values/{id}" )]
    public string Get([CustomParameterBinding] string id )
    {
        return id;
    }       
}
所以现在我打电话的时候


我得到:“这是格式化的ID值:5”

要从URI读取复杂类型,可以使用
[FromUri]

    [Route("{id:int}")]
    public Book Get([FromUri] GetBookByIdQuery query) {

        // execute query and return result
    }

如果您请求api/values/2,则查询对象的id属性将为2

我想使用route参数而不是QueryString我不明白你为什么要在这上面浪费时间。使用id而不是GetBookByIdQuery有什么问题?你能多说一点关于这个提议的目的或用途吗?嗯,为什么这是浪费时间?对于WebApi中的帖子,您可以直接绑定到强类型模型,而不是绑定到每个单独的字段,然后自己填充强类型模型。为什么一个GET会有什么不同呢。现在,我必须接受每个绑定参数并创建我的强类型查询对象,而不是首先绑定到该对象。您的方法将打破REST标准。您响应的是请求的资源id,而不是模型。REST是关于如何获取、放置、发布、修补和删除的定义良好的,ASP.NETWebAPI2是为REST应用程序而构建的。也许你是个创新者。然后,您需要更好地证明您的方法。我在ASP.NETMVC中使用模型绑定器做了类似的事情。你可以在这里找到Web API,我非常不喜欢你的GET提案,但我希望这能帮助你,我很困惑。。我没有违反任何标准。您仍在请求具有Id的资源,url不会更改,具有其约束的路由也不会更改。我只是问他们是否是一条有约束力的捷径,仅此而已。我的问题是,你能直接绑定到一个模型而不是绑定到每个单独的路由参数吗?为什么要向下投票?这有什么问题?这只适用于复杂类型的查询字符串中有值的情况。然后它将获取路由id和查询字符串值。如果
GetBookIdQuery
正文中也有值,会发生什么情况?理想情况下,它将首先基于主体构建对象,然后尝试基于路由模板参数在其上设置值。在AspNet Core中,[FromUri]-属性被拆分为路由和查询字符串的单独属性:[FromRoute]和[FromQuery]。在上面的例子中,[FromRoute]是正确的。还要注意的是,即使它可以工作,在将路由参数绑定到复杂对象的属性时,Swashback(Swagger UI)也可能会混淆。