主頁 > .NET開發 > 我為什么要放棄RESTful,選擇擁抱GraphQL

我為什么要放棄RESTful,選擇擁抱GraphQL

2023-02-05 06:15:19 .NET開發

背景

REST作為一種現代網路應用非常流行的軟體架構風格,自從Roy Fielding博士在2000年他的博士論文中提出來到現在已經有了20年的歷史,它的簡單易用性,可擴展性,伸縮性受到廣大Web開發者的喜愛,

 REST 的 API 配合JSON格式的資料交換,使得前后端分離、資料互動變得非常容易,而且也已經成為了目前Web領域最受歡迎的軟體架構設計模式,

 

但隨著REST API的流行和發展,它的缺點也暴露了出來:

  • 濫用REST介面,導致大量相似度很高(具有重復性)的API越來越冗余,

  • 對于前端而言:REST API粒度較粗,難以一次性符合前端的資料要求,前端需要分多次請求介面資料,增加了前端人員的作業量,

  • 對于后端而言:前端需要的資料往往在不同的地方具有相似性,但卻又不同,比如針對同樣的用戶資訊,有的地方只需要用戶簡要資訊(比如頭像、昵稱),有些地方需要詳細的資訊,這就需要開發不同的介面來滿足這些需求,當這樣的相似但又不同的地方多的時候,就需要開發更多的介面來滿足前端的需要,增加了后端開發人員的作業量和重復度,

 

那我們來分析一下,當前端需求變化,涉及到改動舊需求時,會有以下這些情況:

「做加法:」

產品需求增加,頁面需要增加功能,資料也就相應的要增加顯示,那么REST介面也需要做增加,這種無可厚非,

「做減法:」

產品需求減少,頁面需要減少功能,或者減少某些資訊顯示,那么資料就要做減法,

 

一種通常懶惰的做法是,前端不與后端溝通,僅在前端對資料選擇性顯示,

 

因為后端介面能夠滿足資料需要,僅僅是在做顯示的時候對資料進行了選擇性顯示,但介面的資料是存在冗余的,這種情況一個是存在資料泄露風險,另外就是資料量過大時造成網路流量過大,頁面加載緩慢,用戶流量費白白消耗,用戶體驗就會下降,

 

另外一種做法就是告知后端,要么開發新的介面,要么,修改舊介面,刪掉冗余欄位,

但一般來說,開發新介面往往是后端開發人員會選擇的方案,因為這個方案對現有系統的影響最低,不會有額外的風險,

 

修改舊介面洗掉冗余資料的方案往往開發人員不會選擇,這是為什么呢?

 

這就涉及到了系統的穩定性問題了,舊介面往往不止是一個地方在用,很有可能很多頁面、設定不同客戶端、不同服務都呼叫了這個介面獲取資料,不做詳細的調查,是不可能知道到底舊介面被呼叫了多少次,一旦改動舊介面,涉及范圍可能非常大,往往會引起其他地方出現崩潰,改動舊介面成本太高,所以往往不會被采取,

 

「同時做加減法:」

 

既有加法,又有減法,其實這種就跟新需求沒啥區別,前端需要重做頁面,后端需要新寫介面滿足前端需要,但是舊介面還是不能輕舉妄動(除非確定只有這一處呼叫才可以洗掉),

往往這個時候,其實用到的資料大多都是來自于同一個DO或者DTO,不過是在REST介面組裝資料時,用不同的VO來封裝不同欄位,或者,使用同樣的VO,組裝資料時做刪減,

 

看到這些問題是不是覺得令人頭大?

 

所以需求頻繁改動是萬惡之源,當產品小哥哥改動需求時,程式員小哥哥可能正提著鐵鍬趕來......

 

那么有沒有一種方案或者框架,可以使得在用到同一個領域模型(DO或者DTO)的資料時,前端對于這個模型的資料欄位需求的改動,后端可以根據前端的改動和需要,自動適配,自動組裝需要的欄位,回傳給前端呢?如果能這樣做的話,那么后端程式猿小哥可能要開心死了,前端妹子也不用那么苦口婆心地勸說后端小哥哥了,

 

所以GraphQL隆重出世了!那么問題來了!

 


Part 1 What is GraphQL

