在ASP.NET Core Web API中為RESTful服務增加對HAL的支持

来源:http://www.cnblogs.com/daxnet/archive/2017/11/14/7835261.html
-Advertisement-
Play Games

HAL(Hypertext Application Language,超文本應用語言)是一種RESTful API的數據格式風格,為RESTful API的設計提供了介面規範,同時也降低了客戶端與服務端介面的耦合度。很多當今流行的RESTful API開發框架,包括Spring REST,也都預設支 ...


HAL(Hypertext Application Language,超文本應用語言)是一種RESTful API的數據格式風格,為RESTful API的設計提供了介面規範,同時也降低了客戶端與服務端介面的耦合度。很多當今流行的RESTful API開發框架,包括Spring REST,也都預設支持HAL規範,當RESTful API被調用後,服務端就會返回ContentType為application/hal+json的JSON內容,例如:

{
  "_links": {
    "self": {
      "href": "http://example.com/api/book/hal-cookbook"
    }
  },
  "_embedded": {
    "author": {
      "_links": 
        "self": {
          "href": "http://author-example.com"
        }
      }, 
      "id": "shahadat",
      "name": "Shahadat Hossain Khan"
    }
  },
  "id": "hal-cookbook",
  "name": "HAL Cookbook"
}

相對於僅返回一個id和一個name的結果而言,這樣的JSON Response包含了更為豐富的信息,比如:當前請求的API地址、HAL Cookbook這本書的作者信息,以及訪問作者信息的超文本鏈接。那麼客戶端在獲取到這個服務端的響應後,就能很方便地將這些信息綁定在界面上,而無需通過多個API的調用來查找關聯信息。另一方面,這種JSON Response中包含的超文本鏈接也可以是動態的,比如分頁導航鏈接,這樣客戶端實現分頁功能將變得非常方便。本文著重介紹在ASP.NET Core Web API中,如何為自己設計的RESTful API增加對HAL的支持。

Apworks框架

在ASP.NET Core Web API中為RESTful服務增加對HAL的支持,是通過Apworks框架以及HAL框架來完成的。這兩個框架都是我自己設計開發的開源框架,前者基於Apache 2.0開源,後者基於MIT開源,因此完全可以用於商業系統開發。HAL項目為超文本應用語言(Hypertext Application Language)提供了基本的數據模型和處理邏輯,它對JSON的支持基於大名鼎鼎的Newtonsoft.Json,因此性能方面是可以保證的。簡便快捷的流暢介面(Fluent Interface API)編程方式,使得構建一個完整合理的HAL對象模型變得非常容易。HAL項目的設計使用了一些對象結構化模式,有興趣的朋友可以到Github項目主頁(https://github.com/daxnet/hal)瞭解一下。

至於Apworks框架,它的主要功能並不是僅僅為了向ASP.NET Core Web API提供HAL的支持,它更重要的是一套基於.NET Core的微服務快速開發框架,不僅提供了面向領域驅動(DDD)的基本構造元素(聚合、實體、倉儲、工廠等),而且整合了消息隊列、消息派發及訂閱、消息處理、查詢服務、事件存儲等微服務架構功能模塊,並基於MongoDB、Entity Framework、RabbitMQ、PostgreSQL、SQL Server等基礎服務作出了實現。目前整個框架還在開發和完善階段,讀者有興趣也可以上Apworks Examples案例項目查看Apworks框架的案例代碼,案例代碼也在同步更新之中。等所有的案例代碼開發完成後,我會對Apworks框架發佈一個相對穩定的版本。

值得一提的是,Apworks框架中的Apworks.Integration.AspNetCore Package提供了對ASP.NET Core Web API的開發擴展,對HAL的支持也是該Package的一個部分。OK,Apworks框架和HAL框架暫時介紹這些,它們不是本文重點。接下來,讓我們看看,如何快速地在ASP.NET Core Web API中實現HAL的支持。

最簡單的案例

事實上,在《在ASP.NET Core中使用Apworks開發數據服務:對HAL的支持》一文中,我已經介紹瞭如何在Apworks快速搭建數據服務的同時,提供HAL的JSON數據格式。當時的案例是需要滿足數據服務開發模式的,比如需要註入倉儲實例,並且Controller需要預設提供GET、POST、PUT、DELETE的操作。這對於僅需要實現某些特定功能的通用Web API Controller而言,又顯得太重了。所以,我們還是從最簡單的案例開始吧。

  1. 打開Visual Studio 2017,新建一個ASP.NET Core Web API,.NET框架建議選擇.NET Core/ASP.NET Core 2.0,項目模板選擇Web API,此時會生成一個預設的ASP.NET Core 2.0 Web API應用程式。可以暫且不啟用Docker支持
  2. 直接啟動這個ASP.NET Core Web API應用程式,將預設在瀏覽器中輸出value1和value2兩個值:

    image

  3. 根據《在ASP.NET Core中使用Apworks快速開發數據服務》一文中的介紹,將Apworks和Apworks.Integration.AspNetCore兩個Package添加到項目中。註意,版本必須大於等於0.1.138(目前是開發版本)

    image

  4. 添加成功後,ASP.NET Core Web API應用程式的NuGet依賴項類似如下:

    image

  5. 雙擊打開Startup.cs文件,在ConfigureServices方法中,加入以下代碼:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    
        var halBuildConfiguration = new HalBuildConfiguration(new HalBuildConfigurationItem[]
        {
            new HalBuildConfigurationItem("Values.Get", context =>
                new ResourceBuilder().WithState(null)
                    .AddSelfLink()
                    .WithLinkItem(context.HttpContext.Request.GetDisplayUrl())
                    .AddEmbedded("values")
                    .Resource(new ResourceBuilder().WithState(context.State)))
        });
    
        services.AddApworks()
            .WithHalSupport(halBuildConfiguration)
            .Configure();
    }
    
  6. 雙擊打開ValuesController.cs文件,在Get()方法上,加上SupportsHal特性:

    [HttpGet]
    [SupportsHal]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
    
  7. 再次運行,可以看到,返回結果已經是HAL的JSON格式,Content-Type為application/hal+json:

    image

