在ASP.NET Core中使用Apworks開發數據服務:對HAL的支持

HAL,全稱爲Hypertext Application Language,它是一種簡單的數據格式,它能以一種簡單、統一的形式,在API中引入超連接特性,使得API的可發現性(discoverable)更強,並具備自描述的特色。使用了HAL的API會更容易地被第三方開源庫所調用,而且使用起來也很方便,開發者能夠像處理普通JSON數據那樣去處理API數據。有關HAL的更多信息,能夠參考官方網站:http://stateless.co/hal_specification.html。目前,不少RESTful服務開發框架都支持HAL的Response格式(Content-Type爲application/hal+json),好比大名鼎鼎的Spring Data,默認就支持HAL。如今,使用全新的Apworks Core(從此簡稱Apworks)開發數據服務時,默認也提供對HAL的支持。html

HAL的啓用和禁用

上一篇快速開發文章中,演練部分經過修改Startup.cs文件中的ConfigureServices方法以在ASP.NET Core Web API中啓用Apworks以及Data Service的開發支持。首先咱們回顧一下這段代碼:git

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddApworks()
        .WithDataServiceSupport(new DataServiceConfigurationOptions
            (new MongoRepositoryContext
                (new MongoRepositorySettings("localhost", "customer-service"))))
        .Configure();
}

 

默認狀況下,HAL的支持是啓用的。也就是說,當你運行Data Service時,直接發起HTTP GET請求,返回的Response已是application/hal+json格式的了:github

image

注意:因爲返回的數據量並無超出一頁的分頁尺寸,因此在_links下僅顯示了一個self的連接。若是存在多個分頁,那麼_links部分也會出現prev、next、first、last等連接。json

若是但願禁用HAL的功能,其實很是簡單,在上面的代碼中,在構造DataServiceConfigurationOptions時直接指定useHalSupport參數爲false便可:api

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddApworks()
        .WithDataServiceSupport(new DataServiceConfigurationOptions
            (new MongoRepositoryContext
                (new MongoRepositorySettings("localhost", "customer-service")), useHalSupport: false))
        .Configure();
}

因而,獲得的返回內容就再也不是application/hal+json,而是application/json了:數組

image

開發人員在開發Data Service的時候,能夠根據本身的需求啓用或者禁用HAL的支持。服務器

自定義HAL的返回內容

在ASP.NET Core Web API中使用Apworks開發數據服務時,對於HAL的返回內容是能夠自定義的。固然,這並不會改變HTTP Response的Content-Type,而是針對Response Body,其Json內容是能夠被自定義的。例如,在上面的例子中,HTTP GET的Response Body中不只包含所請求的數據對象數組(customers),並且還包含分頁信息,以及一個含有分頁連接的_links的對象。在實現Data Service的時候,若是這些返回內容不能知足需求,開發人員徹底能夠自定義。app

舉個例子,假設咱們但願在返回內容中包含當前的服務器時間,其開發過程以下。框架

首先,新建一個繼承於Apworks.Integration.AspNetCore.DataServices.DataServiceHalBuildConfiguration的類型,取名爲ServerTimeHalBuildConfigurationless

using Apworks.Integration.AspNetCore.DataServices;
using Hal.Builders;
using Microsoft.AspNetCore.Http.Extensions;
using System;

namespace CustomerService
{
    public class ServerTimeHalBuildConfiguration : DataServiceHalBuildConfiguration
    {
        protected override void RegisterHalBuilderFactoryForGetAll()
        {
            this.RegisterHalBuilderFactory("*.Get(int, int)", context =>
                new ResourceBuilder()
                    .WithState(new { ServerTime = DateTime.UtcNow })
                    .AddSelfLink().WithLinkItem(context.HttpContext.Request.GetEncodedUrl())
                    .AddEmbedded(context.ControllerAction.ControllerName.ToLower())
                        .Resource(new ResourceBuilder().WithState(context.State))
            );
        }
    }
}

而後,回到Startup.cs文件中的ConfigureServices方法,在DataServiceConfigurationOptions的構造函數參數中,指定halBuildConfigurationFactory參數,代碼以下:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddApworks()
        .WithDataServiceSupport(new DataServiceConfigurationOptions
            (new MongoRepositoryContext
                (new MongoRepositorySettings("localhost", "customer-service")),
                halBuildConfigurationFactory: _ => new ServerTimeHalBuildConfiguration()))
        .Configure();
}