GraphQL簡介

  • GraphQL是一種新的API標準,它提供了一種比REST更有效、更強大和更靈活的替代方案,

  • 它是由Facebook開發并開源的,現在由來自世界各地的公司和個人組成的大型社區維護,

  • GraphQL本質上是一種基于api的查詢語言,現在大多數應用程式都需要從服務器中獲取資料,這些資料存盤可能存盤在資料庫中,API的職責是提供與應用程式需求相匹配的存盤資料的介面,

  • 它是資料庫無關的,而且可以在使用API的任何環境中有效使用,我們可以理解為GraphQL是基于API之上的一層封裝,目的是為了更好,更靈活的適用于業務的需求變化,

簡單的來說,它

 

它的作業模式是這樣子的:

 

GraphQL 對比 REST API 有什么好處?

REST API 的介面靈活性差、介面操作流程繁瑣,GraphQL 的宣告式資料獲取,使得介面資料精確回傳,資料查詢流程簡潔,照顧了客戶端的靈活性,

 

客戶端拓展功能時要不斷撰寫新介面(依賴于服務端),GraphQL 中一個服務僅暴露一個 GraphQL 層,消除了服務器對資料格式的硬性規定,客戶端按需請求資料,可進行單獨維護和改進,

 

REST API 基于HTTP協議,不能靈活選擇網路協議,而傳輸層無關、資料庫技術無關使得 GraphQL 有更加靈活的技術堆疊選擇,能夠實作在網路協議層面優化應用,

 

舉個經典的例子:前端向后端請求一個book物件的資料及其作者資訊,

我用動圖來分別演示下REST和GraphQL是怎么樣的一個程序,

先看REST API的做法:

 

再來看GraphQL是怎么做的:

 

可以看出其中的區別:

  • 與REST多個endpoint不同,每一個的 GraphQL 服務其實對外只提供了一個用于呼叫內部介面的端點,所有的請求都訪問這個暴露出來的唯一端點,

Endpoints對比

 

REST API's Endpoints

 

  • GraphQL 實際上將多個 HTTP 請求聚合成了一個請求,將多個 restful 請求的資源變成了一個從根資源 POST 訪問其他資源的 Comment 和 Author 的圖,多個請求變成了一個請求的不同欄位,從原有的分散式請求變成了集中式的請求,因此GraphQL又可以被看成是圖資料庫的形式,

那我們已經能看到GraphQL的先進性,接下來看看它是怎么做的,

 

GraphQL 思考模式

使用GraphQL介面設計獲取資料需要三步:

 

GraphQL獲取資料三步驟

 

  1. 首先要設計資料模型,用來描述資料物件,它的作用可以看做是VO,用于告知GraphQL如何來描述定義的資料,為下一步查詢回傳做準備;

  2. 前端使用模式查詢語言(Schema)來描述需要請求的資料物件型別和具體需要的欄位(稱之為宣告式資料獲取);

  3. 后端GraphQL通過前端傳過來的請求,根據需要,自動組裝資料欄位,回傳給前端,

GraphQL的這種思考模式是不是完美解決了之前遇到的問題呢?!

總結它的好處:

在它的設計思想中,GraphQL 以圖的形式將整個 Web 服務中的資源展示出來,客戶端可以按照其需求自行呼叫,類似添加欄位的需求其實就不再需要后端多次修改了,

創建GraphQL服務器的最終目標是:

允許查詢通過圖和節點的形式去獲取資料,


是什么讓我放棄了restful api?了解清楚后我全面擁抱GraphQL

GraphQL執行邏輯

有人會問:

 

  • 使用了GraphQL就要完全拋棄REST了嗎?

  • GraphQL需要直接對接資料庫嗎?

  • 使用GraphQL需要對現有的后端服務進行大刀闊斧的修改嗎?

 

答案是:NO!不需要!

 

它完全可以以一種不侵入的方式來部署,將它作為前后端的中間服務,也就是,現在開始逐漸流行的 前端 —— 中端 —— 后端 的三層結構模式來部署!

 

那就來看一下這樣的部署模式圖:

 

GraphQL執行邏輯

也就是說,完全可以搭建一個GraphQL服務器,專門來處理前端請求,并處理后端服務獲取的資料,重新進行組裝、篩選、過濾,將完美符合前端需要的資料回傳,

新的開發需求可以直接就使用GraphQL服務來獲取資料了,以前已經上線的功能無需改動,還是使用原有請求呼叫REST介面的方式,最低程度的降低更換GraphQL帶來的技術成本問題!