上面是最簡單的案例,我們就只用了幾行代碼,花了10分鐘不到,就把ASP.NET Core Web API的預設項目打造成了支持HAL JSON格式的RESTful API項目。大概介紹幾個要點:

  1. 首先需要創建一個HalBuildConfiguration對象,這個對象可以容納一個或者多個HalBuildConfigurationItem對象,每個HalBuildConfigurationItem對象包含了“需要對哪個Controller的哪個Action的返回值進行HAL格式處理”以及“如何處理API的返回結果並包裝成HAL JSON數據格式”這兩方面的信息
  2. 構造HalBuildConfigurationItem的第一個參數,用以指定API Controller下的Action的方法簽名,以便能夠確定HAL處理的API。大致規則如下,但事實上要更加靈活:
    1. *.Get:表示匹配所有Controller下,參數個數為0的Get方法
    2. Values.Get:表示匹配Values Controller下,參數個數為0的Get方法
    3. Values.Get(int,string):表示匹配Values Controller下,參數個數為2,類型分別為int和string的Get方法
  3. 構造HalBuildConfigurationItem的第二個參數,用以指定HAL JSON的產生方式。關於HAL ResourceBuilder的相關詳細文檔,請參考https://github.com/daxnet/hal
  4. 在相應的Controller Action上使用SupportsHal特性,標註當前方法需要產生HAL JSON的輸出。SupportsHalAttribute還可以直接使用在Controller級別,用以標註當前Controller下,所有的Action都能夠支持HAL JSON的輸出

過程非常簡單,而且非常靈活,開發人員可以完全自定義所產生的HAL JSON的格式(比如在這個例子中,我們向RESTful API的結果輸出了請求的URL路徑(也就是上圖中_links.self節點))。接下來,讓我們看一個稍微複雜一點的應用場景,看看如何通過HAL JSON的RESTful API快速實現服務端分頁。

服務端分頁案例介紹

分頁,是Web Service開發中不可避免的常見問題。來自服務端的數據量往往很大,即使可以通過查詢條件來過濾掉很大一部分數據,用戶資料庫中的數據量仍然是無法估計的。採用服務端分頁,不僅可以減少網路上的數據傳輸,提高服務響應度,而且還可以降低客戶端數據處理的壓力,為用戶提供較好的使用體驗。Apworks.Integration.AspNetCore程式包通過向ASP.NET Core Web API提供HAL的支持,開發人員可以非常方便地實現專業化的服務端分頁功能。接下來,就讓我們一起看一個簡單的案例:將26個英文字母進行分頁並根據用戶的輸入條件返回相應頁的數據。

