【问题标题】:ASP.NET Web API get child list (hierarchical resources)ASP.NET Web API 获取子列表(分层资源)
【发布时间】:2013-01-18 09:58:28
【问题描述】:

我想使用 ASP.NET Web Api 实现以下其余模式:

http://mydomain/api/students
http://mydomain/api/students/s123
http://mydomain/api/students/s123/classes
http://mydomain/api/students/s123/classes/c456

我已经使用 ApiController 和以下两种方法使前两个链接正常工作:

public class StudentsController : ApiController {
  // GET api/students
  public IEnumerable<Student> GetStudents() {  
  }

  // GET api/students/5
  public IEnumerable<Student> GetStudent(string id) {  
  }
}

在同一个控制器中,(或者我是否需要一个名为 ClassesController 的不同控制器?),我将如何实现最后两个链接?另外,“类”部分的路由是什么样的(如果需要)?

这是我的 WebApiConfig(我希望保持动态,而不是尽可能硬编码到 /classes 的路由:

config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{id}",
  defaults: new { id = RouteParameter.Optional }
);   

// EDIT - I'm getting 404's when trying to use this
context.Routes.MapHttpRoute(
  name: "JobsApi",
  routeTemplate: this.AreaName + "/Students/{id}/Classes/{classId}",
  defaults: new { classId = RouteParameter.Optional }
);   

编辑 这是我新创建的 ClassesController:

public class ClassesController : ApiController {
  // GET api/classes
  public IEnumerable<TheClass> Get(string id) {    
      return null;
  }
}

我在尝试访问此 URL 时遇到 404 错误:

http://mydomain/api/students/s123/classes

【问题讨论】:

标签: c# asp.net rest asp.net-web-api asp.net-mvc-routing


【解决方案1】:

ASP.NET 中的路由可以表达这些更复杂的规则,但需要明确设置。例如,在这种情况下,您必须定义 2 条路线:

config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/{controller}/{id}",
  defaults: new { id = RouteParameter.Optional }
);   

config.Routes.MapHttpRoute(
  name: "DefaultApi",
  routeTemplate: "api/students/{studentId}/{controller}/{classId}",
  defaults: new { classId = RouteParameter.Optional }
);   

你会有一个控制器来控制它:

public class ClassesController
{
   public TheClass Get(int studentId, int classId)
   {
       ....
   }
}

这可能并不理想,但却是主要选择。

我正在处理分层路由,由于 Web API 中的实现问题而无法实现,但这个问题现在已经修复,所以我可能会再次开始处理它。

【讨论】:

    【解决方案2】:

    使用这种漂亮的分层方法,您可以更关心内部路由。有一个很好的示例应用程序采用分层资源结构:PingYourPackage。检查一下。

    注意:我有一篇关于此问题的博文,其中解释了以下问题,并通过一些代码示例为那些问题提供了解决方案。你可以 查看更多详情:

    让我通过设置一个示例场景来简要解释这里的问题。对于这类情况,这可能不是理想的方法,但很好地解决了这些问题。假设您的数据库中有以下两家货运公司的附属公司:

    • 附属公司1(ID:100)
    • 附属公司2(ID:101)

    然后假设这些附属公司附有一些货物:

    • 附属公司 1(密钥:100)
      • Shipment1(密钥:100)
      • Shipment2(密钥:102)
      • Shipment4(密钥:104)
    • 附属公司2(密钥:101)
      • Shipment3(密钥:103)
      • Shipment5(密钥:105)

    最后,我们希望有如下的资源结构:

    GET api/affiliates/{key}/shipments
    GET api/affiliates/{key}/shipments/{shipmentKey}
    POST api/affiliates/{key}/shipments
    PUT api/affiliates/{key}/shipments/{shipmentKey}
    DELETE api/affiliates/{key}/shipments/{shipmentKey}
    

    路由问题

    @Ali 已经解释过了,但我在这里有不同的方法。假设我们正在发送一个针对/api/affiliates/105/shipments/102 的 GET 请求。请注意,此处的附属密钥是 105,它不存在。因此,我们希望尽快在此处终止请求。我们可以通过每个路由消息处理程序来实现这一点。

    授权问题

    如果您有某种类型的身份验证,您需要确保(在我们这里的场景中)经过身份验证的用户和请求的附属资源是相关的。例如,假设 Affiliate1Affiliate 角色 下进行了身份验证,并且您已注册 AuthorizeAttribute 以检查“Affiliate”角色授权。在这种情况下,您将惨遭失败,因为这意味着 Affiliate1 可以访问以下资源:属于 Affiliate2 的/api/affiliates/101/shipments。我们可以通过自定义AuthorizeAttribute 来消除这个问题。

    所有权问题

    现在,以下 URI 应该为我提供正确的数据:

    GET /api/affiliates/100/shipments/102

    但是,下面的 URI 会发生什么:

    GET /api/affiliates/100/shipments/103

    这应该会得到“404 Not Found”HTTP 响应,因为 ID 为 100affiliate 不拥有 ID 为的 shipment 103

    【讨论】:

    • 感谢您的回复/帖子。我想知道,有没有办法动态路由到辅助控制器?
    • @AdamLevitt 你到底是什么意思?
    • 我的意思是,我正在查看此页面上答案中的路由,并且路由是硬编码的,我想知道它是否可以是动态的?像这样的东西:“api/{controller1}/{id}/{controller2}
    • @AdamLevitt 我明白了。不适用于当前的实现。您可以使用控制器选择器,实现自己的选择器并将其替换为默认选择器以启用这种类型的选择。另外,看看这篇文章:strathweb.com/2013/01/…这可能是你正在寻找的。​​span>
    • 谢谢。现在我正在尝试硬编码尝试,但我的路由无法正常工作,因为我遇到了 404 错误。也许我做错了什么?我会把我的路线放在原来的帖子里。
    猜你喜欢
    • 2021-11-30
    • 1970-01-01
    • 2021-02-12
    • 2018-08-29
    • 1970-01-01
    • 1970-01-01
    • 2016-03-25
    • 1970-01-01
    • 2022-07-28
    相关资源
    最近更新 更多