Skip to content

fix(http-client-csharp): resolve PackageReference assemblies for cust…#10229

Merged
JoshLove-msft merged 8 commits into
microsoft:mainfrom
JoshLove-msft:fix/external-metadata-references
Apr 1, 2026
Merged

fix(http-client-csharp): resolve PackageReference assemblies for cust…#10229
JoshLove-msft merged 8 commits into
microsoft:mainfrom
JoshLove-msft:fix/external-metadata-references

Conversation

@JoshLove-msft
Copy link
Copy Markdown
Contributor

…om code compilation

When custom code references types from external NuGet packages (e.g., Azure.Storage.Common.StorageSharedKeyCredential), the Roslyn compilation would fail because those assemblies weren't added as metadata references.

Parse the project's .csproj file for PackageReference items and resolve their assemblies from the NuGet global packages cache. This allows custom constructors and other user code that references external library types to compile correctly.

Fixes #10224

…om code compilation

When custom code references types from external NuGet packages (e.g.,
Azure.Storage.Common.StorageSharedKeyCredential), the Roslyn compilation
would fail because those assemblies weren't added as metadata references.

Parse the project's .csproj file for PackageReference items and resolve
their assemblies from the NuGet global packages cache. This allows
custom constructors and other user code that references external library
types to compile correctly.

Fixes microsoft#10224

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 1, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@typespec/http-client-csharp@10229

commit: 47ff5b1

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 1, 2026

No changes needing a change description found.

@microsoft-github-policy-service microsoft-github-policy-service Bot added the emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp label Apr 1, 2026
JoshLove-msft and others added 4 commits March 31, 2026 20:26
Parse .csproj PackageReference items and resolve assemblies from the
NuGet global cache. Fixes custom code that references external types
(e.g. StorageSharedKeyCredential) failing to compile.

Use fresh ProjectCollection to avoid MSBuild caching stale project
files. Use Configuration.PackageName for .csproj file discovery.

Tests:
- AddsReferencesFromCsproj: verifies assembly is added from NuGet cache
- SkipsWhenNoCsproj: no-op when project file doesn't exist
- SkipsPackageNotInCache: no-op when package isn't in cache

Fixes microsoft#10224

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a PackageReference assembly isn't in the NuGet global cache,
download it from NuGet feeds using the existing NugetPackageDownloader.
This matches the pattern used by LoadBaselineContract and ensures
external references resolve even without a prior dotnet restore.

Update tests to async and verify graceful skip when packages can't
be found in cache or NuGet feeds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Check existing metadata references before resolving from NuGet cache
or downloading. Packages already added (e.g., by a plugin via
AddMetadataReference) are skipped to avoid redundant downloads.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- SkipsAlreadyAddedReferences: verifies packages already in
  AdditionalMetadataReferences are not re-added
- AddsMultiplePackageReferences: verifies all PackageReference items
  are resolved, not just the first

Extract CreateFakeNuGetPackage helper to reduce duplication.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JoshLove-msft JoshLove-msft enabled auto-merge April 1, 2026 03:54
- Import ProjectCollection via using alias to avoid ambiguity
- Check Display is not null instead of coalescing with empty string
- Handle PackageReference with no Version (centrally managed packages)
  by scanning all cached versions for matching assemblies
- Move existingRefs check before version parsing
- Extract FindPackageAssembly helper for cache lookup
- Add test for versionless PackageReference resolution

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

@jorgerangel-msft jorgerangel-msft left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Should we run the regen preview for sanity?

Remove version-specific checks and NuGet download fallback. Instead,
scan all cached versions for the package and use whatever is available.
The cache will contain the correct version from the last dotnet restore.

This handles centrally managed packages (no version in csproj) and
avoids downloading the wrong version from NuGet.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When a PackageReference assembly isn't found in the NuGet global cache,
resolve the latest stable version from configured NuGet feeds and
download it. Version checks are skipped — we use whatever is cached
first, falling back to latest from NuGet. This handles centrally
managed packages where the version isn't in the csproj.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@JoshLove-msft
Copy link
Copy Markdown
Contributor Author

LGTM. Should we run the regen preview for sanity?

https://dev.azure.com/azure-sdk/internal/_build/results?buildId=6094076&view=results

