我可以声明一个 web API 端点来接受任何参数并让我自己检查它们吗?

Can I declare a web API endpoint that accepts any arguments and lets me check them myself?

我正在开发基于 ASP.NET 的 .NET 4.6.1 Web 应用程序。我们的网络 API 控制器大量使用 [HttpGet][HttpPost] 属性;路由是通过 [Route] 属性完成的。

我了解到,如果多个方法具有相同的路由,ASP.NET 将通过它们的参数名称(和编号)来区分它们。

现在,在我的一个控制器上,我想提供一种方法(其路由,或至少路由 + HTTP 动词组合,是唯一的)将接受其查询字符串中的任何参数。最好是,我希望将解析后的查询字符串作为 key/value 对的列表,但如果我必须自己解析查询字符串,那也行。

如何在保持我们的通用代码结构的同时实现这一点(即依赖 [Route] 进行路由等)?

我找到了几个可能的解决方案,但不知何故,总是缺少某些东西,或者至少,由于缺乏文档,我的发现尚无定论。例如:

编辑:例如,我希望我的端点(我们称它为 call)对以下任何一项做出反应:

.../call
.../call?a=5&b=20&c=800
.../call?a=foo&z=bar

基本原理简介:该方法是基于我的实际控制器的抽象基础class。 URL 参数将被每个单独的控制器实际接受的信息可以很容易地从运行时 data/reflection 中提取,因此如果接收到的参数不合适,我可以自己 return 状态 404。我所做的 而不是 想做的是为每个控制器单独实现该方法 - 尽管这会让我在每个控制器上指定不同的参数,但它会造成不便的冗余。

EDIT2:这是控制器外观的简化版本:

基地class:

public abstract class ControllerBase<T, TKey> : ApiControllerBase
{
    [Route("call")]
    [HttpGet]
    public T Call([FromUri(Name = "")] TKey key)
    {
        // retrieve T from database based on key (for instance)
    }
}

实际控制人:

public class Thing
{}

public class ThingKey
{
    public int OwnerId { get; set; }
    public int Id { get; set; }
}

[RoutePrefix("api/thing")]
public class ThingController : ControllerBase<Thing, ThingKey>
{}

还有另一个控制器:

public class Stuff
{}

public class StuffKey
{
    public int Scope { get; set; }
    public int Group { get; set; }
    public int UniqueKey { get; set; }
}

[RoutePrefix("api/stuff")]
public class StuffController : ControllerBase<Stuff, StuffKey>
{}

如此处所示,我的 call 端点当前仍将其 URL 查询字符串中的参数映射到特定于控制器的对象的属性。我想消除为每个控制器提供单独的键 class 的必要性,而是在字典或类似的东西中接收 call 的参数。

您可以接受如下字典:

[HttpPost]
[Route("api/call")]
public void SomeMethod(HttpRequestMessage request)
{
    Dictionary<string,string> requestData= request.Content.ReadAsAsync<Dictionary<string,string>>().Result;
}

然后你就可以看字典了。

您可以使用 HttpRequestMessage 作为操作方法中的参数,而不是依赖自定义模型绑定器:

[Route("call")]
public IHttpActionResult SomeMethod(HttpRequestMessage request)
{
    var dict = new Dictionary<string, string>(ParseQueryStringToDictionary(request));

    // some code here
}

然后您需要使用 ParseQueryStringToDictionary 方法将查询字符串解析为 Dictionary<string, string>

private IDictionary<string, string> ParseQueryStringToDictionary(HttpRequestMessage request)
{
    var queryString = string.Join(string.Empty, request.RequestUri.ToString().Split('?').Skip(1));
    var queryStringValues = System.Web.HttpUtility.ParseQueryString(queryString);
    return queryStringValues.Cast<string>().ToDictionary(x => x, x => queryStringValues[x]);
}

并称它为:.../call?a=5&b=20&c=800