AI coding agents working in a user's project have stale training data about
this SDK: they invent methods, use parameters from other versions, and assume
behaviour from sibling Cloudinary SDKs that does not hold here. Fix that by
shipping task documentation inside the package, so it is always version-matched
to the assembly the agent is looking at.
Follows the standard set by pycloudinary #450, cloudinary_npm #742/#744,
cloudinary_gem #596 and cloudinary_php #428.
Contents:
- docs/ - 14 task pages plus an index, shipped in the .nupkg. Covers install,
configuration, upload, chunked video upload, signed browser uploads, image
and video delivery, search and asset management, moderation, structured
metadata, ASP.NET Core integration, and troubleshooting.
- examples/ - 8 runnable examples behind a single runner, deliberately NOT
packaged: loose .cs files with a Main entry point could be picked up by a
consumer's compile glob. Every doc page carries its flow inline instead.
- AGENTS.md (+ CLAUDE.md) - contributor guide for agents working on this repo.
- SECURITY.md, context7.json, restructured README.md.
Packaging uses the mechanism already in the csproj for README.md and the icon,
rather than introducing a second one. Verified by unpacking the .nupkg and by
restoring it into a scratch project: all 15 pages are present and reachable at
<global-packages>/cloudinarydotnet/<version>/docs/ for all three targets.
Every documented behaviour was established by executing it against live
Claimable Clouds, not by reading source. Notable findings that contradict a
sibling SDK or a plausible guess, and are now documented:
- Cloudinary API errors are returned in result.Error, never thrown. The
assembly exports no exception types and Error carries only Message, so
StatusCode is the only thing to branch on. try/catch around a call catches
nothing.
- URLs are HTTP by default (Api.Secure is false), unlike the Node SDK.
- Moderation does not gate delivery: a pending asset returns HTTP 200,
identically to a non-moderated control. The status set has six values, and
ModerationStatus is empty on the upload result but populated on a read.
- UploadLargeAsync with RawUploadParams stores a video as raw with HTTP 200 and
no error, leaving an asset no transformation can ever touch.
- Overwrite = false on an existing public ID is a silent no-op; the only signal
is an existing flag available solely in JsonObj.
- folder: search expressions match nothing on a dynamic-folder environment.
- An unsubscribed add-on reports as HTTP 420, the rate-limit code.
- Undefined structured-metadata keys fail the whole upload.
- Timeouts throw TaskCanceledException, bypassing the Error check.
- Signing an upload from .NET needs MultipartFormDataContent field names
pre-quoted, or Cloudinary treats the request as unsigned.
Verified: 63/63 C# snippets compile, 128/128 internal links and anchors
resolve, 70/70 external URLs return 200, 8/8 examples run green against both
an accumulated and a clean-slate cloud, 8/8 error paths exit non-zero with a
readable message and no stack trace, and the unit suite is unchanged at
613 passed / 0 failed.
The context7.json public key is account-scoped and shared with the other
Cloudinary SDKs, so it is reused here rather than newly issued.
No CHANGELOG entry (docs-only), no linter or formatter added, and samples/ is
left untouched.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>