Asp.net web api 来自Uri和正文的ASP.NET Web Api 2 post请求

Asp.net web api 来自Uri和正文的ASP.NET Web Api 2 post请求,asp.net-web-api,asp.net-web-api2,model-binding,Asp.net Web Api,Asp.net Web Api2,Model Binding,我有一个ASP.NET Web Api 2端点,用于不同的客户端。端点应该接受来自主体和Uri的发布数据。 所以我的问题是,我的POST操作是否可以支持这两种类型的请求,并将发布的数据映射到POST操作中 我的解决方案是公开两个端点——一个支持每个场景(请参阅下面的代码),但我更希望只有一个端点可以提供给所有客户机。怎么可能呢 // The Controller Action when data is posted in the Uri: // POST: api/PostUri [HttpP

我有一个ASP.NET Web Api 2端点,用于不同的客户端。端点应该接受来自主体和Uri的发布数据。 所以我的问题是,我的POST操作是否可以支持这两种类型的请求,并将发布的数据映射到POST操作中

我的解决方案是公开两个端点——一个支持每个场景(请参阅下面的代码),但我更希望只有一个端点可以提供给所有客户机。怎么可能呢

// The Controller Action when data is posted in the Uri:

// POST: api/PostUri
[HttpPost]
[ActionName("PostUri")]
public Result Post([FromUri]Data data)
{
   // Do something..
}

// The Controller Action when request is posted with data in the Body:

// POST: api/MyController/PostBody
[HttpPost]
[ActionName("PostBody")]
public Result PostBody(Data data)
{
   return Post(data);
}

您可以通过自定义实现
HttpParameterBinding
来实现您的目标。以下是此类活页夹的工作示例:

public class UriOrBodyParameterBinding : HttpParameterBinding
{
    private readonly HttpParameterDescriptor paramDescriptor;

    public UriOrBodyParameterBinding(HttpParameterDescriptor descriptor) : base(descriptor)
    {
        paramDescriptor = descriptor;
    }

    public override async Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext,
        CancellationToken cancellationToken)
    {
        HttpParameterBinding binding = actionContext.Request.Content.Headers.ContentLength > 0
            ? new FromBodyAttribute().GetBinding(paramDescriptor)
            : new FromUriAttribute().GetBinding(paramDescriptor);

        await binding.ExecuteBindingAsync(metadataProvider, actionContext, cancellationToken);
    }
}
我们检查
Content-Length
HTTP头以确定请求是否包含HTTP主体。如果是,则从主体绑定模型。否则,将从Url绑定模型

还应添加自定义属性,用于标记将使用此自定义绑定器的操作参数:

[AttributeUsage(AttributeTargets.Parameter)]
public sealed class FromUriOrBodyAttribute : Attribute
{
}
下面是应该添加到
WebApiConfig.Register()方法中的活页夹注册。我们检查动作参数是否标记为
FromUriOrBodyAttribute
,并在这种情况下使用我们的自定义活页夹:

config.ParameterBindingRules.Insert(0, paramDesc =>
{
    if (paramDesc.GetCustomAttributes<FromUriOrBodyAttribute>().Any())
    {
        return new UriOrBodyParameterBinding(paramDesc);
    }

    return null;
});

我可以通过让我的
控制器
操作
获取两个参数来解决这个问题。我的数据类型的两个参数—一个带有
[FromUri]
属性,另一个不带:

public Result Post([FromUri]Data FromUri,Data fromBody)
{
//检查fromUri及其属性
//检查fromBody及其属性
...
}

如果数据的
请求
放在主体中,则数据将绑定到
fromBody
参数。如果
请求
数据在URI中,则它们将使用
[fromUri]
属性绑定到
fromUri
参数

在我看来,这似乎是一个simpel任务的大量工作!从body和Uri参数绑定模型不是一项非常常见的任务。这就是ASP.NET framework不支持开箱即用的原因。然而,正如我所演示的,它足够灵活,并提供了使之成为可能的扩展点。关于它所需的代码量,它看起来并不太复杂,并且基于现有的绑定。是否使用它取决于你,但我怀疑用更少的努力是否可能做到这一点。
[HttpPost]
public void Post([FromUriOrBody] Data data)
{
    //  ...
}