@JoshLove-msft JoshLove-msft added this pull request to the merge queue Apr 1, 2026
Merged via the queue into microsoft:main with commit 1f8c6e8 Apr 1, 2026
29 checks passed
@JoshLove-msft JoshLove-msft deleted the fix/external-metadata-references branch April 1, 2026 18:52
JoshLove-msft added a commit to JoshLove-msft/typespec that referenced this pull request May 13, 2026
- ExternalTypeReferenceResolver: tie cache state to the active
  CodeModelGenerator via ConditionalWeakTable so a fresh generator
  starts with an empty cache (Copilot review).
- ExternalTypeReferenceResolver: rename ResetForTests -> Reset and
  drop test-only doc comments; remove dead ?. checks on the
  CodeModelGenerator.Instance reference (Josh review).
- NugetPackageResolver.FindPackageAssembly: when no MinVersion is
  supplied, fall back to lexicographic-descending probing of
  unparseable directory names so PR microsoft#10229's
  AddPackageReferencesFromProject behavior is preserved (Copilot review).
- TypeFactory.CreateExternalType: restructure the diagnostic message
  into self-contained clauses so it no longer reads
  'could not be resolved ... could not be resolved' (Copilot review).
- Tests.Common: introduce FakeNuGetPackage helper and route the new
  ExternalTypeReferenceResolverTests + ModelProviderTests through it
  to remove the duplicated emit-fake-dll code (Copilot review).
- Mark ExternalTypeReferenceResolverTests fixture and the
  ExternalTypePropertyResolvedFromNuGetCache test [NonParallelizable]
  since they mutate process-wide state (Copilot review).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
FionaBronwen pushed a commit to FionaBronwen/typespec that referenced this pull request May 14, 2026
…om NuGet (microsoft#10666)

Fixes microsoft#10665.

Adds a NuGet-backed fallback to `TypeFactory.CreateExternalType` so
external types declared in TypeSpec can resolve to types from arbitrary
NuGet packages (e.g. `Azure.Core.Expressions.DataFactoryExpression`),
not just BCL framework types.

### Resolution order in `CreateExternalType`

1. `CreateFrameworkType` (unchanged — source of truth for BCL types, no
I/O)
2. `ExternalTypeReferenceResolver.TryResolve` (NEW NuGet fallback when
`externalProperties.Package` is set)
3. `unsupported-external-type` diagnostic (now includes attempted
package metadata)

### Implementation highlights

- `src/Utilities/NugetPackageResolver.cs` extracts the
`FindPackageAssembly` and `ResolveLatestPackageVersion` helpers
introduced in microsoft#10229 from `GeneratedCodeWorkspace` so they can be
shared. They are also now `MinVersion`-aware (lower bound: highest
cached/feed-resolved version >= MinVersion).
- `src/Utilities/ExternalTypeReferenceResolver.cs` walks the
`InputLibrary` up front (before the Roslyn workspaces are constructed)
and resolves every `InputExternalTypeMetadata` whose `Package` is set.
Resolved assemblies are loaded via byte arrays (`Assembly.Load` +
`MetadataReference.CreateFromImage`) so we never hold a file handle on
cached NuGet dlls.
- `CSharpGen.ExecuteAsync` now awaits `ResolveAllAsync` after
`AddPackageReferencesFromProject` and
`GeneratedCodeWorkspace.Initialize()` is moved to **after** both
ref-adding steps so the cached project picks up all metadata references.

### Tests

- 12 new `ExternalTypeReferenceResolverTests` covering
null/missing-package short-circuits, NuGet-cache load, `MinVersion`
selection (highest >= MinVersion), dedup of metadata refs, unknown
package, and the `ResolveAllAsync` pre-walk on a complex InputLibrary
graph (model -> property -> union -> external).
- `ModelProviderTests.ExternalTypePropertyResolvedFromNuGetCache`
integration test exercises the end-to-end path through
`TypeFactory.CreateExternalType`.
- `UnsupportedExternalTypeEmitsDiagnostic` strengthened to assert the
unresolvable property is dropped.

All `2,957` existing dotnet tests pass; `25` emitter vitest files pass;
`Generate.ps1` produces no spurious diff.

--generated by Copilot

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

emitter:client:csharp Issue for the C# client emitter: @typespec/http-client-csharp

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Find a Solution to Handling External Metadata References

2 participants