如果沒有那么多成本來支撐改造,那么就不需要改造!

只有當原有需求發生變化,需要對原功能進行修改時,就可以換成GraphQL了,

GraphQL應用的基本架構

下圖是一個 GraphQL 應用的基本架構,其中客戶端只和 GraphQL 層進行 API 互動,而 GraphQL 層再往后接入各種資料源,這樣一來,只要是資料源有的資料, GraphQL 層都可以讓客戶端按需獲取,不必專門再去定介面了,

 

GraphQL應用基本架構

 

一個GraphQL服務僅暴露一個 GraphQL Endpoint,可以按照業務來進行區分,部署多個GraphQL服務,分管不同的業務資料,這樣就可以避免單服務器壓力過大的問題了,

GraphQL特點總結

  • 宣告式資料獲取(可以對API進行查詢): 宣告式的資料查詢帶來了介面的精確回傳,服務器會按資料查詢的格式回傳同樣結構的 JSON 資料、真正照顧了客戶端的靈活性,

  • 一個微服務僅暴露一個 GraphQL 層:一個微服務只需暴露一個GraphQL endpoint,客戶端請求相應資料只通過該端點按需獲取,不需要再額外定義其他介面,

  • 傳輸層無關、資料庫技術無關:帶來了更靈活的技術堆疊選擇,比如我們可以選擇對移動設備友好的協議,將網路傳輸資料量最小化,實作在網路協議層面優化應用,


GraphQL支持的資料操作

GraphQL對資料支持的操作有:

  • 查詢(Query):獲取資料的基本查詢,

  • 變更(Mutation):支持對資料的增刪改等操作,

  • 訂閱(Subscription):用于監聽資料變動、并靠websocket等協議推送變動的訊息給對方,

圖片

GraphQL支持的操作

GraphQL的核心概念:圖表模式(Schema)

要想要設計GraphQL的資料模型,用來描述你的業務資料,那么就必須要有一套Schema語法來做支撐,

想要描述資料,就必須離不開資料型別的定義,所以GraphQL設計了一套Schema模式(可以理解為語法),其中最重要的就是資料型別的定義和支持,

那么型別(Type)就是模式(Schema)最核心的東西了,

什么是型別?

  • 對于資料模型的抽象是通過型別(Type)來描述的,每一個型別有若干欄位(Field)組成,每個欄位又分別指向某個型別(Type),這很像Java、C#中的類(Class),

  • GraphQL的Type簡單可以分為兩種,一種叫做Scalar Type(標量型別),另一種叫做Object Type(物件型別),

那么就分別來介紹下兩種型別,

標量型別(Scalar Type)

標量是GraphQL型別系統中最小的顆粒,類似于Java、C#中的基本型別,

其中內建標量主要有:

  • String

  • Int

  • Float

  • Boolean

  • Enum

  • ID

上面的型別僅僅是GraphQL默認內置的型別,當然,為了保證最大的靈活性,GraphQL還可以很靈活的自行創建標量型別,

物件型別(Object Type)

僅有標量型別是不能滿足復雜抽象資料模型的需要,這時候我們可以使用物件型別,

通過物件模型來構建GraphQL中關于一個資料模型的形狀,同時還可以宣告各個模型之間的內在關聯(一對多、一對一或多對多),

物件型別的定義可以參考下圖:

 

物件模型引入關聯關系

是不是很方便呢?我們可以像設計類圖一樣來設計GraphQL的物件模型,

型別修飾符(Type Modifier)

那么,型別系統僅僅只有型別定義是不夠的,我們還需要對型別進行更廣泛性的描述,

型別修飾符就是用來修飾型別,以達到額外的資料型別要求控制,

比如:

  • 串列:[Type]

  • 非空:Type!

  • 串列非空:[Type]!

  • 非空串列,串列內容型別非空:[Type!]!

在描述資料模型(模式Schema)時,就可以對欄位施加限制條件,

例如定義了一個名為User的物件型別,并對其欄位進行定義和施加限制條件:

User欄位控制

那么,回傳資料時,像下面這種情況就是不允許的:

 

Graphql會根據Schema Type來自動回傳正確的資料:

 

其他型別

除了上面的,Graphql還有一些其他型別來更好的引入面向物件的設計思想:

  • 介面型別(Interfaces):其他物件型別實作介面必須包含介面所有的欄位,并具有相同的型別修飾符,才算實作介面,

