RESTful和存储库从另一种类型的体系结构返回值 [英] RESTful and Repository returning values from another type architecture

查看:69
本文介绍了RESTful和存储库从另一种类型的体系结构返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In short, I have two database tables: Languages and Frameworks. The important thing is that there is one-to-many relation between the tables(one language has many frameworks). I am designing a RESTful(WebAPI2) service to consume the information from these tables. I am using the repository pattern. Using EF, I've made a navigational property for the language to reach its frameworks.

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

However, how should that be implemented in the repositories. Is it correct to return a framework collection in the Language repository? I want to reach the frameworks of a language using the same WebAPI controller because it gives a more simple route and I'm not sure if that is a correct way to do it at all.

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}")一样,这似乎也不正确.

In the other hand, if I implement it in the framework repository(either by using the navigation property from the other table in the context or by scanning by id), I should use some nasty routing in the framework WebAPI controller(something like "api/frameworks/bylanguage/{id}") which again doesn't seem right.

推荐答案

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

In my opinion, for a RESTful service to be as clean as possible it is the best approach to define api controllers on a business entity basis. That is, you should define a controller to do your CRUD operations on languages and frameworks separately, like so:

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控制器上定义操作方法.

The point here is that for a RESTful service, in my opinion, it is the best to not assume anything about how the data returned by them are consumed. That is, you should not assume that everywhere the languages are displayed the frameworks are displayed as well. For example, imagine that some client lists the languages in a tabular manner. It would make a pretty messy UI to include the frameworks there as well. It is better to let the user pick a language and display the details separately, for example, in a modal window. The whole point of a RESTful service is, afterall, to supply data as granually as possible and not to tailor it to your specific views. They are meant to serve data to all kinds of HTTP-capable devices and software - including browsers and smartphone apps. If you want to just serve some data tailored to your views using AJAX calls, it is better to just define action methods on regular MVC controllers that respond to ajax calls and return a JsonResult.

我想在这里指出的一件事是,您不应在服务中返回数据库实体.我会提到两个+一个原因:

Also one thing I'd like to point out here is that you should not return DB entites in your services. I'll mention two+one reasons to this:

  • 安全性:不受任何控制地返回数据库实体意味着,每次修改数据模型时,这些更改都会反映在发送回客户端的数据中.这是因为将您的数据转换为所需格式的序列化程序不知道要包含哪些数据-除非您向其中添加属性,否则在这种情况下不应该这样做,因为包含实体的项目不应依赖于Web特定于api的程序集.因此,如果您修改实体,使其中的一些实体包含某种敏感数据,则该数据也将包含在响应中.在您的特定域中可能不必担心这件事,但是您应该记住这一点.
  • 域遍历:转换数据的序列化程序-除非通过使用属性(如我在上一个项目符号中所解释的那样另行指示),否则-只需将其找到的每个属性转换为所需格式,例如JSON,递归.通常,您的问题要比问题中描述的要多得多-用户(包含敏感数据,例如密码哈希),管理数据以及您能想到的一切.数据模型不连接的情况很少见,也就是说,可以通过遍历一个或多个导航属性从任何其他实体访问任何实体.因此,如果未正确告知序列化程序要包含和转换的数据,它将仅递归地包含所有连接的实体.由于通常已连接数据模型,这仅意味着包含每个表的每个记录,这将导致堆栈溢出异常或仅是太大的响应消息.
  • 安全性+域遍历相结合:第一个问题和第二个问题意味着,如果您的数据库只有很少的数据可容纳在单个响应中,并且它们都只是被序列化了,那么任何敏感数据(例如,用户数据,密码哈希等)甚至在没有意识到这一点的情况下就被包括在内.
  • Security: returning DB entities without any control means that every time you modify your data model, these changes are reflected in the data sent back to the clients. This is because the serializer that transforms your data into the demanded format is not aware of what data to include - unless you add attributes to it, which you shouldn't do in this case because the project that contains your entities should not rely on web api-specific assemblies. So if you modify your entites so that some of them contains some sort of sensitive data, this data is included in the response as well. This might be a thing not to worry about in your specific domain, but you should keep this in mind.
  • Domain traversal: the serializer that transforms your data - unless instructed otherwise by using attributes which is problematic as I explained in the previous bulletpoint - simply transforms every property it finds to the demanded format, say to JSON, recursively. Generally, you will have way more entites than described in your question - users (containing sensitive data, such as password hashes), administrative data and whatever you can think of. It is very uncommon for a data model to be not connected - that is, any entity can be reached from any other entity by traversing one or more navigation property. So if your serializer is not told exactly which data to include and transform, it just recursively includes any connected entites. Because of the data model generally being connected, this simply means every record of every table gets included and this leads to a stack overflow exception or simply a too large response message.
  • Security+domain traversal combined: the first and second issue implies that if your db has few enough data to fit in a single response and they all just get serialized, any sensitive data (for example, user data, password hashes etc) get included without you even realizing this.

简而言之,要解决此问题,您应该定义一些类,这些类准确地描述了将哪些数据发送回客户端,并仔细实现了如何选择它们的逻辑.

In short, to solve this problem you should define classes that exactly describe what data to send back to the client and carefully implement the logic of how to select them.

这篇关于RESTful和存储库从另一种类型的体系结构返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