|
| 1 | +# RestSharp – Best Practices |
| 2 | + |
| 3 | +This document captures practical guidance for developing, testing, reviewing, and releasing changes in the RestSharp repository. It consolidates conventions used across the solution and provides checklists and examples to reduce regressions and ensure consistency across target frameworks. |
| 4 | + |
| 5 | + |
| 6 | +## 1) Daily Development Workflow |
| 7 | + |
| 8 | +- Prefer small, focused pull requests with clear descriptions and test coverage. |
| 9 | +- Build and test locally before pushing. Validate all relevant target frameworks (TFMs) for your changes. |
| 10 | +- Keep commits tidy; prefer meaningful commit messages over large "fix" commits. |
| 11 | +- Follow repository code style and file organization rules (see sections below). |
| 12 | +- Use the latest C# language features (C# 14). |
| 13 | + |
| 14 | +Suggested loop: |
| 15 | +- dotnet build |
| 16 | +- dotnet test |
| 17 | + |
| 18 | +## 2) Multi-Targeting Guidance |
| 19 | + |
| 20 | +The core library targets netstandard2.0, net471, net48, net8.0, net9.0, and net10.0. Tests target net48 (Windows only), net8.0, net9.0, and net10.0. |
| 21 | + |
| 22 | +- Use conditional compilation for TFM-specific APIs or behaviors: |
| 23 | + - #if NET |
| 24 | + - #if NET for platform attributes (e.g., [UnsupportedOSPlatform("browser")]) |
| 25 | +- When adding features, ensure compilation succeeds for all TFMs. If an API is missing on older TFMs, add polyfills or conditional code, or guard with feature detection. |
| 26 | +- Be mindful of System.Text.Json: it is a package dependency on older TFMs but built-in on modern TFMs. |
| 27 | +- Validate tests for each TFM impacted by your changes. If a test only applies to modern .NET, guard it with #if NET8_0_OR_GREATER. |
| 28 | + |
| 29 | + |
| 30 | +## 3) Build and Configuration |
| 31 | + |
| 32 | +- Shared build logic lives in props/Common.props, src/Directory.Build.props, and test/Directory.Build.props. Do not duplicate MSBuild settings in individual projects unless necessary. |
| 33 | +- Language version is preview; prefer modern C# features but ensure cross-TFM compatibility. |
| 34 | +- Nullable reference types: |
| 35 | + - Enabled in /src (Nullable=enable). Treat nullable warnings as design feedback. |
| 36 | + - Disabled in /test (Nullable=disable) for test authoring ergonomics. |
| 37 | +- Assemblies are strong-named via RestSharp.snk. Do not remove signing. |
| 38 | +- Package versions are centrally managed in Directory.Packages.props; do not pin versions locally unless justified by TFM constraints. |
| 39 | + |
| 40 | + |
| 41 | +## 4) Source Generators |
| 42 | + |
| 43 | +Custom incremental generators live in gen/SourceGenerator and are referenced as analyzers by src/RestSharp. |
| 44 | + |
| 45 | +- Use [GenerateImmutable] to produce immutable wrappers of mutable classes. |
| 46 | + - Exclude properties with [Exclude] when not needed in the immutable type. |
| 47 | + - Generated files are emitted to obj/<Configuration>/<TFM>/generated/SourceGenerator/. |
| 48 | +- Use [GenerateClone(BaseType=..., Name=...)] to create static factory methods that upcast/copy base properties into derived types. |
| 49 | +- When editing generators: |
| 50 | + - Keep the generator targets netstandard2.0. |
| 51 | + - Ensure EmitCompilerGeneratedFiles is enabled when debugging locally. |
| 52 | + - Validate output by building and inspecting generated files under obj/... |
| 53 | +- Keep generator helpers cohesive (Extensions.cs) and prefer small, composable utilities. |
| 54 | + |
| 55 | + |
| 56 | +## 5) Testing Strategy |
| 57 | + |
| 58 | +- Frameworks and libraries: xUnit + FluentAssertions + AutoFixture. |
| 59 | +- Organization: |
| 60 | + - Unit tests in test/RestSharp.Tests. |
| 61 | + - Integration tests (HTTP/WireMock) in test/RestSharp.Tests.Integrated. |
| 62 | + - Serializer-specific tests in dedicated projects. |
| 63 | + - Shared helpers in test/RestSharp.Tests.Shared. |
| 64 | +- Best practices: |
| 65 | + - Co-locate tests with feature areas; use partial classes to split large suites. |
| 66 | + - Prefer WireMockServer over live endpoints for HTTP scenarios. |
| 67 | + - Avoid flaky tests: don’t depend on timing, locale, or network conditions. |
| 68 | + - Use descriptive assertions, e.g., result.Should().Be(expected). |
| 69 | + - Scope tests by TFM when API availability differs. |
| 70 | +- Useful commands: |
| 71 | + - dotnet test RestSharp.sln -c Debug |
| 72 | + - dotnet test test/RestSharp.Tests/RestSharp.Tests.csproj -f net8.0 |
| 73 | + - dotnet test test/RestSharp.Tests/RestSharp.Tests.csproj --filter "FullyQualifiedName=Namespace.Class.Method" -f net8.0 |
| 74 | +- Test results are written to test-results/<TFM>/<ProjectName>.trx. |
| 75 | + |
| 76 | + |
| 77 | +## 6) Code Coverage |
| 78 | + |
| 79 | +- Use coverlet.collector for data-collector-based coverage. |
| 80 | +- Example command (Cobertura output): |
| 81 | + - dotnet test test/RestSharp.Tests/RestSharp.Tests.csproj -f net10.0 --collect:"XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=cobertura |
| 82 | +- Coverage artifacts are placed alongside test results in test-results. |
| 83 | + |
| 84 | + |
| 85 | +## 7) Dependency Injection and Extensions |
| 86 | + |
| 87 | +- DI extensions live in src/RestSharp.Extensions.DependencyInjection. |
| 88 | +- When updating DI helpers: |
| 89 | + - Keep APIs minimal and idiomatic for Microsoft.Extensions.DependencyInjection. |
| 90 | + - Maintain backward compatibility where feasible; add overloads rather than breaking changes. |
| 91 | + - Add focused tests under test/RestSharp.Tests.DependencyInjection. |
| 92 | + |
| 93 | + |
| 94 | +## 8) Serialization Extensions |
| 95 | + |
| 96 | +- JSON (Newtonsoft.Json), XML, and CSV serializers are separate packages within src/RestSharp.Serializers.*. |
| 97 | +- Keep serializer-specific behavior isolated. Avoid coupling core library to serializers. |
| 98 | +- Each serializer project has its own tests; ensure behavior parity across TFMs. |
| 99 | + |
| 100 | + |
| 101 | +## 9) Performance and Benchmarks |
| 102 | + |
| 103 | +- Use benchmarks/RestSharp.Benchmarks for perf investigations. |
| 104 | +- Before merging performance-related changes: |
| 105 | + - Validate allocations and throughput with BenchmarkDotNet where practical. |
| 106 | + - Check for regression across TFMs if the code path is shared. |
| 107 | + |
| 108 | + |
| 109 | +## 10) Versioning and Packaging |
| 110 | + |
| 111 | +- Versioning is handled by MinVer via Git tags and history. Ensure CI uses full history (unshallow fetch). |
| 112 | +- Do not hardcode versions; rely on MinVer for assembly and file versions (CustomVersion target aligns versions post-MinVer). |
| 113 | +- Packaging notes: |
| 114 | + - dotnet pack src/RestSharp/RestSharp.csproj -c Release -o nuget -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg |
| 115 | + - Symbol packages must be .snupkg; SourceLink is enabled for debugging. |
| 116 | + - NuGet metadata is defined in src/Directory.Build.props; keep it accurate. |
| 117 | + |
| 118 | + |
| 119 | +## 11) Continuous Integration |
| 120 | + |
| 121 | +- PR workflow executes matrix tests on Windows (net48, net8.0, net9.0, net10.0) and Linux (net8.0, net9.0, net10.0). |
| 122 | +- Build/Deploy workflow packages and pushes to NuGet on dev branch and tags using OIDC-based auth. |
| 123 | +- To simulate CI locally: |
| 124 | + - dotnet test -c Debug -f net8.0 |
| 125 | + - Optionally also run -f net9.0 and -f net10.0. On Windows, include net48. |
| 126 | +- Uploading artifacts and publishing test results are CI-responsibilities; keep local output organized in test-results for quick inspection. |
| 127 | + |
| 128 | + |
| 129 | +## 12) Code Organization and Style |
| 130 | + |
| 131 | +- File organization: |
| 132 | + - Use partial classes to split large types by responsibility (e.g., RestClient.*, PropertyCache.*). Link related files via <DependentUpon> in csproj when appropriate. |
| 133 | +- License header: |
| 134 | + - All source files under /src must include the standard repository license header. |
| 135 | + - Test files do not require the header. |
| 136 | +- EditorConfig and rules: |
| 137 | + - Follow .editorconfig for formatting and analyzer rules. |
| 138 | + - In /src, suppress XML doc warnings via NoWarn=1591; in tests suppress xUnit1033 and CS8002 as configured. |
| 139 | +- Nullable: |
| 140 | + - Treat nullable annotations and warnings as design signals; prefer explicit nullability and defensive checks at public boundaries. |
| 141 | +- Public API surface: |
| 142 | + - Avoid breaking changes. If unavoidable, document in docs and changelog, and add clear migration notes. |
| 143 | + |
| 144 | + |
| 145 | +## 13) PR Readiness Checklist |
| 146 | + |
| 147 | +Use this quick checklist before requesting review: |
| 148 | +- Builds cleanly across all targeted TFMs for affected projects. |
| 149 | +- Unit/integration tests added or updated; all pass locally for relevant TFMs. |
| 150 | +- No analyzer warnings introduced in src (beyond allowed suppressions). |
| 151 | +- License header present in new /src files. |
| 152 | +- Source generator changes validated (if applicable) by inspecting obj/.../generated output. |
| 153 | +- Public API changes reviewed, documented, and tested. |
| 154 | +- Central package versions unchanged unless intentionally updated with justification. |
| 155 | +- Commit messages and PR description explain the why and the how. |
| 156 | + |
| 157 | + |
| 158 | +## 14) Troubleshooting Guide |
| 159 | + |
| 160 | +- Tests fail only on a specific TFM |
| 161 | + - Run with -f <TFM> to isolate. Look for conditional compilation and API availability differences. |
| 162 | +- Generator output missing |
| 163 | + - Ensure EmitCompilerGeneratedFiles is true in the project under test; clean and rebuild; inspect obj/.../generated. |
| 164 | +- net48 failures on non-Windows |
| 165 | + - Expected. Use net8.0 or higher on Linux/macOS. Run net48 only on Windows. |
| 166 | +- MinVer version incorrect |
| 167 | + - Ensure CI or local clone has full git history (git fetch --prune --unshallow). |
| 168 | +- Platform-specific failures |
| 169 | + - Use [UnsupportedOSPlatform] and conditional compilation to guard APIs not available on Browser, etc. |
| 170 | + |
| 171 | + |
| 172 | +## 15) Useful Commands (Quick Reference) |
| 173 | + |
| 174 | +- Build solution (Release): |
| 175 | + - dotnet build RestSharp.sln -c Release |
| 176 | +- Run tests for a single TFM: |
| 177 | + - dotnet test test/RestSharp.Tests/RestSharp.Tests.csproj -f net8.0 |
| 178 | +- Run a single test by fully-qualified name: |
| 179 | + - dotnet test test/RestSharp.Tests/RestSharp.Tests.csproj --filter "FullyQualifiedName=RestSharp.Tests.ObjectParserTests.ShouldUseRequestProperty" -f net8.0 |
| 180 | +- Pack locally with symbols: |
| 181 | + - dotnet pack src/RestSharp/RestSharp.csproj -c Release -o nuget -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg |
| 182 | +- View generated source files after build: |
| 183 | + - find src/RestSharp/obj/Debug -name "*.g.cs" -o -name "ReadOnly*.cs" |
| 184 | +- Clean all build artifacts: |
| 185 | + - dotnet clean RestSharp.sln |
| 186 | + - rm -rf src/*/bin src/*/obj test/*/bin test/*/obj gen/*/bin gen/*/obj |
| 187 | + |
| 188 | + |
| 189 | +## 16) Documentation and References |
| 190 | + |
| 191 | +- Main docs: https://restsharp.dev |
| 192 | +- Repository: https://github.com/restsharp/RestSharp |
| 193 | +- NuGet Packages: |
| 194 | + - RestSharp |
| 195 | + - RestSharp.Serializers.NewtonsoftJson |
| 196 | + - RestSharp.Serializers.Xml |
| 197 | + - RestSharp.Serializers.CsvHelper |
| 198 | +- License: Apache-2.0 |
| 199 | + |
| 200 | +Keep this document up-to-date when build properties, TFMs, CI workflows, or repository conventions change. |
0 commit comments