|
| 1 | +# Copilot Instructions for nanoframework/System.Net.Http |
| 2 | + |
| 3 | +## Repository Overview |
| 4 | + |
| 5 | +This repository implements the `System.Net.Http` class library for [.NET nanoFramework](https://nanoframework.net/) — a free, open-source platform that enables running C# code on constrained embedded/IoT devices (microcontrollers). It is **not** standard .NET; it targets a stripped-down CLR with significant limitations. |
| 6 | + |
| 7 | +The library is published as three separate NuGet packages: |
| 8 | +- `nanoFramework.System.Net.Http` — full HTTP library (client + server + shared types) |
| 9 | +- `nanoFramework.System.Net.Http.Client` — client-only subset |
| 10 | +- `nanoFramework.System.Net.Http.Server` — server-only subset |
| 11 | + |
| 12 | +## Key nanoFramework Constraints |
| 13 | + |
| 14 | +These constraints are critical to understand before making any code changes: |
| 15 | + |
| 16 | +- **No `async`/`await`**: nanoFramework does not support the Task Parallel Library or `async`/`await`. All APIs are synchronous. Method names intentionally drop the `Async` suffix. |
| 17 | +- **No generics**: Generic types and methods are not supported. |
| 18 | +- **No LINQ**: LINQ is not available. |
| 19 | +- **No `Task`/`CancellationToken`**: These concepts do not exist in the nanoFramework runtime. |
| 20 | +- **Limited reflection**: Only a very limited subset of reflection is available. |
| 21 | +- **Limited memory**: Devices may have as little as 16 KB of RAM; always dispose `HttpResponseMessage` after use. |
| 22 | +- **No `async` streams**: All I/O is blocking and synchronous. |
| 23 | +- **Target framework**: `v1.0` (nanoFramework's own TFM, not .NET 1.0). |
| 24 | +- **No `HttpClient.SendAsync`**: Replaced by synchronous `HttpClient.Send` / convenience methods (`Get`, `Post`, `Put`, `Delete`). |
| 25 | + |
| 26 | +## Repository Structure |
| 27 | + |
| 28 | +``` |
| 29 | +/ |
| 30 | +├── nanoFramework.System.Net.Http/ # Main library project (full) |
| 31 | +│ ├── Http/ # All source files |
| 32 | +│ │ ├── Headers/ # HTTP header types |
| 33 | +│ │ ├── HttpClient.cs # HttpClient implementation |
| 34 | +│ │ ├── HttpContent.cs, StringContent.cs, ByteArrayContent.cs, StreamContent.cs |
| 35 | +│ │ ├── HttpRequestMessage.cs, HttpResponseMessage.cs, HttpMethod.cs |
| 36 | +│ │ ├── HttpMessageHandler.cs, HttpClientHandler.cs, HttpMessageInvoker.cs |
| 37 | +│ │ ├── System.Net.HttpWebRequest.cs # Lower-level WebRequest implementation |
| 38 | +│ │ ├── System.Net.HttpListener*.cs # HTTP server listener |
| 39 | +│ │ └── System.Net.*.cs # Supporting System.Net types (Uri, WebRequest, etc.) |
| 40 | +│ ├── System.Net.Http.nfproj # nanoFramework project file (MSBuild) |
| 41 | +│ ├── key.snk # Strong-name signing key |
| 42 | +│ └── packages.config / packages.lock.json |
| 43 | +│ |
| 44 | +├── nanoFramework.System.Net.Http.Client/ # Client-only subset project |
| 45 | +│ ├── Http/Headers/ # Client-specific headers (mostly .gitkeep) |
| 46 | +│ └── System.Net.Http.Client.nfproj |
| 47 | +│ |
| 48 | +├── nanoFramework.System.Net.Http.Server/ # Server-only subset project |
| 49 | +│ └── System.Net.Http.Server.nfproj |
| 50 | +│ |
| 51 | +├── Tests/ |
| 52 | +│ └── HttpUnitTests/ # Unit test project (nanoFramework test runner) |
| 53 | +│ ├── HttpClientTest.cs # HttpClient tests (skipped on WIN32 nanoCLR) |
| 54 | +│ ├── HttpContentTest.cs, ByteArrayContentTest.cs, StreamContentTest.cs, StringContentTest.cs |
| 55 | +│ ├── MediaTypeHeaderValueTest.cs |
| 56 | +│ ├── HttpUtilityTest.cs |
| 57 | +│ ├── UriUnitTests.cs |
| 58 | +│ ├── LoopbackServer.cs |
| 59 | +│ ├── MockContent.cs |
| 60 | +│ └── HttpUnitTests.nfproj |
| 61 | +│ |
| 62 | +├── nanoFramework.System.Net.Http.sln # Visual Studio solution |
| 63 | +├── nanoFramework.System.Net.Http.nuspec # NuGet spec (full package) |
| 64 | +├── nanoFramework.System.Net.Http.Client.nuspec |
| 65 | +├── nanoFramework.System.Net.Http.Server.nuspec |
| 66 | +├── version.json # Nerdbank.GitVersioning config (semver 2.0) |
| 67 | +├── NuGet.Config # Points to nuget.org |
| 68 | +├── azure-pipelines.yml # CI/CD build pipeline (Azure Pipelines) |
| 69 | +├── .github/workflows/ # GitHub Actions workflows |
| 70 | +│ ├── pr-checks.yml # PR validation (package lock + NuGet version checks) |
| 71 | +│ ├── update-dependencies.yml |
| 72 | +│ ├── update-dependencies-develop.yml |
| 73 | +│ └── generate-changelog.yml |
| 74 | +└── .editorconfig # Code style configuration |
| 75 | +``` |
| 76 | + |
| 77 | +## Project File Format |
| 78 | + |
| 79 | +All library and test projects use `.nfproj` files — a custom MSBuild project format for nanoFramework. These are **not** standard `.csproj` files. The project type GUID is `{11A8DD76-328B-46DF-9F39-F559912D0360}`. |
| 80 | + |
| 81 | +- Dependencies are declared via `packages.config` (not `PackageReference`). |
| 82 | +- Package restore locks are stored in `packages.lock.json`. |
| 83 | +- In CI (`TF_BUILD=True`), packages are restored in locked mode. |
| 84 | +- The nanoFramework MSBuild SDK is referenced via `$(MSBuildExtensionsPath)\nanoFramework\v1.0\`. |
| 85 | + |
| 86 | +## Coding Conventions |
| 87 | + |
| 88 | +From `.editorconfig` and existing code: |
| 89 | + |
| 90 | +- **File encoding**: UTF-8 with BOM (`utf-8-bom`), CRLF line endings. |
| 91 | +- **Indentation**: 4 spaces for C#, 2 spaces for XML/YAML/config files. |
| 92 | +- **Namespaces**: `System.Net` and `System.Net.Http` (mirroring .NET's BCL namespaces). |
| 93 | +- **Naming**: |
| 94 | + - Private/internal fields: `_camelCase` (underscore prefix) |
| 95 | + - Static private/internal fields: `s_camelCase` |
| 96 | + - Constants: `PascalCase` |
| 97 | +- **Braces**: Allman style (open brace on new line) for C#. |
| 98 | +- **No `var`**: Explicit types are strongly preferred. |
| 99 | +- **License header**: Every `.cs` file starts with: |
| 100 | + ```csharp |
| 101 | + // |
| 102 | + // Copyright (c) .NET Foundation and Contributors |
| 103 | + // Portions Copyright (c) Microsoft Corporation. All rights reserved. |
| 104 | + // See LICENSE file in the project root for full license information. |
| 105 | + // |
| 106 | + ``` |
| 107 | +- **XML doc comments**: All public APIs must have `<summary>`, `<param>`, `<returns>`, `<exception>` etc. |
| 108 | +- **Assembly signing**: The main library assembly is strong-name signed using `key.snk`. |
| 109 | + |
| 110 | +## Testing |
| 111 | + |
| 112 | +- Tests use `nanoFramework.TestFramework` (attributes: `[TestClass]`, `[TestMethod]`, `[Setup]`). |
| 113 | +- The test project targets the nanoFramework nanoCLR runtime. |
| 114 | +- **`HttpClientTest` is always skipped** on the WIN32 nanoCLR (no network support); `Assert.SkipTest(...)` is called in `[Setup]`. |
| 115 | +- Network-dependent tests cannot be run in a standard CI environment — only on real hardware or an emulator with network access. |
| 116 | +- Tests that can run on WIN32 nanoCLR (no network): `HttpUtilityTest`, `UriUnitTests`, `ByteArrayContentTest`, `StreamContentTest`, `StringContentTest`, `HttpContentTest`, `MediaTypeHeaderValueTest`. |
| 117 | +- The test runner binary is `nanoFramework.UnitTestLauncher.exe` from the `nanoFramework.TestFramework` package. |
| 118 | +- Run settings: `Tests/HttpUnitTests/nano.runsettings`. |
| 119 | + |
| 120 | +## Building |
| 121 | + |
| 122 | +- **Build toolchain**: Visual Studio 2022 on Windows with the nanoFramework extension installed. |
| 123 | +- **CI build**: Azure Pipelines (`azure-pipelines.yml`) runs on `windows-latest`, builds `Release|Any CPU`. |
| 124 | +- The build is orchestrated via templates from the `nanoframework/nf-tools` repository. |
| 125 | +- Three NuGet packages are produced: full, client, server. |
| 126 | +- Package versioning is managed by `Nerdbank.GitVersioning` (`version.json`), current major.minor: `1.5`. |
| 127 | +- There is **no standard `dotnet build`** CLI workflow — builds require the nanoFramework MSBuild extensions. |
| 128 | + |
| 129 | +## CI/CD Workflows |
| 130 | + |
| 131 | +### Azure Pipelines (`azure-pipelines.yml`) |
| 132 | +- Triggers on push to `main`, `develop`, `release-*`, and version tags (`v*`). |
| 133 | +- Two jobs: `Build_Library` and `Update_Dependents`. |
| 134 | +- Publishes to NuGet and creates GitHub releases from `main`. |
| 135 | +- Downstream repos updated on tag: `nanoFramework.WebServer`, `nanoFramework.Azure.Devices`, `System.Net.WebSockets`. |
| 136 | +- Build failures are reported to Discord via webhook. |
| 137 | + |
| 138 | +### GitHub Actions |
| 139 | +- `pr-checks.yml`: Validates `packages.lock.json` consistency and that NuGet packages are up to date. |
| 140 | +- `update-dependencies.yml` / `update-dependencies-develop.yml`: Automated dependency update PRs. |
| 141 | +- `generate-changelog.yml`: Auto-generates `CHANGELOG.md`. |
| 142 | + |
| 143 | +## Key API Design Decisions |
| 144 | + |
| 145 | +- `HttpClient` is designed to be instantiated once and reused (same as .NET). |
| 146 | +- `HttpResponseMessage` **must always be disposed** — device memory is very limited. |
| 147 | +- HTTPS requires manually providing the CA root certificate via `HttpClient.HttpsAuthentCert` (an `X509Certificate`). |
| 148 | +- The library mirrors .NET `System.Net.Http` APIs as closely as possible, with synchronous equivalents of async methods. |
| 149 | +- `HttpClient` convenience methods: `Get(string)`, `Post(string, HttpContent)`, `Put(string, HttpContent)`, `Delete(string)`. |
| 150 | +- `HttpContent` subtypes: `StringContent`, `ByteArrayContent`, `StreamContent`. |
| 151 | +- Header types mirror .NET: `HttpRequestHeaders`, `HttpResponseHeaders`, `HttpContentHeaders`, `MediaTypeHeaderValue`, etc. |
| 152 | + |
| 153 | +## Known Limitations / Workarounds |
| 154 | + |
| 155 | +- When sending consecutive requests to a development machine through a reverse proxy (e.g., iisexpress-proxy), `SocketException`s may occur. A retry mechanism in Debug mode is the recommended workaround. |
| 156 | +- No `CancellationToken` support — timeouts are set via `HttpClient.Timeout`. |
| 157 | +- No multipart form data support. |
| 158 | +- The `System.Net.Http.Client` and `System.Net.Http.Server` projects currently have empty `Http/` directories (only `.gitkeep`) — they reference the full library assembly. Check `.nfproj` files to understand what each package actually packages. |
| 159 | + |
| 160 | +## Versioning |
| 161 | + |
| 162 | +- Version is managed by `Nerdbank.GitVersioning`. |
| 163 | +- Current version line: `1.5` (see `version.json`). |
| 164 | +- Release branches follow pattern: `release-v{version}`. |
| 165 | +- Public release branches: `main`, `develop`, `v\d+(\.\d+)?`. |
| 166 | +- NuGet packages use SemVer 2.0. |
| 167 | + |
| 168 | +## Dependencies (NuGet packages) |
| 169 | + |
| 170 | +- `nanoFramework.CoreLibrary` (mscorlib) |
| 171 | +- `nanoFramework.Runtime.Events` |
| 172 | +- `nanoFramework.System.Collections` |
| 173 | +- `nanoFramework.System.Text` |
| 174 | +- `nanoFramework.System.Net` |
| 175 | +- `nanoFramework.System.Threading` |
| 176 | +- `nanoFramework.System.IO.Streams` |
| 177 | +- `Nerdbank.GitVersioning` (build-time only) |
0 commit comments