如何将多个请求DTO映射到单个路由

时间:2013-05-10 19:48:32

标签: c# rest url-routing servicestack dto

我一直在尝试使用ServiceStack框架来开发一个简单的REST API。我在尝试正确定义路由以处理我想要的不同URL时遇到了麻烦。

我有一个简单的DomainModel类:

public class Student
{
    public int Id { get; set; } // unique
    public string Email { get; set; } // not unique

    // some other properties and business logic
}

我想创建一个REST服务来响应对以下URL的HTTP请求:

  • /students
    • GET返回所有学生
  • /students/123
    • GET返回ID = 123
    • 的学生
  • /students?id=123
    • GET返回ID = 123
    • 的学生
  • /students?email=foo@example.com
    • GET返回所有匹配电子邮件的学生

我尝试使用以下请求DTO来完成此任务:

[Route("/students", "GET")]
public class GetAllStudents : IReturn<StudentList>
{
}

[Route("/students", "GET")] // I want this to be for /students?Id=
[Route("/students/{Id}", "GET")]
public class GetStudentById : IReturn<Student>
{
    public int Id { get; set; }
}

[Route("/students", "GET")] // I want this to be for /students?Email=
public class GetStudentsByEmail : IReturn<StudentList>
{
    public string Email { get; set; }
}

如您所见,我只是尝试使用两种不同的Response DTO:

public class StudentList : List<Student>
{
}

public class Student
{
    public int Id { get; set; }
    public String Email { get; set; }
}

注意:此Reponse DTO Student类与我的DomainModel类不同;它们位于不同的名称空间中。

不幸的是,当我尝试使用这些路线时,/students?<anything>的每个请求最终都会返回所有学生。唯一可行的路线是,如果我向/students/123发出GET请求,那么我会返回带有Id 123的学生。我认为这不起作用,因为我正在重新使用"/students"路由定义对于多个请求DTO。

我一直在阅读ServiceStack wikiexamples,但我无法弄清楚如何完成我的尝试。我能找到的关于高级路由的最详细的文档是"Smart Routing" section of the "New API" page,但它并没有真正解决这种情况。

如何为多个请求DTO重复使用相同的路由定义?

1 个答案:

答案 0 :(得分:5)

在您的请求DTO上添加ByXXX后缀是ServiceStack中的代码嗅觉,他们希望鼓励设计基于消息的粗粒度接口。请参阅How to design a Message-Based API with ServiceStack上的此前面的答案以及为什么要按响应类型调用语义

对服务进行分组

在这种情况下,您有一项服务在唯一标识上执行Get,返回单个学生,您还希望拥有{{1}在电子邮件上,它会返回多个学生。所以在这种情况下,我会提供以下服务:

Search

只处理[Route("/students/{Id}")] public GetStudent : IReturn<Student> { public int Id { get; set; } }

/students/123

可以用来处理:

  • [Route("/students")] public FindStudents : IReturn<List<Student>> { public int? Id { get; set; } public string Email { get; set; } }
  • /students //但返回/students?id=123而不是
  • List<Student>
  • /students?email=foo@example.com

虽然我个人不会在此处添加/students?id=123&email=foo@example.com,因为它是获取而不是过滤器