You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Today, TypeFactory.CreateExternalType in the C# generator can only resolve an InputExternalTypeMetadata if the type is one the generator already knows how to map to a framework type via CreateFrameworkType (e.g. System.Uri, System.Net.IPAddress once the BCL has it). For any other identity — a type that lives in a NuGet package the generated project depends on but the generator process itself doesn't reference — we fall through to:
CodeModelGenerator.Instance.Emitter.ReportDiagnostic("unsupported-external-type",$"External type '{externalProperties.Identity}' is not currently supported.");returnnull;
…and the property is silently dropped. This is the path covered by the existing UnsupportedExternalTypeEmitsDiagnostic test (e.g. Azure.Core.Expressions.DataFactoryExpression).
This is unfortunate because InputExternalTypeMetadata already carries everything we'd need to load such a type dynamically:
Add dynamic NuGet-based loading of external types as a fallback in TypeFactory.CreateExternalType, reusing the mechanism introduced by #10229 (GeneratedCodeWorkspace.AddPackageReferencesFromProject / FindPackageAssembly / ResolveLatestPackageVersion / NugetPackageDownloader).
Resolution order should be:
CreateFrameworkType(identity) — current behavior; cheapest and the source of truth for BCL types. If it returns non-null, we're done.
Dynamic load via NuGet (new fallback) — only if step 1 returns null and InputExternalTypeMetadata.Package is provided:
Resolve the assembly for Package (honoring MinVersion when present) by first probing the NuGet global packages cache (à la FindPackageAssembly), then falling back to a feed download (ResolveLatestPackageVersion + NugetPackageDownloader) that PR fix(http-client-csharp): resolve PackageReference assemblies for cust… #10229 already wired up.
Load the resolved assembly via Roslyn MetadataReference.CreateFromFile and add it to CodeModelGenerator.Instance.AdditionalMetadataReferences so customization compilation also sees it (PR fix(http-client-csharp): resolve PackageReference assemblies for cust… #10229's de-dup against existingRefs already covers this nicely).
Use reflection (Assembly.LoadFrom / MetadataLoadContext) on the same DLL to find the Type matching Identity and produce a CSharpType from it, exactly like the framework-type path does.
Diagnostic — only if both 1 and 2 fail, emit the existing unsupported-external-type diagnostic. The diagnostic message should be expanded to mention the package/version that was attempted (or that no Package was supplied) so users have something actionable.
Why a fallback (not a replacement)
Keeping CreateFrameworkType as the first attempt:
Avoids any I/O / NuGet hit for the common BCL cases.
Preserves existing behavior and test expectations for System.* types whose Package is null.
Makes the new code path opt-in via the emitter / TCGC supplying Package + (optionally) MinVersion.
Out of scope / open questions
Whether we should require MinVersion to be present before attempting a feed download, or fall back to "latest stable" the way ResolveLatestPackageVersion does today.
How (or whether) to surface a warning when the resolved assembly's version is lower than MinVersion.
Whether to share a single resolution helper between AddPackageReferencesFromProject and the new external-type path so caching and diagnostics stay consistent.
Acceptance criteria
A InputExternalTypeMetadata whose Identity is not a known framework type but whose Package resolves via the NuGet cache or feed produces a valid CSharpType (and no unsupported-external-type diagnostic).
The existing ExternalTypeModelUsedAsProperty / ExternalTypePropertyIsResolved tests continue to pass unchanged (framework-type path is hit first).
A new test covers the NuGet fallback using the same fake-cache pattern as AddPackageReferencesFromProject_AddsReferencesFromCsproj in GeneratedCodeWorkspaceTests.
A negative test covers the case where neither framework lookup nor NuGet resolution succeeds, asserting the (improved) diagnostic.
Clear and concise description of the problem
Today,
TypeFactory.CreateExternalTypein the C# generator can only resolve anInputExternalTypeMetadataif the type is one the generator already knows how to map to a framework type viaCreateFrameworkType(e.g.System.Uri,System.Net.IPAddressonce the BCL has it). For any other identity — a type that lives in a NuGet package the generated project depends on but the generator process itself doesn't reference — we fall through to:…and the property is silently dropped. This is the path covered by the existing
UnsupportedExternalTypeEmitsDiagnostictest (e.g.Azure.Core.Expressions.DataFactoryExpression).This is unfortunate because
InputExternalTypeMetadataalready carries everything we'd need to load such a type dynamically:Proposal
Add dynamic NuGet-based loading of external types as a fallback in
TypeFactory.CreateExternalType, reusing the mechanism introduced by #10229 (GeneratedCodeWorkspace.AddPackageReferencesFromProject/FindPackageAssembly/ResolveLatestPackageVersion/NugetPackageDownloader).Resolution order should be:
CreateFrameworkType(identity)— current behavior; cheapest and the source of truth for BCL types. If it returns non-null, we're done.InputExternalTypeMetadata.Packageis provided:Package(honoringMinVersionwhen present) by first probing the NuGet global packages cache (à laFindPackageAssembly), then falling back to a feed download (ResolveLatestPackageVersion+NugetPackageDownloader) that PR fix(http-client-csharp): resolve PackageReference assemblies for cust… #10229 already wired up.MetadataReference.CreateFromFileand add it toCodeModelGenerator.Instance.AdditionalMetadataReferencesso customization compilation also sees it (PR fix(http-client-csharp): resolve PackageReference assemblies for cust… #10229's de-dup againstexistingRefsalready covers this nicely).Assembly.LoadFrom/MetadataLoadContext) on the same DLL to find theTypematchingIdentityand produce aCSharpTypefrom it, exactly like the framework-type path does.unsupported-external-typediagnostic. The diagnostic message should be expanded to mention the package/version that was attempted (or that noPackagewas supplied) so users have something actionable.Why a fallback (not a replacement)
Keeping
CreateFrameworkTypeas the first attempt:System.*types whosePackageis null.Package+ (optionally)MinVersion.Out of scope / open questions
MinVersionto be present before attempting a feed download, or fall back to "latest stable" the wayResolveLatestPackageVersiondoes today.MinVersion.AddPackageReferencesFromProjectand the new external-type path so caching and diagnostics stay consistent.Acceptance criteria
InputExternalTypeMetadatawhoseIdentityis not a known framework type but whosePackageresolves via the NuGet cache or feed produces a validCSharpType(and nounsupported-external-typediagnostic).ExternalTypeModelUsedAsProperty/ExternalTypePropertyIsResolvedtests continue to pass unchanged (framework-type path is hit first).AddPackageReferencesFromProject_AddsReferencesFromCsprojinGeneratedCodeWorkspaceTests.Checklist