ASP.NET Web API获取子列表(分层资源)

时间:2013-02-03 15:49:42

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

我有以下休息架构,我想使用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 }
);   

EDIT 这是我新创建的ClassesController:

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

尝试访问此网址时出现404错误:

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

2 个答案:

答案 0 :(得分:7)

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中的实现问题而无法实现的,但此问题现已修复,因此我可能会再次开始处理它。

答案 1 :(得分:7)

通过这种优秀的分层方法,您可以更多地关注内部路由。有一个很好的示例应用程序采用分层资源结构:PingYourPackage。检查一下。

  

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

     

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

  • Affiliate1(Id:100)
  • Affiliate2(Id:101)

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

  • Affiliate1(Key:100)
    • 发货1(钥匙:100)
    • 发货2(钥匙:102)
    • 发货4(钥匙:104)
  • Affiliate2(Key:101)
    • 发货3(钥匙:103)
    • 发货5(钥匙: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,但不存在。所以,我们希望尽快终止请求。我们可以使用每个路由的消息处理程序来实现这一点。

授权问题

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

所有权问题

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

  

GET / api / affiliates / 100 / shipment / 102

但是,以下URI会发生什么:

  

GET / api / affiliates / 100 / shipment / 103

这会让您获得“404 Not Found”HTTP响应,因为 100 联属会员不拥有货件,其ID为的 103