测试一个接受对象作为参数的GET请求(Asp.NET WebApi控制器)

12

我被指派为一个应用程序开发WebAPI控制器(这是我以前从未接触过的东西)。一切都很顺利,有一些基本请求,比如 GetAllUsers(int id),只是为了测试目的 - 配置本身没问题。

现在出现了问题。我有一个方法GetAllItems(Carrier carrier),其中Carrier是一个带有许多不同参数的类。由于我们已经在数据库中有了一些Carrier实例供测试,所以我尝试查询数据库,根据ID (GUID)属性选择Carrier实例,但没有任何结果。

是否有一种方法可以测试GET请求,当输入参数是对象而不是单个值(例如int ID)时,手动使用测试方法或某种测试输入参数?

编辑:谢谢大家的反馈,解决我的问题的方法比我预期的要简单得多。我非常愿意给你们所有人点赞,但很遗憾,我的声望还不够高(我刚刚来到stackoverflow),所以我将不得不在不久的将来回来做到这一点。干杯:)


1
参数中的对象是否非空?这可能是序列化问题。那个对象来自哪里,它的属性如何在GET请求中发送? - Slavo
请提供有关Carrier类是什么以及GetAllItems的预期结果的更多信息。看起来它应该返回某种载体详细记录... - Pavel Kutakov
可以做到,但在决定这样做之前,您可能应该阅读以下帖子:https://dev59.com/N2gu5IYBdhLWcg3wxZtM 和 https://dev59.com/53NA5IYBdhLWcg3wZ85S。 - David Tansey
2个回答

21

就我理解,您希望能够直接在URL中传递Carrier的属性,而不是在请求体中传递。

例如:

[GET] http://localhost/entities?id=000000000000000

您的控制器方法如下

GetAllItems(Carrier carrier)

Carrier有一个Id(Guid)属性:

class Carrier {
    public Guid Id { get; set; }
    public string Name { get; set; }
}

在 WebApi 的模型绑定中,Carrier 是一个复杂的对象。

模型绑定的默认行为如下:

对于以下情况,Web API 使用以下规则来绑定参数: 如果参数是“简单”类型,则尝试从 URI 中获取该值。简单类型包括 .NET 原始类型(int、bool、double 等),以及 TimeSpan、DateTime、Guid、decimal 和 string,以及任何具有类型转换器的类型,可以从字符串进行转换。(稍后详细了解类型转换器。) 对于复杂类型,Web API 尝试从消息正文中读取值,使用媒体类型格式化程序。

详见:http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

期待通过 URL 绑定一个复杂对象并不是 WebApi 的默认行为。

如果您想让控制器方法从 URL 模型绑定复杂对象,则需要告诉它如何操作。

GetAllItems([FromUri] Carrier carrier)

通过FromUri绑定指示符,您可以从URL中使用复杂模型绑定。

现在您甚至可以在URL中添加更多属性映射:

[GET] http://localhost/entities?id=000000000000000&name=ABC

GetAllItems将接收到一个填充了以下内容的Carrier对象: carrier.Id = 0000-00000000000-000; carrier.Name = "ABC"


我能否拥有一个像 Get(int id) 这样的方法,以及另一个像 Get([FromUri]Carrier c) 这样的方法,但是我得到了“太多匹配的get错误”? - eRaisedToX

4
你在这里有一个路由问题,还存在一些误解。
WebApi的默认路由是:
routes.MapHttpRoute(
            name: "Default",
            routeTemplate: "{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

这与某些常规约定一起使用:

  • GetX将GET方法映射。
  • InsertX将POST方法映射。
  • UpdateX将PUT方法映射。
  • DeleteX将DELETE方法映射。

当您的命名约定与WepApi约定不一致时,您需要指定方法、操作名称等。

同样在路由方面也是如此。如果没有定义其他路由,则仅绑定遵循约定和默认路由的操作。

例如:

public IEnumerable<Carrier> GetAll(){
   //this will get called when using the route: /api/carriers/
}

public IEnumerable<Carrier> Get(string id){
   //this will be called when using the route: /api/carriers/1
   //where 1 is the carrier id
}

由于CarrierController与约定和路由对齐,因此您将在CarrierController中工作。

现在,如果您需要返回承运人的所有项目的方法,则需要使用此方法:

[ActionName("getItems")]
public IEnumerable<Item> GetAllItems(string id){
   //where id is the carrierid       
   var carrierId = id;
   //because you are specifying the ActionName to getItems this will match the following route: 
   // /api/carriers/getItems/1
}

另一个选项是创建一个ItemsController,并添加一个基于carrierId返回项目列表的操作,从概念上讲,这可能更好,但路由原则相同。

虽然这并没有完全回答楼主的问题,但它写得非常好,信息丰富而简洁。 - gitsitgo
@gitsitgo,同意,提供了很多信息.. +1 - eRaisedToX

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接