RESTful和Repository从另一个类型体系结构返回值

时间:2016-01-07 20:38:54

标签: .net asp.net-web-api2 repository-pattern

简而言之,我有两个数据库表:语言和框架。重要的是表之间存在一对多的关系(一种语言有很多框架)。我正在设计一个RESTful(WebAPI2)服务来使用这些表中的信息。我正在使用存储库模式。使用EF,我已经为语言创建了一个导航属性来实现其框架。

但是,应该如何在存储库中实现。在语言库中返回框架集合是否正确?我想使用相同的WebAPI控制器来访问语言的框架,因为它提供了一个更简单的路径,我不确定这是否是一种正确的方法。

public class LanguagesController : ApiController
{
    private readonly IProgrammingLanguageRepository languages;

    public LanguagesController() : this(new ProgrammingLanguageRepository(new CVSystemDbContext()))
    {
    }

    public LanguagesController(ProgrammingLanguageRepository languagesRepository)
    {
        this.languages = languagesRepository;
    }

    [HttpGet]
    [Route("api/languages")]
    public IHttpActionResult GetAll()
    {
        return this.Ok(this.languages.GetAll());
    }

    [HttpGet]
    [Route("api/languages/{id:int}")]
    public IHttpActionResult GetById(int id)
    {
        return this.Ok(this.languages.GetById(id));
    }

    [HttpGet]
    [Route("api/languages/{id:int}/frameworks")]
    public IHttpActionResult GetByLanguage(int id)
    {
        ----
    }
}

另一方面,如果我在框架存储库中实现它(通过使用上下文中其他表的导航属性或通过id扫描),我应该在框架WebAPI控制器中使用一些讨厌的路由(某些东西)比如“api / frameworks / bylanguage / {id}”),这似乎也不对。

1 个答案:

答案 0 :(得分:1)

在我看来,为了使RESTful服务尽可能干净,它是在业务实体基础上定义api控制器的最佳方法。也就是说,您应该定义一个控制器来分别在languagesframeworks上执行您的CRUD操作,如下所示:

public class LanguagesController : ApiController
{
    public IHttpActionResult Get(int id)
    {
        // logic to query and return a language by id
    }

    public IHttpActionResult GetAll()
    {
        // logic to query all (and possibly paginate) all the languages
    }
}

public class FrameworksController : ApiController
{
    public IHttpActionResult Get(int id)
    {
        // logic to query and return a framework by id
    }

    public IHttpActionResult GetByLanguage(int id)
    {
        // logic to return the frameworks of a specific language
    }

    public IHttpActionResult GetAll()
    {
        // logic to query all (and possibly paginate) all the frameworks
    }
}

这里的要点是,对于RESTful服务,在我看来,最好不要假设它们返回的数据是如何被消耗的。也就是说,您不应该假设在显示语言的任何地方都会显示框架。例如,假设某些客户端以表格方式列出语言。在那里包含框架也会是一个非常混乱的UI。最好让用户选择一种语言并单独显示细节,例如,在模态窗口中。 RESTful服务的重点始终是尽可能地提供数据,而不是根据您的具体视图进行定制。它们旨在为各种支持HTTP的设备和软件提供数据 - 包括浏览器和智能手机应用程序。如果您只想使用AJAX调用来提供针对您的视图定制的一些数据,最好只定义响应ajax调用并返回JsonResult的常规MVC控制器上的操作方法。

我还想指出的一件事是你不应该在你的服务中返回DB entites。我会提到两个+一个原因:

  • 安全性:在没有任何控制的情况下返回数据库实体意味着每次修改数据模型时,这些更改都会反映在发送回客户端的数据中。这是因为将数据转换为所需格式的序列化程序不知道要包含哪些数据 - 除非您向其添加属性,在这种情况下您不应该这样做,因为包含您的实体的项目不应该依赖于Web api专用程序集。因此,如果您修改您的entites以使其中一些包含某种敏感数据,则此数据也包含在响应中。这可能是您不需要担心的具体领域,但您应该牢记这一点。
  • 域遍历:转换数据的序列化程序 - 除非通过使用我在上一个要点中解释的有问题的属性另有说明 - 只需将找到的每个属性转换为所需格式,比如JSON,递归< / em>的。通常情况下,您的问题比您的问题中描述的更多 - 用户(包含敏感数据,如密码哈希),管理数据以及您能想到的任何内容。数据模型未连接的情况非常罕见 - 也就是说,可以通过遍历一个或多个导航属性从任何其他实体到达任何实体。因此,如果没有准确地告知序列化器要包含和转换哪些数据,它只是递归地包含任何连接的entites。由于数据模型通常是连接的,这只是意味着每个表的每个记录都包含在内,这会导致堆栈溢出异常或只是一个太大的响应消息。
  • 安全性+域遍历相结合:第一个和第二个问题意味着如果您的数据库中只有足够的数据不适合单个响应并且它们都被序列化,那么任何敏感数据(例如,用户数据,密码哈希等)包括在内,你甚至没有意识到这一点。

简而言之,要解决此问题,您应该定义完全描述要发送回客户端的数据的类,并仔细实现如何选择它们的逻辑。