From 699262cc7809d048bc47abd0007e9e8daef78e7b Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 16:14:07 +0800 Subject: [PATCH 01/13] Update GitHub Actions workflow to use .NET 8.0 and Kampose --- .github/workflows/main.yml | 39 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 1111088..ae8ad23 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -7,48 +7,39 @@ on: pull_request: branches: [ master ] -permissions: - contents: write - jobs: build-test-document: runs-on: ubuntu-latest + permissions: + contents: write + steps: - uses: actions/checkout@v4 - - name: Setup .NET 6.0 + - name: Setup .NET 8.0 uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' + + - name: Install Kampose + run: dotnet tool install --global kampose - - name: Restore dependencies + - name: Restore Dependencies run: dotnet restore - - name: Build + - name: Build Solution run: dotnet build --no-restore -c Release - - name: Test + - name: Test Solution run: dotnet test --no-restore --verbosity minimal - - name: Setup DocFX - run: | - wget https://github.com/dotnet/docfx/releases/download/v2.75.3/docfx-linux-x64-v2.75.3.zip -O docfx.zip - unzip docfx.zip -d docfx - - name: Generate Documentation - run: | - docfx/docfx docfx.json - - - name: Prepare Docs for Deployment - run: | - mv ./docs/README.html ./docs/index.html - cp ICON.png ./docs/ - cp LICENSE ./docs/ + run: kampose build - - name: Deploy to GitHub Pages - uses: peaceiris/actions-gh-pages@v3 + - name: Deploy Documentation to GitHub Pages if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' + uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./docs + publish_dir: ./.site From fe58bbfa3a9c64538426b03a70bcc2800ea6c273 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 16:21:14 +0800 Subject: [PATCH 02/13] Fix documentation by adding missing XML comments --- src/Kampute.HttpClient.DataContract/XmlContent.cs | 13 +++++++++++-- src/Kampute.HttpClient.Json/JsonContent.cs | 13 +++++++++++-- .../JsonContent.cs | 13 +++++++++++-- src/Kampute.HttpClient.Xml/XmlContent.cs | 13 +++++++++++-- src/Kampute.HttpClient/Content/EmptyContent.cs | 13 +++++++++++-- .../RetryManagement/RetryScheduler.cs | 5 ++++- .../Utilities/ScopedCollection.cs | 1 + .../Utilities/SharedDisposable.cs | 9 ++++++--- 8 files changed, 66 insertions(+), 14 deletions(-) diff --git a/src/Kampute.HttpClient.DataContract/XmlContent.cs b/src/Kampute.HttpClient.DataContract/XmlContent.cs index 211f8fc..881e0a6 100644 --- a/src/Kampute.HttpClient.DataContract/XmlContent.cs +++ b/src/Kampute.HttpClient.DataContract/XmlContent.cs @@ -68,7 +68,12 @@ public XmlContent(object content, Encoding encoding) /// public DataContractSerializerSettings? Settings { get; set; } - /// + /// + /// Serializes the content to a stream asynchronously. + /// + /// The target stream. + /// The transport context. + /// A task that represents the asynchronous operation. protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { using var streamWriter = new StreamWriter(stream, _encoding, 4096, true); @@ -84,7 +89,11 @@ protected override Task SerializeToStreamAsync(Stream stream, TransportContext c return Task.CompletedTask; } - /// + /// + /// Attempts to compute the length of the content. + /// + /// When this method returns, contains the length of the content in bytes. + /// > if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1; diff --git a/src/Kampute.HttpClient.Json/JsonContent.cs b/src/Kampute.HttpClient.Json/JsonContent.cs index 74d264c..e3f15c7 100644 --- a/src/Kampute.HttpClient.Json/JsonContent.cs +++ b/src/Kampute.HttpClient.Json/JsonContent.cs @@ -44,13 +44,22 @@ public JsonContent(object content) /// public JsonSerializerOptions? Options { get; set; } - /// + /// + /// Serializes the content to a stream asynchronously. + /// + /// The target stream. + /// The transport context. + /// A task that represents the asynchronous operation. protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { return JsonSerializer.SerializeAsync(stream, _content, Options); } - /// + /// + /// Attempts to compute the length of the content. + /// + /// When this method returns, contains the length of the content in bytes. + /// > if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1; diff --git a/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs b/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs index d725c5c..cfa926c 100644 --- a/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs +++ b/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs @@ -46,7 +46,12 @@ public JsonContent(object content) /// public JsonSerializerSettings? Settings { get; set; } - /// + /// + /// Serializes the content to a stream asynchronously. + /// + /// The target stream. + /// The transport context. + /// A task that represents the asynchronous operation. protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { using var streamWriter = new StreamWriter(stream, utf8WithoutMarker, 4096, true); @@ -56,7 +61,11 @@ protected override Task SerializeToStreamAsync(Stream stream, TransportContext c return Task.CompletedTask; } - /// + /// + /// Attempts to compute the length of the content. + /// + /// When this method returns, contains the length of the content in bytes. + /// > if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1; diff --git a/src/Kampute.HttpClient.Xml/XmlContent.cs b/src/Kampute.HttpClient.Xml/XmlContent.cs index b836637..15bb130 100644 --- a/src/Kampute.HttpClient.Xml/XmlContent.cs +++ b/src/Kampute.HttpClient.Xml/XmlContent.cs @@ -60,7 +60,12 @@ public XmlContent(object content, Encoding encoding) /// public Encoding Encoding => _encoding; - /// + /// + /// Serializes the content to a stream asynchronously. + /// + /// The target stream. + /// The transport context. + /// A task that represents the asynchronous operation. protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { using var streamWriter = new StreamWriter(stream, _encoding, 4096, true); @@ -76,7 +81,11 @@ protected override Task SerializeToStreamAsync(Stream stream, TransportContext c return Task.CompletedTask; } - /// + /// + /// Attempts to compute the length of the content. + /// + /// When this method returns, contains the length of the content in bytes. + /// > if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1; diff --git a/src/Kampute.HttpClient/Content/EmptyContent.cs b/src/Kampute.HttpClient/Content/EmptyContent.cs index 809559f..05a14b8 100644 --- a/src/Kampute.HttpClient/Content/EmptyContent.cs +++ b/src/Kampute.HttpClient/Content/EmptyContent.cs @@ -14,13 +14,22 @@ /// public sealed class EmptyContent : HttpContent { - /// + /// + /// Serializes the content to a stream asynchronously. + /// + /// The target stream to which the content should be written. + /// The transport context. + /// A task that represents the asynchronous operation. protected override Task SerializeToStreamAsync(Stream stream, TransportContext context) { return Task.CompletedTask; } - /// + /// + /// Attempts to compute the length of the content. + /// + /// When this method returns, contains the length of the content in bytes. + /// if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = 0; diff --git a/src/Kampute.HttpClient/RetryManagement/RetryScheduler.cs b/src/Kampute.HttpClient/RetryManagement/RetryScheduler.cs index 5f797d5..b0a4ae8 100644 --- a/src/Kampute.HttpClient/RetryManagement/RetryScheduler.cs +++ b/src/Kampute.HttpClient/RetryManagement/RetryScheduler.cs @@ -32,16 +32,19 @@ public RetryScheduler(IRetryStrategy strategy) /// /// Gets the retry strategy associated with this scheduler. /// + /// The instance used by this scheduler. public virtual IRetryStrategy Strategy { get; } /// /// Gets the number of retry attempts that have been made. /// + /// The number of retry attempts. public virtual uint Attempts => _attempts; /// /// Gets the total elapsed time since the retry attempts were started. /// + /// The elapsed time as a . public virtual TimeSpan Elapsed => _timer.Elapsed; /// @@ -78,7 +81,7 @@ public virtual void Reset() /// Prepares the internal state for the next retry attempt. /// /// - /// This method is called immediately after a retry attempt is determined to be necessary and before the delay for the next attempt begins. + /// This method is called immediately after a retry attempt is determined to be necessary and before the delay for the next attempt begins. /// It allows for updating the internal state or performing any preparations required before the next attempt. /// protected virtual void ReadyNextAttempt() diff --git a/src/Kampute.HttpClient/Utilities/ScopedCollection.cs b/src/Kampute.HttpClient/Utilities/ScopedCollection.cs index 2e67560..f1f9b5d 100644 --- a/src/Kampute.HttpClient/Utilities/ScopedCollection.cs +++ b/src/Kampute.HttpClient/Utilities/ScopedCollection.cs @@ -9,6 +9,7 @@ /// /// Manages items within specific contexts. /// + /// The type of items managed within the scopes. /// /// /// This class facilitates the management of contextual items, which are elements associated with distinct operational contexts, diff --git a/src/Kampute.HttpClient/Utilities/SharedDisposable.cs b/src/Kampute.HttpClient/Utilities/SharedDisposable.cs index 7271ed8..012db17 100644 --- a/src/Kampute.HttpClient/Utilities/SharedDisposable.cs +++ b/src/Kampute.HttpClient/Utilities/SharedDisposable.cs @@ -14,7 +14,7 @@ namespace Kampute.HttpClient.Utilities /// The type of the disposable object. Must be a class that implements . /// /// - /// This class is particularly useful for managing resources that are expensive to create and can be safely shared across different parts + /// This class is particularly useful for managing resources that are expensive to create and can be safely shared across different parts /// of an application. It ensures that the resource remains alive as long as it is needed and is properly cleaned up afterwards. This pattern /// helps prevent resource leaks and promotes efficient resource usage. /// @@ -27,13 +27,14 @@ public sealed class SharedDisposable where T : class, IDisposable { private T? _instance; private int _referenceCount; - private readonly Func? _factory; + private readonly Func _factory; private readonly object _lock = new(); /// /// Initializes a new instance of the class that uses the default constructor of . /// public SharedDisposable() + : this(Activator.CreateInstance) { } @@ -68,7 +69,7 @@ private T IncReferenceCount() lock (_lock) { if (++_referenceCount == 1) - _instance = _factory is not null ? _factory() : (T)Activator.CreateInstance(typeof(T)); + _instance = _factory(); return _instance ?? throw new InvalidOperationException("The shared disposal manager factory failed."); } @@ -110,6 +111,7 @@ internal Reference(SharedDisposable owner) /// /// Gets the instance that owns this reference. /// + /// The owning instance. public SharedDisposable Owner => _owner; /// @@ -135,6 +137,7 @@ public void Dispose() /// Allows implicit conversion of the to the shared resource type. /// /// The reference instance. + /// The shared disposable resource instance. public static implicit operator T(Reference reference) => reference.Instance; } } From 917cf7af5d2978fdfc3d0b4e0db07439923fc531 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 16:37:59 +0800 Subject: [PATCH 03/13] Update .gitignore --- .gitignore | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 1e13dab..c1f2556 100644 --- a/.gitignore +++ b/.gitignore @@ -240,14 +240,6 @@ ClientBin/ *.publishsettings orleans.codegen.cs -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - # RIA/Silverlight projects Generated_Code/ @@ -364,4 +356,10 @@ FodyWeavers.xsd # Key files *.pfx -*.snk \ No newline at end of file +*.snk + +# VS Code settings folder +.vscode/ + +# Static website output +.site/ From d9c00a49c842575a2afb8541523e61018dfc1904 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 16:39:36 +0800 Subject: [PATCH 04/13] Replace DocFx with Kampose for generating documentation --- ICON.png | Bin 1330 -> 0 bytes docfx.json | 52 ------------------------------------------------- kampose.json | 40 +++++++++++++++++++++++++++++++++++++ logo-dark.png | Bin 0 -> 994 bytes logo-light.png | Bin 0 -> 931 bytes 5 files changed, 40 insertions(+), 52 deletions(-) delete mode 100644 ICON.png delete mode 100644 docfx.json create mode 100644 kampose.json create mode 100644 logo-dark.png create mode 100644 logo-light.png diff --git a/ICON.png b/ICON.png deleted file mode 100644 index 7293ebafec7e7a7894bef30c219a3d048673a787..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1330 zcmV-21Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!TeSaefwW^{L9 za%BKPWN%_+AW3auXJt}lVPtu6$z?nM00g2*L_t(oN9|TkOk7nIKKI@C-T(u&B_v1} z$fD5%EklAWSQC?`wuJ&|wOUuM8iU>WvoMM)(`a?!&qgtEVKiwXO+_k&(!`B51=B$I ziNVG+N;D~^kzy$@^Zu^id0fVMGXwK>-SkT?GkoXX^L_W6^B&NB+-nH^nMKRzT@@2O zL#z7N*k~O&+(5pp6-p>gMIfbbIIdd0c69U?O@)XU*f(^fStiXvcg4Fl-ZlK3rnkhN zZ#y2gE9D0&P=`o}@{m-89)uxCm?H33{ob*z;WL^hLw|vE zp>3dJx2!NjasRGcWRh|KU*z|N8*VZCEjLg&$+{o z%Ifk<(vo$t#2>K9TXlanAb$1POE)wf!KM`m!FDjcq(u3X{ZH51+sw--`%W*`%@gFU zc%!r`4_-MwdQ;N{*wO%IfSjewbwi0k+Mf8qC^L6@%O%7SvvwrNz2ltA{Bg7U>ah#U zI#Lu-134`aroqFwtX#j3O!cXeFn5&_=V#qS+3^(hjdff+G0`)D16!l80&D>yLXhia z{0oK@CuO({&n6PJ2HGq(420I)El07#Jla1%HX}Q25w_<9E-qH0K;WQ z+ExCk@$Qj#b*9+BHU3AcHPs-itO-g}wIT>`J2s{wI~~BrDZahL4@paFKdtPYbLM{2 zk=TeBXliPD*&_2ZKkzlf;4Qi8c|b^@cVyAup64B#ot+)mkywbdKnP)y1wroj`pPJ& zT%L&>F1oN^nTiaw0CXxsKf5dIa3UxXpPrH&Q{8|QN{aRw%~d^GcCpkUllPI4S)4#NFY zQ&VTr>sR8M;JJW_H!+xfnl8YW6<~4PWC5#la&j{Kiv|;);BkAEV{uGiFPrFriT;+B z7E6b+$TyI!04GNR2MJEh%*_0*=@8S?(;vI8`&t|m4D2O5qR*ou1C5Q1wx&bmw}9X7 zVNxzL#9zXTd@*R$>Ej_H^~1B9#BKP0_FL%nJL_y|ptm(JydPidAX4a_Zme10meKCdb4mpRR91007*qoM6N<$f-x0vKmY&$ diff --git a/docfx.json b/docfx.json deleted file mode 100644 index 2f76eb8..0000000 --- a/docfx.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "metadata": [ - { - "src": [ - { - "files": [ "src/**/*.csproj" ], - "exclude": [ "**/obj/**", "**/bin/**" ], - "properties": { - "TargetFrameworks": "netstandard2.0;netstandard2.1", - "OutputPaths": [ - "bin/Release/netstandard2.0", - "bin/Release/netstandard2.1" - ] - }, - "codeProjectProperties": { - "ProjectReferences": [ - { - "ProjectPath": "**/*.csproj" - } - ] - } - } - ], - "dest": "api" - } - ], - "build": { - "content": [ - { - "files": "**/*.yml" - }, - { - "files": "README.md" - } - ], - "globalMetadata": { - "_appName": "Kampute.HttpClient .NET Library", - "_appTitle": "Kampute.HttpClient .NET Library", - "_appFooter": "© 2024 Kampute", - "_appFaviconPath": "ICON.png", - "_appLogoPath": "ICON.png", - "_disableContribution": true, - "_disableNavbar": true, - "_disableNewTab": true - }, - "sitemap": { - "baseUrl": "https://kampute.github.io/http-client" - }, - "template": [ "default", "modern" ], - "dest": "docs" - } -} diff --git a/kampose.json b/kampose.json new file mode 100644 index 0000000..57f268e --- /dev/null +++ b/kampose.json @@ -0,0 +1,40 @@ +{ + "convention": "docfx", + "outputDirectory": ".site", + "audit": { + "options": [ + "recommended" + ], + "stopOnIssues": true + }, + "assemblies": [ + "src/**/bin/Release/netstandard2.1/*.dll" + ], + "assets": [ + { + "source": [ + "LICENSE", + "logo-dark.png", + "logo-light.png" + ] + } + ], + "references": [ + { + "namespaces": [ + "Newtonsoft.Json.*" + ], + "strategy": "onlineSearch", + "url": "https://www.phind.com/search/" + } + ], + "theme": "classic", + "themeSettings": { + "projectName": "Kampute.HttpClient", + "projectSlogan": "A lightweight .NET library that simplifies RESTful API communication.", + "projectLogoLightUri": "logo-dark.png", + "projectLogoDarkUri": "logo-light.png", + "faviconUri": "logo-dark.png", + "pageFooter": "- Copyright © {{now 'yyyy'}} [Kampute](https://kampute.com/)\n- Site built with [Kampose](https://kampute.github.io/kampose/)." + } +} diff --git a/logo-dark.png b/logo-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..48ed448374ef4853ca37ed140ea03d96cf86b48e GIT binary patch literal 994 zcmV<810DQ{P)?7$zgd*rgv8|6Lhnfd;|`R1EVS=n0q-7Bu%gt|tJFf%OIB{&YP8zK6a^7r>JUwIKj5;va?yKP1iJ+2+n; z`vo&MEYDDz$xmsI9Z?RYDo;CdY0j&;=LDu5!kWB~9! zL%QeLSg3;=6enrS@w)j(8xW$aAmbGPXau`}567ZM5pHt{VUp&|@#+ zC)L6kmLY}WD>f-k`O*>W<5A?1sE*-B2r~yCuggW7s{m;!2!;#Zm`K=Y=sTxKgdGrm zsXt5FJ8u*ehtF&}{FP11ttFXbvwEx*Or3L%@i~dz#}GRY;xu`)lz9hpn1GWodz~LE z%PV)43}CTXS{)XK*lMgY#DuncZ(1_ z`(0k)I+!;P{ryD)z~Z)S00_7M0MDWSi3WmUn9Q2SzXgEL4-oJU^gq)=fPTPn9xE6? zt$~$Cpaz8JYk=qifF&9ToP%*-&Bc-dP;R#ypJzdbwX>#za5|j`LH}Wb$t}46+V2;T z3H2WhK?;R{{;i?_G@}{F%=Vml9T=Df0_AeK@Yw_LjQ^Y<@QDln28UfQz}@!i%sp2K zgq8`Vs;a777a(&BGDQSCKWYRFRnrdHMb-vhv5>y+1*6*27n zu5EUO*crc6ol9I$V5)qs3S4Ulz$#=PKj?`u3VCGJxT;6o#f9ZQHYCN_0hy`_Nh<_v zsPm~i6+mNFqWvJAIuEo2okz~^aynX z$Q@&V$KqN3d7Vn^9Q078S8yAq+$ZcobLX=<3gEc0v0$E$)*;|$xZi3BU=Iqd2!KJ{ z6F21sq_0@pY;&eptYjndlx1^#sj&Q!35b=ZJ)j3r17FlrCP0RF28FfD<_`{_`6o-} zpqiKU_#)$MkFX=NhamtEwk!i^s)hQ(^LDl29=a;Hh&;&`V9ti65x(2CS)W1c0AQjv zq(W|ST?eJljVXuNKF`MN5?Tg;V?!MwNS|Ngxv=!sk~wrco(gEVE?cLq zJXZr711O|91Ayll(mluc1uxrA#;lm*apQ;T5u(HF_?iQt5xfO_I2P@Sc#jQ=V^(U8 zM;DtGVsDz6n*u=a8MSdDGNh19Fd;JTjC$}MOOZoFox_h1W)41H*YcU014Jbk7%n*c zgfc!M$tn_M`otym>ZCn$_&@>p%tqb6n5f)h#oQENQrFGL zW+U&Swvqvo$z)49nWm{ks&J)J(-6;;1OS_yOQ+MgSw_D>i@M*2(&FYohe`ox%>q~e zy#mb^0D&;M1&002ovPDHLk FV1i@3pv3?H literal 0 HcmV?d00001 From c51d8a149bc5dc44b93b5511ef3e80dc34eeab4e Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 16:39:52 +0800 Subject: [PATCH 05/13] Update README file --- README.md | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index cac4b75..8ff587c 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,10 @@ -# Kampute.HttpClient - -[![Release](https://img.shields.io/github/v/release/kampute/http-client)](https://github.com/kampute/http-client/releases/latest) -[![Build](https://github.com/kampute/http-client/actions/workflows/main.yml/badge.svg?branch=master)](https://github.com/kampute/http-client/actions/workflows/main.yml) +# Welcome to HttpClient `Kampute.HttpClient` is a .NET library designed to simplify HTTP communication with RESTful APIs by enhancing the native `HttpClient` capabilities. Tailored for developers seeking a potent yet flexible HTTP client for API integration within .NET applications, it combines ease of use with a wide array of functionalities to address the complexities of web service consumption. -[Explore the API documentation](https://kampute.github.io/http-client/api/Kampute.HttpClient.html) for detailed insights. +[Explore the API documentation](https://kampute.github.io/http-client/api/) for detailed insights. ## Key Features @@ -56,20 +53,20 @@ to address the complexities of web service consumption. By default, `Kampute.HttpClient` does not include any content deserializer. To accommodate popular content types, the following extension packages are available: -- **[Kampute.HttpClient.Json](https://www.nuget.org/packages/Kampute.HttpClient.Json)**: +- **[Kampute.HttpClient.Json](https://kampute.github.io/http-client/api/Kampute.HttpClient.Json)**: Utilizes the `System.Text.Json` library for handling JSON content types, offering high-performance serialization and deserialization that integrates tightly with the .NET ecosystem. -- **[Kampute.HttpClient.NewtonsoftJson](https://www.nuget.org/packages/Kampute.HttpClient.NewtonsoftJson)**: +- **[Kampute.HttpClient.NewtonsoftJson](https://kampute.github.io/http-client/api/Kampute.HttpClient.NewtonsoftJson)**: Leverages the `Newtonsoft.Json` library for handling JSON content types, providing extensive customization options and compatibility with a vast number of JSON features and formats. -- **[Kampute.HttpClient.Xml](https://www.nuget.org/packages/Kampute.HttpClient.Xml)**: +- **[Kampute.HttpClient.Xml](https://kampute.github.io/http-client/api/Kampute.HttpClient.Xml)**: Employs the `XmlSerializer` for handling XML content types, enabling straightforward serialization and deserialization of XML into .NET objects using custom class structures. -- **[Kampute.HttpClient.DataContract](https://www.nuget.org/packages/Kampute.HttpClient.DataContract)**: - Utilizes the `DataContractSerializer` for handling XML content types, focusing on serialization and deserialization of .NET objects into XML based on data contract +- **[Kampute.HttpClient.DataContract](https://kampute.github.io/http-client/api/Kampute.HttpClient.DataContract)**: + Utilizes the `DataContractSerializer` for handling XML content types, focusing on serialization and deserialization of .NET objects into XML based on data contract attributes for fine-grained control over the XML output. For scenarios where the provided serialization packages do not meet specific requirements, `Kampute.HttpClient` allows the implementation of custom deserializers. @@ -153,7 +150,7 @@ var csv = await client Similar to headers, you can also scope request properties. This capability is invaluable in scenarios where you need to maintain state or context-specific information temporarily during a series of HTTP operations. Scoped properties work similarly to scoped headers, allowing developers to define temporary data attached to requests that are automatically -cleared once the scope is exited. This feature enhances the adaptability of your HTTP interactions, especially in complex or state-dependent communication scenarios. +cleared once the scope is exited. This feature enhances the adaptability of your HTTP interactions, especially in complex or state-dependent communication scenarios. ### Custom Retry Strategies @@ -168,7 +165,7 @@ using Kampute.HttpClient; using var client = new HttpRestClient(); // Configure the client's retry mechanism. -// The Fibonacci strategy will retry up to 5 times +// The Fibonacci strategy will retry up to 5 times // with an initial delay of 1 second between retries // and delay increases following the Fibonacci sequence for subsequent retries. client.BackoffStrategy = BackoffStrategies.Fibonacci(maxAttempts: 5, initialDelay: TimeSpan.FromSeconds(1)); @@ -187,7 +184,7 @@ using Kampute.HttpClient.ErrorHandlers; // This handler defines the logic to handle unauthorized responses. using var unauthorizedErrorHandler = new HttpError401Handler(async (client, challenges, cancellationToken) => { - // In this example, we're handling the unauthorized error by making a POST request to an + // In this example, we're handling the unauthorized error by making a POST request to an // authentication endpoint to obtain a new authentication token. var auth = await client.PostAsFormAsync("https://api.example.com/auth", [ @@ -251,15 +248,20 @@ await client.PostAsXmlAsync("https://api.example.com/resource", newResource); ## Documentation -Explore the `Kampute.HttpClient` library's [API Documentation](https://kampute.github.io/http-client/api/Kampute.HttpClient.html) for an in-depth understanding of its +Explore the `Kampute.HttpClient` library's [API Documentation](https://kampute.github.io/http-client/api/) for an in-depth understanding of its functionalities. You'll find detailed class references, method signatures, and descriptions of properties to guide your implementation and leverage the library's full potential. ## Contributing -Contributions are welcomed! Please feel free to fork the repository, make changes, and submit pull requests. For major changes or new features, please open an issue -first to discuss what you would like to change. +Contributions welcome! Please follow the existing coding and documentation conventions to maintain consistency across the codebase. + +1. Fork the repository +2. Create a feature branch: `git checkout -b feature-name` +3. Commit changes: `git commit -m 'Add feature'` +4. Push branch: `git push origin feature-name` +5. Open a pull request ## License -`Kampute.HttpClient` is licensed under the terms of the MIT license. See the [LICENSE](LICENSE) file for more details. +Licensed under the [MIT License](LICENSE). From 8ea202067e5f3f4235b1f06c94997f87add7ee22 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 16:46:11 +0800 Subject: [PATCH 06/13] Disable package generation on build for all projects --- .../Kampute.HttpClient.DataContract.csproj | 2 +- src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj | 2 +- .../Kampute.HttpClient.NewtonsoftJson.csproj | 2 +- src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj | 4 ++-- src/Kampute.HttpClient/Kampute.HttpClient.csproj | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj b/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj index f94f6e0..cc27356 100644 --- a/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj +++ b/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj @@ -13,7 +13,7 @@ true snupkg true - true + false Kampute.HttpClient.DataContract http http-client restful rest-client rest-api web-api xml ICON.png diff --git a/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj b/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj index bfb5fea..328fe0a 100644 --- a/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj +++ b/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj @@ -13,7 +13,7 @@ true snupkg true - true + false Kampute.HttpClient.Json http http-client restful rest-client rest-api web-api json ICON.png diff --git a/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj b/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj index dd8c800..59b11fd 100644 --- a/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj +++ b/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj @@ -13,7 +13,7 @@ true snupkg true - true + false Kampute.HttpClient.NewtonsoftJson http http-client restful rest-client rest-api web-api json ICON.png diff --git a/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj b/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj index 522c3df..43cdd4d 100644 --- a/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj +++ b/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj @@ -13,13 +13,13 @@ true snupkg true - true + false Kampute.HttpClient.Xml http http-client restful rest-client rest-api web-api xml ICON.png README.md LICENSE - For detailed release notes, please visit https://github.com/kampute/http-client/releases + For detailed release notes, please visit https://github.com/kampute/http-client/releases https://kampute.github.io/http-client/ https://github.com/kampute/http-client.git git diff --git a/src/Kampute.HttpClient/Kampute.HttpClient.csproj b/src/Kampute.HttpClient/Kampute.HttpClient.csproj index 6d63377..927ac46 100644 --- a/src/Kampute.HttpClient/Kampute.HttpClient.csproj +++ b/src/Kampute.HttpClient/Kampute.HttpClient.csproj @@ -13,7 +13,7 @@ true snupkg true - true + false true Kampute.HttpClient http http-client restful rest-client rest-api web-api From 9d5cb8f522d871861a59b3f68842eff284881497 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 17:17:28 +0800 Subject: [PATCH 07/13] Add NamespaceDoc for documenting namespaces --- src/Kampute.HttpClient.DataContract/NamespaceDoc.cs | 13 +++++++++++++ src/Kampute.HttpClient.Json/NamespaceDoc.cs | 13 +++++++++++++ .../NamespaceDoc.cs | 13 +++++++++++++ src/Kampute.HttpClient.Xml/NamespaceDoc.cs | 13 +++++++++++++ .../Content/Abstracts/NamespaceDoc.cs | 13 +++++++++++++ .../Content/Compression/Abstracts/NamespaceDoc.cs | 12 ++++++++++++ .../Content/Compression/NamespaceDoc.cs | 12 ++++++++++++ src/Kampute.HttpClient/Content/NamespaceDoc.cs | 12 ++++++++++++ .../ErrorHandlers/NamespaceDoc.cs | 12 ++++++++++++ src/Kampute.HttpClient/Interfaces/NamespaceDoc.cs | 12 ++++++++++++ src/Kampute.HttpClient/NamespaceDoc.cs | 12 ++++++++++++ .../RetryManagement/NamespaceDoc.cs | 13 +++++++++++++ .../Strategies/Modifiers/NamespaceDoc.cs | 12 ++++++++++++ .../RetryManagement/Strategies/NamespaceDoc.cs | 12 ++++++++++++ src/Kampute.HttpClient/Utilities/NamespaceDoc.cs | 13 +++++++++++++ 15 files changed, 187 insertions(+) create mode 100644 src/Kampute.HttpClient.DataContract/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient.Json/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient.NewtonsoftJson/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient.Xml/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/Content/Abstracts/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/Content/Compression/Abstracts/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/Content/Compression/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/Content/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/ErrorHandlers/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/Interfaces/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/RetryManagement/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/RetryManagement/Strategies/Modifiers/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/RetryManagement/Strategies/NamespaceDoc.cs create mode 100644 src/Kampute.HttpClient/Utilities/NamespaceDoc.cs diff --git a/src/Kampute.HttpClient.DataContract/NamespaceDoc.cs b/src/Kampute.HttpClient.DataContract/NamespaceDoc.cs new file mode 100644 index 0000000..af65811 --- /dev/null +++ b/src/Kampute.HttpClient.DataContract/NamespaceDoc.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.DataContract +{ + /// + /// This namespace provides support for DataContract serialization in HTTP requests and responses, + /// specifically for handling application/xml content types using the DataContractSerializer. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient.Json/NamespaceDoc.cs b/src/Kampute.HttpClient.Json/NamespaceDoc.cs new file mode 100644 index 0000000..084c71f --- /dev/null +++ b/src/Kampute.HttpClient.Json/NamespaceDoc.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Json +{ + /// + /// This namespace provides support for JSON serialization in HTTP requests and responses, + /// specifically for handling application/json content types using System.Text.Json. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient.NewtonsoftJson/NamespaceDoc.cs b/src/Kampute.HttpClient.NewtonsoftJson/NamespaceDoc.cs new file mode 100644 index 0000000..6af8af3 --- /dev/null +++ b/src/Kampute.HttpClient.NewtonsoftJson/NamespaceDoc.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.NewtonsoftJson +{ + /// + /// This namespace provides support for JSON serialization in HTTP requests and responses, + /// specifically for handling application/json content types using Newtonsoft.Json. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient.Xml/NamespaceDoc.cs b/src/Kampute.HttpClient.Xml/NamespaceDoc.cs new file mode 100644 index 0000000..e04ff5e --- /dev/null +++ b/src/Kampute.HttpClient.Xml/NamespaceDoc.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Xml +{ + /// + /// This namespace provides support for XML serialization in HTTP requests and responses, + /// specifically for handling application/xml content types using the XmlSerializer. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/Content/Abstracts/NamespaceDoc.cs b/src/Kampute.HttpClient/Content/Abstracts/NamespaceDoc.cs new file mode 100644 index 0000000..339a989 --- /dev/null +++ b/src/Kampute.HttpClient/Content/Abstracts/NamespaceDoc.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Content.Abstracts +{ + /// + /// This namespace contains abstract classes for HTTP content + /// deserialization and decoration. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/Content/Compression/Abstracts/NamespaceDoc.cs b/src/Kampute.HttpClient/Content/Compression/Abstracts/NamespaceDoc.cs new file mode 100644 index 0000000..97f16df --- /dev/null +++ b/src/Kampute.HttpClient/Content/Compression/Abstracts/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Content.Compression.Abstracts +{ + /// + /// This namespace contains abstract base classes for compressed content. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/Content/Compression/NamespaceDoc.cs b/src/Kampute.HttpClient/Content/Compression/NamespaceDoc.cs new file mode 100644 index 0000000..8eff1fd --- /dev/null +++ b/src/Kampute.HttpClient/Content/Compression/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Content.Compression +{ + /// + /// This namespace provides classes for compressing HTTP content. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/Content/NamespaceDoc.cs b/src/Kampute.HttpClient/Content/NamespaceDoc.cs new file mode 100644 index 0000000..f3c416d --- /dev/null +++ b/src/Kampute.HttpClient/Content/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Content +{ + /// + /// This namespace contains classes for handling HTTP content. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/ErrorHandlers/NamespaceDoc.cs b/src/Kampute.HttpClient/ErrorHandlers/NamespaceDoc.cs new file mode 100644 index 0000000..5c8f3f2 --- /dev/null +++ b/src/Kampute.HttpClient/ErrorHandlers/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.ErrorHandlers +{ + /// + /// This namespace contains classes for handling specific HTTP error responses. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/Interfaces/NamespaceDoc.cs b/src/Kampute.HttpClient/Interfaces/NamespaceDoc.cs new file mode 100644 index 0000000..eb400b5 --- /dev/null +++ b/src/Kampute.HttpClient/Interfaces/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Interfaces +{ + /// + /// This namespace defines interfaces used throughout the library. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/NamespaceDoc.cs b/src/Kampute.HttpClient/NamespaceDoc.cs new file mode 100644 index 0000000..94d260d --- /dev/null +++ b/src/Kampute.HttpClient/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient +{ + /// + /// This namespace contains classes and methods for making HTTP requests and handling responses. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/RetryManagement/NamespaceDoc.cs b/src/Kampute.HttpClient/RetryManagement/NamespaceDoc.cs new file mode 100644 index 0000000..00a547d --- /dev/null +++ b/src/Kampute.HttpClient/RetryManagement/NamespaceDoc.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.RetryManagement +{ + /// + /// This namespace provides classes and interfaces for managing retry + /// logic and backoff strategies in HTTP requests. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/RetryManagement/Strategies/Modifiers/NamespaceDoc.cs b/src/Kampute.HttpClient/RetryManagement/Strategies/Modifiers/NamespaceDoc.cs new file mode 100644 index 0000000..fa8289b --- /dev/null +++ b/src/Kampute.HttpClient/RetryManagement/Strategies/Modifiers/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.RetryManagement.Strategies.Modifiers +{ + /// + /// This namespace provides modifiers that can be applied to retry strategies to alter their behavior. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/RetryManagement/Strategies/NamespaceDoc.cs b/src/Kampute.HttpClient/RetryManagement/Strategies/NamespaceDoc.cs new file mode 100644 index 0000000..afee57f --- /dev/null +++ b/src/Kampute.HttpClient/RetryManagement/Strategies/NamespaceDoc.cs @@ -0,0 +1,12 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.RetryManagement.Strategies +{ + /// + /// This namespace contains implementations of various retry strategies for HTTP requests. + /// + internal static class NamespaceDoc { } +} diff --git a/src/Kampute.HttpClient/Utilities/NamespaceDoc.cs b/src/Kampute.HttpClient/Utilities/NamespaceDoc.cs new file mode 100644 index 0000000..bd7de8f --- /dev/null +++ b/src/Kampute.HttpClient/Utilities/NamespaceDoc.cs @@ -0,0 +1,13 @@ +// Copyright (C) 2024 Kampute +// +// This file is part of the Kampute.HttpClient package and is released under the terms of the MIT license. +// See the LICENSE file in the project root for the full license text. + +namespace Kampute.HttpClient.Utilities +{ + /// + /// This namespace contains utility classes and extensions for managing + /// shared resources, caching, and asynchronous operations. + /// + internal static class NamespaceDoc { } +} From 34260c9572da8b1ffc359310bbb534e80d142d9a Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 17:18:24 +0800 Subject: [PATCH 08/13] Add missing tags for properties --- src/Kampute.HttpClient/BackoffStrategies.cs | 11 +++++---- .../Content/Abstracts/HttpContentDecorator.cs | 3 ++- .../ErrorHandlers/HttpError429Handler.cs | 20 +++++++++------- .../ErrorHandlers/HttpError503Handler.cs | 23 +++++++++++-------- .../RetryManagement/BackoffStrategy.cs | 1 + 5 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/Kampute.HttpClient/BackoffStrategies.cs b/src/Kampute.HttpClient/BackoffStrategies.cs index 8de22ec..e57fdf4 100644 --- a/src/Kampute.HttpClient/BackoffStrategies.cs +++ b/src/Kampute.HttpClient/BackoffStrategies.cs @@ -47,8 +47,8 @@ namespace Kampute.HttpClient /// /// /// - /// The Dynamic strategy stands apart, as its delay can vary based on the context of the failure. It tailors retry attempts to specific conditions, such - /// as error type or system load, offering the flexibility to adapt retry logic for optimal outcomes. This approach is most useful in complex systems where a + /// The Dynamic strategy stands apart, as its delay can vary based on the context of the failure. It tailors retry attempts to specific conditions, such + /// as error type or system load, offering the flexibility to adapt retry logic for optimal outcomes. This approach is most useful in complex systems where a /// static retry strategy may not adequately address the nuances of different failure scenarios. /// /// @@ -85,7 +85,7 @@ public static IHttpBackoffProvider Once(TimeSpan delay) /// The date and time after which the single retry attempt will be made. /// An that defines a retry strategy of a single attempt after a specified date and time. /// - /// This strategy schedules a single retry attempt for a specified future point in time, ensuring operations are retried when certain + /// This strategy schedules a single retry attempt for a specified future point in time, ensuring operations are retried when certain /// conditions are likely met. If the specified time has already passed, it immediately schedules the retry attempt. /// public static IHttpBackoffProvider Once(DateTimeOffset after) @@ -114,6 +114,7 @@ public static IHttpBackoffProvider Uniform(uint maxAttempts, TimeSpan delay) /// /// The maximum time to spend retrying. /// The constant delay between each retry attempt. + /// An that defines a retry strategy of multiple attempts with a constant delay between each attempt, up to a specified timeout. /// /// This strategy performs multiple retry attempts with a constant delay between each attempt, up to a specified timeout. It is ideal for cases needing /// multiple attempts with predictable delays, but with a maximum time limit for retrying. @@ -294,7 +295,7 @@ public static IHttpBackoffProvider Fibonacci(TimeSpan timeout, TimeSpan initialD /// An instance of . /// Thrown if is . /// - /// This strategy offers the highest flexibility by dynamically scheduling retries based on the specific context of a failure. It adapts to the nature of + /// This strategy offers the highest flexibility by dynamically scheduling retries based on the specific context of a failure. It adapts to the nature of /// encountered errors, making it ideal for complex systems with varied types of transient failures that cannot be effectively handled by a static retry strategy. /// public static IHttpBackoffProvider Dynamic(Func strategyFactory) @@ -309,7 +310,7 @@ public static IHttpBackoffProvider Dynamic(FuncAn instance of . /// Thrown if is . /// - /// This strategy offers the highest flexibility by dynamically scheduling retries based on the specific context of a failure. It adapts to the nature of + /// This strategy offers the highest flexibility by dynamically scheduling retries based on the specific context of a failure. It adapts to the nature of /// encountered errors, making it ideal for complex systems with varied types of transient failures that cannot be effectively handled by a static retry strategy. /// public static IHttpBackoffProvider Dynamic(Func schedulerFactory) diff --git a/src/Kampute.HttpClient/Content/Abstracts/HttpContentDecorator.cs b/src/Kampute.HttpClient/Content/Abstracts/HttpContentDecorator.cs index 69d301a..0adfa7b 100644 --- a/src/Kampute.HttpClient/Content/Abstracts/HttpContentDecorator.cs +++ b/src/Kampute.HttpClient/Content/Abstracts/HttpContentDecorator.cs @@ -4,7 +4,7 @@ using System.Net.Http; /// - /// Serves as a base class for decorating instances. + /// Serves as a base class for decorating instances. /// /// /// This class provides common functionality such as copying headers from the original content and managing the lifecycle of the wrapped content. @@ -26,6 +26,7 @@ protected HttpContentDecorator(HttpContent content) /// /// Gets the original HTTP content that this instance decorates. /// + /// The original instance. protected internal HttpContent OriginalContent { get; } /// diff --git a/src/Kampute.HttpClient/ErrorHandlers/HttpError429Handler.cs b/src/Kampute.HttpClient/ErrorHandlers/HttpError429Handler.cs index 34da3db..b0ae86c 100644 --- a/src/Kampute.HttpClient/ErrorHandlers/HttpError429Handler.cs +++ b/src/Kampute.HttpClient/ErrorHandlers/HttpError429Handler.cs @@ -12,13 +12,13 @@ namespace Kampute.HttpClient.ErrorHandlers using System.Threading.Tasks; /// - /// Handles '429 Too Many Requests' HTTP responses by attempting to back off and retry the request according to a specified or + /// Handles '429 Too Many Requests' HTTP responses by attempting to back off and retry the request according to a specified or /// default backoff strategy. /// /// - /// This handler provides a mechanism to respond to HTTP 429 errors by retrying the request after a delay. The delay duration and - /// retry logic can be customized through the delegate. If the delegate is not provided, or does not - /// specify a strategy, the handler will look for a rate limit reset header in the response. If the header is present, its value is + /// This handler provides a mechanism to respond to HTTP 429 errors by retrying the request after a delay. The delay duration and + /// retry logic can be customized through the delegate. If the delegate is not provided, or does not + /// specify a strategy, the handler will look for a rate limit reset header in the response. If the header is present, its value is /// used to determine the backoff duration. If the header is not present, no retries will be attempted. /// /// @@ -27,9 +27,13 @@ public class HttpError429Handler : IHttpErrorHandler /// /// A delegate that allows customization of the backoff strategy when a 429 Too Many Requests' response is received. /// + /// + /// A function that takes an and an optional representing + /// the rate limit reset time, and returns an to define the backoff strategy. + /// /// /// - /// If this delegate is set and returns an , the returned strategy is used for the retry operation. + /// If this delegate is set and returns an , the returned strategy is used for the retry operation. /// If it is not set, or returns , the handler will defer to the Retry-After header in the response. /// /// @@ -45,7 +49,7 @@ public class HttpError429Handler : IHttpErrorHandler /// /// resetTime /// - /// Indicates the time when the rate limit will be lifted as a value. If the server specifies + /// Indicates the time when the rate limit will be lifted as a value. If the server specifies /// a reset time via response headers, this parameter provides that time, allowing the client to know when to resume requests. /// If the server does not specify a reset time, the value will be . /// @@ -77,8 +81,8 @@ public bool CanHandle(HttpStatusCode statusCode) => /// An that schedules the retry attempts. /// Thrown if is . /// - /// This method first attempts to use the delegate to obtain a retry strategy. If the delegate is not - /// provided or returns , and a rate limit reset header is present, the value of this header is used to create a retry delay. + /// This method first attempts to use the delegate to obtain a retry strategy. If the delegate is not + /// provided or returns , and a rate limit reset header is present, the value of this header is used to create a retry delay. /// If neither condition is met, no retries will be attempted. /// protected virtual IRetryScheduler? CreateScheduler(HttpResponseErrorContext ctx) diff --git a/src/Kampute.HttpClient/ErrorHandlers/HttpError503Handler.cs b/src/Kampute.HttpClient/ErrorHandlers/HttpError503Handler.cs index dbc0a2b..4c1ae5e 100644 --- a/src/Kampute.HttpClient/ErrorHandlers/HttpError503Handler.cs +++ b/src/Kampute.HttpClient/ErrorHandlers/HttpError503Handler.cs @@ -12,14 +12,14 @@ namespace Kampute.HttpClient.ErrorHandlers using System.Threading.Tasks; /// - /// Handles '503 Service Unavailable' HTTP responses by attempting to back off and retry the request according to a specified or + /// Handles '503 Service Unavailable' HTTP responses by attempting to back off and retry the request according to a specified or /// default backoff strategy. /// /// - /// This handler provides a mechanism to respond to HTTP 503 errors by retrying the request after a delay. The delay duration and - /// retry logic can be customized through the delegate. If the delegate is not provided, or does not - /// specify a strategy, the handler will look for a Retry-After header in the response. If the Retry-After header is - /// present, its value is used to determine the backoff duration. If the header is not present, the default backoff strategy of the + /// This handler provides a mechanism to respond to HTTP 503 errors by retrying the request after a delay. The delay duration and + /// retry logic can be customized through the delegate. If the delegate is not provided, or does not + /// specify a strategy, the handler will look for a Retry-After header in the response. If the Retry-After header is + /// present, its value is used to determine the backoff duration. If the header is not present, the default backoff strategy of the /// is used. /// /// @@ -29,10 +29,15 @@ public class HttpError503Handler : IHttpErrorHandler /// /// A delegate that allows customization of the backoff strategy when a '503 Service Unavailable' response is received. /// + /// + /// A function that takes an and an optional representing + /// the suggested retry time from the Retry-After header, and returns an to be used + /// for the retry operation. + /// /// /// - /// If this delegate is set and returns an , the returned strategy is used for the retry operation. - /// If it is not set, or returns , the handler will defer to the Retry-After header in the response or the + /// If this delegate is set and returns an , the returned strategy is used for the retry operation. + /// If it is not set, or returns , the handler will defer to the Retry-After header in the response or the /// client's default backoff strategy. /// /// @@ -75,8 +80,8 @@ public class HttpError503Handler : IHttpErrorHandler /// An that schedules the retry attempts. /// Thrown if is . /// - /// This method first attempts to use the delegate to obtain a retry strategy. If the delegate is not - /// provided or returns , and a Retry-After header is present, the value of this header is used to create a retry + /// This method first attempts to use the delegate to obtain a retry strategy. If the delegate is not + /// provided or returns , and a Retry-After header is present, the value of this header is used to create a retry /// delay. If neither condition is met, the client's default backoff strategy is utilized. /// protected virtual IRetryScheduler? CreateScheduler(HttpResponseErrorContext ctx) diff --git a/src/Kampute.HttpClient/RetryManagement/BackoffStrategy.cs b/src/Kampute.HttpClient/RetryManagement/BackoffStrategy.cs index fb67d44..864d0be 100644 --- a/src/Kampute.HttpClient/RetryManagement/BackoffStrategy.cs +++ b/src/Kampute.HttpClient/RetryManagement/BackoffStrategy.cs @@ -32,6 +32,7 @@ public BackoffStrategy(IRetryStrategy strategy) /// /// Gets the retry strategy associated with this scheduler factory. /// + /// The used by schedulers created by this factory. public virtual IRetryStrategy Strategy { get; } /// From ed973ea9e79ff9ae689f2c2ef2328302007869bc Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 17:23:18 +0800 Subject: [PATCH 09/13] Update test project dependencies to latest versions --- .../Kampute.HttpClient.DataContract.Test.csproj | 12 ++++++------ .../Kampute.HttpClient.Json.Test.csproj | 12 ++++++------ .../Kampute.HttpClient.NewtonsoftJson.Test.csproj | 12 ++++++------ .../Kampute.HttpClient.Test.csproj | 12 ++++++------ .../Kampute.HttpClient.Xml.Test.csproj | 12 ++++++------ 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/Kampute.HttpClient.DataContract.Test/Kampute.HttpClient.DataContract.Test.csproj b/tests/Kampute.HttpClient.DataContract.Test/Kampute.HttpClient.DataContract.Test.csproj index aac1829..668c46e 100644 --- a/tests/Kampute.HttpClient.DataContract.Test/Kampute.HttpClient.DataContract.Test.csproj +++ b/tests/Kampute.HttpClient.DataContract.Test/Kampute.HttpClient.DataContract.Test.csproj @@ -10,15 +10,15 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Kampute.HttpClient.Json.Test/Kampute.HttpClient.Json.Test.csproj b/tests/Kampute.HttpClient.Json.Test/Kampute.HttpClient.Json.Test.csproj index 74348e5..35c8533 100644 --- a/tests/Kampute.HttpClient.Json.Test/Kampute.HttpClient.Json.Test.csproj +++ b/tests/Kampute.HttpClient.Json.Test/Kampute.HttpClient.Json.Test.csproj @@ -10,15 +10,15 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Kampute.HttpClient.NewtonsoftJson.Test/Kampute.HttpClient.NewtonsoftJson.Test.csproj b/tests/Kampute.HttpClient.NewtonsoftJson.Test/Kampute.HttpClient.NewtonsoftJson.Test.csproj index ac27e64..71a95d2 100644 --- a/tests/Kampute.HttpClient.NewtonsoftJson.Test/Kampute.HttpClient.NewtonsoftJson.Test.csproj +++ b/tests/Kampute.HttpClient.NewtonsoftJson.Test/Kampute.HttpClient.NewtonsoftJson.Test.csproj @@ -10,15 +10,15 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Kampute.HttpClient.Test/Kampute.HttpClient.Test.csproj b/tests/Kampute.HttpClient.Test/Kampute.HttpClient.Test.csproj index cd846c8..9b7c31b 100644 --- a/tests/Kampute.HttpClient.Test/Kampute.HttpClient.Test.csproj +++ b/tests/Kampute.HttpClient.Test/Kampute.HttpClient.Test.csproj @@ -10,15 +10,15 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/tests/Kampute.HttpClient.Xml.Test/Kampute.HttpClient.Xml.Test.csproj b/tests/Kampute.HttpClient.Xml.Test/Kampute.HttpClient.Xml.Test.csproj index e15107e..abb1ef8 100644 --- a/tests/Kampute.HttpClient.Xml.Test/Kampute.HttpClient.Xml.Test.csproj +++ b/tests/Kampute.HttpClient.Xml.Test/Kampute.HttpClient.Xml.Test.csproj @@ -10,15 +10,15 @@ - - - - - + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 2b9252885ecc702e7d49f6d817b3a6abccf15ba8 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 17:24:03 +0800 Subject: [PATCH 10/13] Update System.Text.Json package reference to version 8.0.6 --- src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj b/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj index 328fe0a..92e408d 100644 --- a/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj +++ b/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj @@ -36,7 +36,7 @@ - + From e6be40a02d8a6e4d0b53f44320bdc1355cb42953 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 17:40:41 +0800 Subject: [PATCH 11/13] Bump version to 2.3.2 for all projects --- .../Kampute.HttpClient.DataContract.csproj | 2 +- src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj | 2 +- .../Kampute.HttpClient.NewtonsoftJson.csproj | 2 +- src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj | 2 +- src/Kampute.HttpClient/Kampute.HttpClient.csproj | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj b/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj index cc27356..49f2bf2 100644 --- a/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj +++ b/src/Kampute.HttpClient.DataContract/Kampute.HttpClient.DataContract.csproj @@ -5,7 +5,7 @@ Kampute.HttpClient.DataContract This package is an extension package for Kampute.HttpClient, enhancing it to manage application/xml content types, using DataContractSerializer for serialization and deserialization of XML responses and payloads. Kambiz Khojasteh - 2.3.1 + 2.3.2 Kampute Copyright (c) 2024 Kampute latest diff --git a/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj b/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj index 92e408d..6806861 100644 --- a/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj +++ b/src/Kampute.HttpClient.Json/Kampute.HttpClient.Json.csproj @@ -5,7 +5,7 @@ Kampute.HttpClient.Json This package is an extension package for Kampute.HttpClient, enhancing it to manage application/json content types, using System.Text.Json library for serialization and deserialization of JSON responses and payloads. Kambiz Khojasteh - 2.3.1 + 2.3.2 Kampute Copyright (c) 2024 Kampute latest diff --git a/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj b/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj index 59b11fd..240db10 100644 --- a/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj +++ b/src/Kampute.HttpClient.NewtonsoftJson/Kampute.HttpClient.NewtonsoftJson.csproj @@ -5,7 +5,7 @@ Kampute.HttpClient.NewtonsoftJson This package is an extension package for Kampute.HttpClient, enhancing it to manage application/json content types, using Newtonsoft.Json library for serialization and deserialization of JSON responses and payloads. Kambiz Khojasteh - 2.3.1 + 2.3.2 Kampute Copyright (c) 2024 Kampute latest diff --git a/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj b/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj index 43cdd4d..30949cc 100644 --- a/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj +++ b/src/Kampute.HttpClient.Xml/Kampute.HttpClient.Xml.csproj @@ -5,7 +5,7 @@ Kampute.HttpClient.Xml This package is an extension package for Kampute.HttpClient, enhancing it to manage application/xml content types, using XmlSerializer for serialization and deserialization of XML responses and payloads. Kambiz Khojasteh - 2.3.1 + 2.3.2 Kampute Copyright (c) 2024 Kampute latest diff --git a/src/Kampute.HttpClient/Kampute.HttpClient.csproj b/src/Kampute.HttpClient/Kampute.HttpClient.csproj index 927ac46..8f3bd6e 100644 --- a/src/Kampute.HttpClient/Kampute.HttpClient.csproj +++ b/src/Kampute.HttpClient/Kampute.HttpClient.csproj @@ -5,7 +5,7 @@ Kampute.HttpClient Kampute.HttpClient is a versatile and lightweight .NET library that simplifies RESTful API communication. Its core HttpRestClient class provides a streamlined approach to HTTP interactions, offering advanced features such as flexible serialization/deserialization, robust error handling, configurable backoff strategies, and detailed request-response processing. Striking a balance between simplicity and extensibility, Kampute.HttpClient empowers developers with a powerful yet easy-to-use client for seamless API integration across a wide range of .NET applications. Kambiz Khojasteh - 2.3.1 + 2.3.2 Kampute Copyright (c) 2024 Kampute latest From 1081d346b5b951f79c66c8c92672a07c26ad4c4a Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 17:47:10 +0800 Subject: [PATCH 12/13] Add AI Coding Assistant instructions --- .github/copilot-instructions.md | 221 ++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 .github/copilot-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..9602363 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,221 @@ +# Kampute.HttpClient - AI Coding Assistant Instructions + +## Project Overview + +Kampute.HttpClient is a .NET library that enhances the native `HttpClient` for simplified RESTful API communication. It provides a modular, extensible architecture with shared connection pooling, scoped request customization, automatic content deserialization, and built-in retry strategies. + +## Architecture & Design Patterns + +### Core Components +- **`HttpRestClient`**: Main client class wrapping `HttpClient` with enhanced features +- **Extension Packages**: Modular serialization support (`Json`, `Xml`, `DataContract`, `NewtonsoftJson`) +- **Shared HttpClient**: Connection pooling via `SharedHttpClient` for efficient resource management +- **Scoped Collections**: `ScopedCollection` for temporary header/property overrides + +### Key Design Patterns +- **Fluent API**: Extension methods for HTTP verbs (`GetAsync`, `PostAsJsonAsync`, etc.) +- **Event-driven**: `BeforeSendingRequest`/`AfterReceivingResponse` events for interception +- **Strategy Pattern**: `IHttpBackoffProvider` for configurable retry logic +- **Factory Pattern**: `BackoffStrategies` for creating retry policies +- **Decorator Pattern**: `HttpRequestScope` for fluent request configuration + +### Request Flow +1. **Request Creation**: `CreateHttpRequest()` builds `HttpRequestMessage` with headers/properties +2. **Pre-processing**: `BeforeSendingRequest` event allows modification +3. **Dispatch**: `DispatchAsync()` sends via underlying `HttpClient` +4. **Retry Logic**: `DispatchWithRetriesAsync()` handles failures with backoff strategies +5. **Response Processing**: `DeserializeContentAsync()` converts response to .NET objects +6. **Post-processing**: `AfterReceivingResponse` event for inspection/logging + +## Critical Developer Workflows + +### Building & Testing +```bash +# Build solution +dotnet build -c Release + +# Run all tests +dotnet test --verbosity minimal + +# Run specific test project +dotnet test tests/Kampute.HttpClient.Test/ + +# Generate documentation +kampose build +``` + +### Adding New Features +1. **Core Features**: Modify `HttpRestClient.cs` and add tests in corresponding test file +2. **Extensions**: Create new package in `src/Kampute.HttpClient.*` with matching test project +3. **Serialization**: Implement `IHttpContentDeserializer` and add to `ResponseDeserializers` + +### Debugging Common Issues +- **Connection Pooling**: Use `SharedHttpClient` reference counting for proper disposal +- **Header Conflicts**: Scoped headers override defaults; avoid setting headers on underlying `HttpClient` +- **Serialization Failures**: Check `ResponseDeserializers` collection has appropriate deserializer +- **Retry Behavior**: Verify `BackoffStrategy` is set and `ErrorHandlers` are configured + +## Project-Specific Conventions + +### Code Style & Structure +- **Namespaces**: `Kampute.HttpClient` (core), `Kampute.HttpClient.*` (extensions) +- **Naming**: PascalCase for public APIs, consistent with .NET conventions +- **Documentation**: XML comments with ``, ``, and `` sections +- **Nullability**: `Nullable` enabled with proper `?` annotations +- **Async/Await**: Fully asynchronous APIs with `CancellationToken` support + +### Testing Patterns +- **Framework**: NUnit with Moq for mocking +- **Structure**: Test classes mirror source structure (`HttpRestClientTests.cs`) +- **Mocking**: `Mock` for HTTP interactions +- **Helpers**: `TestHelpers` namespace for shared test utilities +- **Coverage**: Comprehensive unit tests for all public APIs + +### Extension Package Pattern +```csharp +// Extension method pattern +public static class HttpRestClientJsonExtensions +{ + public static void AcceptJson(this HttpRestClient client) + { + client.ResponseDeserializers.Add(new JsonContentDeserializer()); + } + + public static Task PostAsJsonAsync(this HttpRestClient client, string uri, object payload) + { + return client.SendAsync(HttpVerb.Post, uri, CreateJsonContent(payload)); + } +} +``` + +### Error Handling +- **Exceptions**: `HttpResponseException` for HTTP errors, `HttpContentException` for deserialization failures +- **Custom Errors**: Implement `IHttpErrorResponse` for structured error responses +- **Retry Logic**: `IHttpErrorHandler` implementations for status-code specific handling +- **Logging**: Use request/response events for comprehensive logging + +### Configuration Management +- **Base Address**: Trailing slash handling in `BaseAddress` setter +- **Headers**: `DefaultRequestHeaders` vs scoped headers precedence +- **Accept Headers**: Auto-generated from `ResponseDeserializers` if not specified +- **Properties**: Request-scoped properties via `HttpRequestMessagePropertyKeys` + +## Integration Points + +### External Dependencies +- **Core**: `System.Net.Http` (native .NET) +- **JSON**: `System.Text.Json` or `Newtonsoft.Json` +- **XML**: `System.Runtime.Serialization` or `System.Xml.Serialization` +- **Testing**: NUnit, Moq, Microsoft.NET.Test.Sdk + +### Cross-Component Communication +- **Events**: `BeforeSendingRequest`/`AfterReceivingResponse` for observability +- **Scopes**: `BeginHeaderScope()`/`BeginPropertyScope()` for request customization +- **Extensions**: Fluent chaining via `HttpRequestScope.WithScope().SetHeader()...PerformAsync()` +- **Handlers**: `ErrorHandlers` collection for pluggable error handling + +## Key Files & Directories + +### Core Implementation +- `src/Kampute.HttpClient/HttpRestClient.cs` - Main client implementation +- `src/Kampute.HttpClient/HttpRestClientExtensions.cs` - HTTP verb extensions +- `src/Kampute.HttpClient/BackoffStrategies.cs` - Retry strategy factories +- `src/Kampute.HttpClient/Utilities/ScopedCollection.cs` - Scoped state management + +### Extension Packages +- `src/Kampute.HttpClient.Json/` - System.Text.Json integration +- `src/Kampute.HttpClient.Xml/` - XML serialization support +- `src/Kampute.HttpClient.DataContract/` - DataContractSerializer integration +- `src/Kampute.HttpClient.NewtonsoftJson/` - Newtonsoft.Json support + +### Testing +- `tests/Kampute.HttpClient.Test/` - Core functionality tests +- `tests/Kampute.HttpClient.Json.Test/` - JSON extension tests +- `TestHelpers/` - Shared testing utilities + +### Build & CI/CD +- `Kampute.HttpClient.sln` - Solution file +- `.github/workflows/main.yml` - GitHub Actions CI/CD +- `kampose.json` - Documentation generation config + +## Common Patterns & Examples + +### Basic Usage +```csharp +using var client = new HttpRestClient(); +client.AcceptJson(); // Add JSON deserializer + +var data = await client.GetAsync("https://api.example.com/data"); +``` + +### Scoped Configuration +```csharp +using var client = new HttpRestClient(); + +var result = await client + .WithScope() + .SetHeader("Authorization", $"Bearer {token}") + .SetProperty("CustomData", context) + .PerformAsync(scoped => scoped.GetAsync("endpoint")); +``` + +### Error Handling & Retry +```csharp +client.BackoffStrategy = BackoffStrategies.Fibonacci(maxAttempts: 5, initialDelay: TimeSpan.FromSeconds(1)); + +client.ErrorHandlers.Add(new HttpError401Handler(async (client, challenges, token) => { + var auth = await client.PostAsFormAsync("auth/refresh", new { refreshToken }); + return new AuthenticationHeaderValue("Bearer", auth.AccessToken); +})); +``` + +### Custom Serialization +```csharp +public class CustomDeserializer : IHttpContentDeserializer +{ + public bool CanDeserialize(string mediaType, Type objectType) => + mediaType == "application/custom" && objectType == typeof(CustomType); + + public Task DeserializeAsync(HttpContent content, Type objectType, CancellationToken token) => + // Custom deserialization logic +} + +client.ResponseDeserializers.Add(new CustomDeserializer()); +``` + +## Quality Assurance + +### Code Quality Checks +- **Build**: `dotnet build -c Release` ensures compilation +- **Tests**: `dotnet test` runs full test suite +- **Documentation**: `kampose build` generates API docs +- **Analysis**: Nullable reference types enabled for null safety + +### Performance Considerations +- **Connection Pooling**: Use `SharedHttpClient` for multiple client instances +- **Async Operations**: All I/O operations are fully asynchronous +- **Memory Management**: Proper `IDisposable` implementation with reference counting +- **Serialization**: Efficient deserialization with content-type matching + +### Security Best Practices +- **Header Injection**: Scoped headers prevent accidental global state changes +- **Authentication**: Built-in support for various auth schemes via error handlers +- **Cancellation**: `CancellationToken` support throughout async APIs +- **Error Handling**: Structured error responses prevent information leakage + +## Development Guidelines +- **SOLID principles**: Prioritize Single Responsibility and Open/Closed principles +- **Simplicity over complexity**: Avoid excessive helper methods and unnecessary abstractions +- **Self-documenting code**: Code should be readable without redundant inline comments +- **Interface pragmatism**: Use interfaces judiciously - avoid "Ravioli" (too many small interfaces) and "Lasagna" (too many layers) +- **Performance & clarity**: Optimize for both execution speed and code understanding +- **Problem-solving approach**: Question existing solutions, propose improvements, document limitations when needed + +## Documentation Guidelines +- Avoid promotional, flowery, or overly embellished language, and use adjectives and adverbs only when strictly necessary. +- Emphasize purpose and usage; do not document implementation details or obvious information. +- Provide meaningful context and call out important behavioral nuances or edge cases. +- Keep content concise and focused by using short sentences and brief paragraphs to convey information clearly. +- Organize content using bullet points, numbered lists, or tables when appropriate, and explain the context or purpose of the list or table in at least one paragraph. +- Numbered lists should be used for steps in a process or sequence only. +- When writing XML documentation comments, use appropriate XML tags for references, language keywords, and for organizing information in lists and tables. Ensure tags are used to clarify context, structure information, and improve readability for consumers of the documentation. From 593bb686f58866557d52feb6e40002edcaf243b3 Mon Sep 17 00:00:00 2001 From: Kambiz Khojasteh Date: Mon, 10 Nov 2025 18:06:40 +0800 Subject: [PATCH 13/13] Fix XML documentation issues --- src/Kampute.HttpClient.DataContract/XmlContent.cs | 2 +- src/Kampute.HttpClient.Json/JsonContent.cs | 2 +- src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs | 2 +- src/Kampute.HttpClient.Xml/XmlContent.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Kampute.HttpClient.DataContract/XmlContent.cs b/src/Kampute.HttpClient.DataContract/XmlContent.cs index 881e0a6..d0be6e5 100644 --- a/src/Kampute.HttpClient.DataContract/XmlContent.cs +++ b/src/Kampute.HttpClient.DataContract/XmlContent.cs @@ -93,7 +93,7 @@ protected override Task SerializeToStreamAsync(Stream stream, TransportContext c /// Attempts to compute the length of the content. /// /// When this method returns, contains the length of the content in bytes. - /// > if the length could be computed; otherwise, . + /// if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1; diff --git a/src/Kampute.HttpClient.Json/JsonContent.cs b/src/Kampute.HttpClient.Json/JsonContent.cs index e3f15c7..8dac131 100644 --- a/src/Kampute.HttpClient.Json/JsonContent.cs +++ b/src/Kampute.HttpClient.Json/JsonContent.cs @@ -59,7 +59,7 @@ protected override Task SerializeToStreamAsync(Stream stream, TransportContext c /// Attempts to compute the length of the content. /// /// When this method returns, contains the length of the content in bytes. - /// > if the length could be computed; otherwise, . + /// if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1; diff --git a/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs b/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs index cfa926c..1fbfb6d 100644 --- a/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs +++ b/src/Kampute.HttpClient.NewtonsoftJson/JsonContent.cs @@ -65,7 +65,7 @@ protected override Task SerializeToStreamAsync(Stream stream, TransportContext c /// Attempts to compute the length of the content. /// /// When this method returns, contains the length of the content in bytes. - /// > if the length could be computed; otherwise, . + /// if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1; diff --git a/src/Kampute.HttpClient.Xml/XmlContent.cs b/src/Kampute.HttpClient.Xml/XmlContent.cs index 15bb130..be8ec7a 100644 --- a/src/Kampute.HttpClient.Xml/XmlContent.cs +++ b/src/Kampute.HttpClient.Xml/XmlContent.cs @@ -85,7 +85,7 @@ protected override Task SerializeToStreamAsync(Stream stream, TransportContext c /// Attempts to compute the length of the content. /// /// When this method returns, contains the length of the content in bytes. - /// > if the length could be computed; otherwise, . + /// if the length could be computed; otherwise, . protected override bool TryComputeLength(out long length) { length = -1;