比如定義了一個介面型別:

 

那么就可以實作該介面:

  •  

    聯合型別(Union Types):聯合型別和介面十分相似,但是它并不指定型別之間的任何共同欄位,幾個物件型別共用一個聯合型別,

 

  • 輸入型別(Input Types):更新資料時有用,與常規物件只有關鍵字修飾不一樣,常規物件時 type 修飾,輸入型別是 input 修飾,

比如定義了一個輸入型別:

 

前端發送變更請求時就可以使用(通過引數來指定輸入的型別):

 

所以,這樣面向物件的設計方式,真的對后端開發人員特別友好!而且前端MVVM框架流行以來,面向物件的設計思想也越來越流行,前端使用Graphql也會得心應手,

 


Graphql 技術接入架構

那么,該怎么設計來接入我們現有的系統中呢?

  • 將Graphql服務直連資料庫的方式:最簡潔的配置,直接操作資料庫能減少中間環節的性能消耗,

直連資料庫的接入

  • 集成現有服務的GraphQL層:這種配置適合于舊服務的改造,尤其是在涉及第三方服務時、依然可以通過原有介面進行互動,

 

集成現有服務的GraphQL層
  • 直連資料庫和集成服務的混合模式:前兩種方式的混合,

 

混合接入方式

可以說是非常靈活了!你都不用擔心會給你帶來任何的麻煩,


 

服務端實作

在服務端, GraphQL 服務器可用任何可構建 Web 服務器的語言實作,有以下語言的實作供參考:

  • C# / .NET
  • Clojure
  • Elixir
  • Erlang
  • Go
  • Groovy
  • Java
  • JavaScript
  • Julia
  • Kotlin
  • Perl
  • PHP
  • Python
  • R
  • Ruby
  • Rust
  • Scala
  • Swift

種類繁多,幾乎流行的語言都有支持,

客戶端實作

在客戶端,Graphql Client目前有下面的語言支持:

  • C# / .NET
  • Clojurescript
  • Elm
  • Flutter
  • Go
  • Java / Android
  • JavaScript
  • Julia
  • Swift / Objective-C iOS
  • Python
  • R

覆寫了眾多客戶端設計語言,而其他語言的支持也在推進中,

Graphql的一些服務

整理了下目前比較流行的服務框架:

  • Apollo Engine:一個用于監視 GraphQL 后端的性能和使用的服務,

  • Graphcool (github): 一個 BaaS(后端即服務),它為你的應用程式提供了一個 GraphQL 后端,且具有用于管理資料庫和存盤資料的強大的 web ui,

  • Tipe (github): 一個 SaaS(軟體即服務)內容管理系統,允許你使用強大的編輯工具創建你 的內容,并通過 GraphQL 或 REST API 從任何地方訪問它,

  • AWS AppSync:完全托管的 GraphQL 服務,包含實時訂閱、離線編程和同步、企業級安全特性以及細粒度的授權控制,

  • Hasura:一個 BaaS(后端即服務),允許你在 Postgres 上創建資料表、定義權限并使用 GraphQL 介面查詢和操作,

Graphql的一些工具

  • graphiql (npm): 一個互動式的運行于瀏覽器中的 GraphQL IDE,

  • Graphql Language Service: 一個用于構建 IDE 的 GraphQL 語言服務(診斷、自動完成等) 的介面,

  • quicktype (github): 在 TypeScript、Swift、golang、C#、C++ 等語言中為 GraphQL 查 詢生成型別,

想要獲取更多關于Graphql的一些框架、工具,可以去awesome-graphql:一個神奇的社區,維護一系列庫、資源等,地址是

https://github.com/chentsulin/awesome-graphql,

想要學習更多Graphql的知識,可以去GraphQL.cn,


好了,一個入門級的Graphql介紹篇就這樣完結了(盡管篇幅也很大哈哈),

  • 不知道你懂得它的原理和優點了嗎?

  • 你對它感興趣嗎?

  • 看完這篇介紹,有沒有想動手嘗試一下呢?

  • 你會在你下一個專案中引入Graphql并使用它嗎?

  • 你對Graphql還有什么疑惑的問題呢?

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/542987.html

標籤:.NET技术

上一篇:uni-app + .NET 7實作微信小程式訂閱訊息推送

下一篇:必知必會的設計原則——開放封閉原則

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more