OK,任務完成,測試一下。打開MINGW,執行curl http://localhost:2238/api/customers -i命令,看看結果如何:

image

能夠看到,咱們已經在返回的HAL結果中加入了服務器的UTC時間,同時,仍是保留了_self的連接。不過,分頁的連接沒有包含在內,這是由於咱們經過override重寫了RegisterHalBuilderFactoryForGetAll方法。你能夠參考Apworks框架源代碼中的Apworks.Integration.AspNetCore.DataServices.DataServiceHalBuildConfiguration類來了解如何將分頁的連接加入到HAL的返回結果中。

大體對上面的代碼作一些介紹:

  1. DataServiceHalBuildConfiguration及其子類主要負責對HAL Resource BuilderBuilder模式,[GoF95])的定義和註冊,它能將某一個HAL的資源構造器(Resource Builder)關聯到某一個ASP.NET Core Web API的控制器上
  2. RegisterHalBuilderFactory方法會根據其第一個參數(ControllerActionSignature)肯定一個ASP.NET Core Web API的Controller Action方法,並將第二個參數所指定的HAL Resource Builder工廠方法委託(Delegate)註冊到由ControllerActionSignature指定的Controller Action方法上
  3. HalResultFilterAttribute類中,當Controller Action執行完成時,會根據所註冊的Hal Resource Builder Factory來獲取最終的HAL內容(經過調用ResourceBuilder的Build方法),而後將產生的HAL以application/hal+json格式返回
  4. SupportsHalAttribute類中會根據是否存在一個IHalBuildConfiguration的Service註冊,來肯定是否使用HAL的返回內容
  5. DataServiceController類已經使用了SupportsHalAttribute,所以,它具備使用HAL功能的能力,那麼繼承於它的控制器都會被應用SupportsHalAttribute特性,所以,你開發的數據服務控制器(Data Service Controller)無需關注HAL的功能
  6. 最後,在DataServiceConfigurationOptions類的構造函數中,經過指定useHalSupport以及halBuildConfigurationFactory兩個參數,來決定是否須要HAL的支持,以及如何產生HAL的結果

事實上,若是你不打算使用DataServiceController來快速開發數據服務,而是但願使用傳統的方式本身開發本身的RESTful服務,你徹底可使用Apworks.Integration.AspNetCore.Hal命名空間下的類型來使得你的RESTful服務也支持流行的HAL,並且開發過程很是方便。因而可知,Apworks.Integration.AspNetCore中對HAL的支持並非專爲框架自己的數據服務開發而設計的,它可以應用於普通的RESTful服務的開發,數據服務只不過是HAL的一個客戶而已。

總結

本文介紹了Apworks數據服務開發中對HAL的支持,能夠看到,Apworks框架的設計是:

  1. 靈活的:經過不一樣的配置信息來干預數據服務的執行過程,同時還支持自定義擴展來定製本身的數據服務
  2. 通用的:組件的設計儘量達到通用性,好比HAL的機制,它不只僅是Apworks數據服務的「特供」,它能夠被應用在任何由ASP.NET Core Web API所開發的RESTful服務上
  3. 開發體驗友好的:簡單的API定義使得應用程序快速開發成爲可能,Fluent Interface API(流暢接口)的設計,使得開發者可以用更爲天然的語言來完成所須要的功能操做,大大提高開發生產率。在Apworks的整個框架中,會更多地引入流暢接口以便保持較好的開發者體驗

就HAL這部分來講,它利用了ASP.NET Core中的ResultFilter以及Filter Factory,建議你們能夠了解一下HAL以及Data Service的相關代碼,來熟悉ASP.NET Core中Filter的相關內容。

值得一提的是,Apworks中對HAL的支持使用的正是我本身開發的HAL庫,這套庫也是開源的,開源地址是:https://github.com/daxnet/hal,它是爲數較少的完整實現HAL規範,並支持.NET Core的HAL開發庫,一樣,它支持流暢接口。

下一講打算介紹一下如何在Apworks數據服務中使用Entity Framework Core。敬請期待。

相關文章
相關標籤/搜索