我們仍舊使用上面的Web API項目:

  1. 將ValuesController中的Get()方法改成如下代碼:

    [HttpGet]
    [SupportsHal]
    public IActionResult Get(int page = 1, int size = 5)
    {
        var values = new[] { "a", "b", "c", "d", "e",
            "f", "g", "h", "i", "j",
            "k", "l", "m", "n", "o",
            "p","q", "r","s","t",
            "u","v","w","x","y",
            "z" };
        var skip = (page - 1) * size;
        var take = size;
        var records = values.Length;
        var pages = (records + size - 1) / size;
        return Ok(new PagedResult(values.Skip(skip).Take(take), page, size, records, pages));
    }
    
  2. 修改Startup.cs文件,將ConfigureServices方法改為如下代碼,註意HalBuildConfigurationItem的第一個參數,已經變成Values.Get(int, int),表示匹配ValuesController中含有兩個int類型參數的Get方法:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    
        services.AddApworks()
            .WithHalSupport(new PagedResultHalBuildConfiguration("Values.Get(int, int)"))
            .Configure();
    }
    
  3. Ctrl+F5直接運行Web API應用程式,在瀏覽器中輸出如下:

    image

    可以看到,英文字母已經通過分頁形式輸出,在_links節點下包含了self、first、last、next的鏈接,與此同時,服務端還返回了當前頁碼、每頁數、總記錄條數以及總頁數的信息。

  4. 在瀏覽器中,輸入http://localhost:52566/api/values?page=2,產生的結果如下:

    image

    此時已經顯示了第二頁的信息,並且分頁的鏈接已經相應地更新了。如果你的瀏覽器安裝了JSON格式數據查看插件,那麼很有可能JSON中的超文本鏈接已經可以直接點擊了,於是,你就可以在瀏覽器中直接點擊這些鏈接來實現各頁面的跳轉,非常方便。

由此可見,基於Apworks在ASP.NET Core Web API中為RESTful服務增加對HAL的支持還是非常方便的。在上面分頁的案例中,分頁查詢是通過在URL中增加名為page的Query String來實現了,page這個Query String就對應Get方法中的第一個page參數。那麼,如果我希望使用其它的Query String來作為分頁的頁碼參數,又該如何做呢?

自定義分頁參數

自定義分頁參數方法非常簡單,只需要在參數定義前加上PageNumberAttribute就行了。比如下麵的Get方法:

[HttpGet]
[SupportsHal]
public IActionResult Get([PageNumber] int p = 1, int size = 5)
{
    var values = new[] { "a", "b", "c", "d", "e",
        "f", "g", "h", "i", "j",
        "k", "l", "m", "n", "o",
        "p","q", "r","s","t",
        "u","v","w","x","y",
        "z" };
    var skip = (p - 1) * size;
    var take = size;
    var records = values.Length;
    var pages = (records + size - 1) / size;
    return Ok(new PagedResult(values.Skip(skip).Take(take), p, size, records, pages));
}

我們通過PageNumberAttribute來指定參數p為分頁參數,那麼,在訪問特定頁的數據時,就可以使用http://localhost:52566/api/values?p=2這樣的方式:

image

客戶端範例

既然我們已經有了一個服務端分頁的RESTful API,我們不妨快速搭建一個客戶端App,來試用一下這個支持HAL JSON格式的服務端分頁API是否好用。為此,我建立了一個客戶端項目,開發採用Angular 4和TypeScript,主要代碼如下:

// LettersResponse.ts
export class LettersResponse {
    public first: string;
    public prev: string;
    public next: string;
    public last: string;
    public values: string[];
}

// my-letters-service.service.ts
@Injectable()
export class MyLettersServiceService {

  constructor(private http: Http) { }

  getLetters(url: string): Promise<LettersResponse> {
    return this.http.get(url)
      .toPromise()
      .then(response => {
        const json = response.json();
        return {
          first: json._links.first ? json._links.first.href : null,
          last: json._links.last ? json._links.last.href : null,
          prev: json._links.prev ? json._links.prev.href : null,
          next: json._links.next ? json._links.next.href : null,
          values: json._embedded.values
        };
      });
  }
}

// app.component.ts
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [MyLettersServiceService]
})
export class AppComponent implements OnInit {

  response: LettersResponse;

  constructor(private service: MyLettersServiceService) {
  }

  ngOnInit(): void {
    this.service.getLetters(environment.serviceUrl)
      .then(res => this.response = res);
  }

  onLinkClicked(url: string): void {
    console.log(url);
    this.service.getLetters(url)
    .then(res => this.response = res);
  }
}

// app.component.html
<div *ngIf="response">
  <ul>
    <li *ngFor="let c of response.values">
      <h2>{{c}}</h2>
    </li>
  </ul>
  <button (click)="onLinkClicked(response.first)" [disabled]="!response.first">First Page</button>
  <button (click)="onLinkClicked(response.prev)" [disabled]="!response.prev">Previous Page</button>
  <button (click)="onLinkClicked(response.next)" [disabled]="!response.next">Next Page</button>
  <button (click)="onLinkClicked(response.last)" [disabled]="!response.last">Last Page</button>
</div>

在命令行使用NgCLI啟動客戶端程式,然後訪問http://localhost:4200,得到的效果如下:

service

總結

本文介紹瞭如何使用Apworks對於ASP.NET Core的擴展,來實現為RESTful API提供HAL支持的功能。文章使用了兩個案例,展示了ASP.NET Core Web API對HAL的支持是非常簡單方便的,而且自定義功能很強大,第二個服務端分頁案例更是引入了Angular和TypeScript,通過實現一個簡單的客戶端頁面來更詳細地展示具有HAL特性的RESTful API的便捷之處。正如上文所說,對HAL的支持僅僅是Apworks框架中對ASP.NET Core進行擴展的一個部分,Apworks框架更多地專註於為微服務的快速開發提供解決方案。在今後的文章中,我會更多地介紹Apworks對微服務支持的相關內容。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 首先查看自己的ubuntu系統的codename,這一步很重要,直接導致你更新的源是否對你的系統起效果,查看方法: lsb_release -a 如,我的系統顯示: Description: Ubuntu 17.04 Release: 17.04 Codename: zesty 2. 確認阿裡 ...
  • 這個是Linux下連接VFS文件系統框架和不同文件/文件系統底層實現之間的一個核心數據結構,雖然它只是一個指針,但是一個指針可以解決所有問題,有了它,媽媽再也不用擔心我的學習。我們回想一下用戶態線程的創建結構,函數的入口同樣是一個void*指針,而千言萬語彙成一根指針,詩可以興、可以觀、可以群、可以 ...
  • 遞歸時候每次調用自身在堆棧上要記錄返回地址,而堆棧的空間很少,調用次數多了後會產生堆棧溢出,以下代碼是實際項目中,通過Queue<T>來避免遞歸演算法的代碼: /// <summary> /// 獲取某個節點下特定屬性的所有子孫節點 /// </summary> /// <param name="gr ...
  • UNIT_PRICE :資料庫原先類型為: NUMBER(18,4) AMOUNT : 資料庫原先類型為: NUMBER(18,4) 如果直接進行修改會報錯,因為原先欄位中已經有數據了。 ALTER TABLE CLOUD_RELEASE.CONTRACT_PRODUCT_ITEM MODIFY(U ...
  • 我真的很喜歡在前端使用 Vue.js,Vue 服務端渲染直到第二個版本才被支持。 在本例中,我想展示如何將 Vue.js 2 服務端渲染功能整合 ASP.NET Core ...
  • 電商平臺和傳統店鋪相比,確實方便不少,直接在網上下單,快遞直接送貨到家。這其中,做電商平臺的童鞋表示壓力很大,因為可能同時開很多店鋪,每個店鋪都要登錄、查看訂單量、發貨揀貨等,非常辛苦。 多店鋪同時操作,需要打開很多瀏覽器,每個店鋪的帳號和密碼也要記清楚,腦子一定要夠用,不然就會頭暈腦漲。 ...
  • 相關博文: "Ubuntu 簡單安裝 Docker" "Mac OS、Ubuntu 安裝及使用 Consul" "Consul 服務註冊與服務發現" "Fabio 安裝和簡單使用" 閱讀目錄: Docker 運行 Consul 環境 Docker 運行 Fabio 環境 使用 Consul 註冊 A ...
  • MongDB .Net工具庫MongoRepository的簡單使用 最近研究了一下MongoDB資料庫,並使用了開源的在.net環境下的一個類庫,Mongo倉庫。對於數據的一些簡單的操作非常好用,特記錄供後期參考。 具體的使用過程如下: 一、新建項目,在Nuget上獲取庫。 二、在配置文件中設置數 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...