Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug] .NET API bug: duplicate key in GenerateNestedTocStructure #9507

Open
sliekens opened this issue Dec 5, 2023 · 4 comments
Open

[Bug] .NET API bug: duplicate key in GenerateNestedTocStructure #9507

sliekens opened this issue Dec 5, 2023 · 4 comments
Labels
bug A bug to fix dotnet Generate .NET API reference docs

Comments

@sliekens
Copy link

sliekens commented Dec 5, 2023

Describe the bug
My docfx build started failing because of a duplicate dictionary key error when generating a nested ToC structure. This started happening after I updated PolySharp in my project to 1.14.0.

To Reproduce

git clone https://github.com/sliekens/gw2sdk.git
cd gw2sdk
git reset --hard c62c6f5167b6dbee83dbc73b1bf6d1a414fa945d
git clean -df
dotnet tool restore
dotnet docfx

Expected behavior
No crash

Context (please complete the following information):

  • OS: Debian 12

  • Docfx version: 2.74.1

  • .NET version: .NET 8.0.100

  • docfx.json config

{
  "metadata": [
    {
      "src": [
        {
          "src": "GW2SDK",
          "files": [
            "GW2SDK.csproj"
          ]
        }
      ],
      "dest": "docs/api",
      "outputFormat": "mref",
      "includePrivateMembers": false,
      "disableGitFeatures": false,
      "disableDefaultFilter": false,
      "noRestore": false,
      "namespaceLayout": "nested",
      "memberLayout": "separatePages",
      "enumSortOrder": "declaringOrder",
      "allowCompilationErrors": false
    }
  ],
  "build": {
    "content": [
      {
        "src": "docs",
        "files": [
          "index.md",
          "toc.yml"
        ]
      },
      {
        "src": "docs/guide",
        "dest": "guide",
        "files": [
          "**.md",
          "**/toc.yml"
        ]
      },
      {
        "src": "docs/api",
        "dest": "api",
        "files": [
          "**.yml",
          "index.md"
        ]
      }
    ],
    "resource": [
      {
        "src": "docs",
        "files": [
          "images/**"
        ]
      }
    ],
    "output": "artifacts",
    "fileMetadataFiles": [],
    "postProcessors": [],
    "keepFileLink": false,
    "disableGitFeatures": false,
    "template": [
      "default",
      "docs/templates/singulinkfx"
    ],
    "globalMetadata": {
      "_appTitle": "GW2SDK",
      "_appName": "GW2SDK",
      "_appLogoPath": "images/logo-50x50.png",
      "_appFaviconPath": "images/logo-50x50.png",
      "_appFooter": "Built with docfx, theme created by Singulink",
      "_copyrightFooter": "© Steven Liekens. All rights reserved.",
      "_enableSearch": true,
      "_enableNewTab": true
    }
  }
}
  • Exceptions
Creating output...
ArgumentException: An item with the same key has already been added. Key: System
  at bool TryInsert(TKey key, TValue value, InsertionBehavior behavior)                                                                                                                                     
  at void Add(TKey key, TValue value)                                                                                                                                                                       
  at MetadataItem GenerateNestedTocStructure(IEnumerable<KeyValuePair<string, MetadataItem>> namespaces, Dictionary<string, ReferenceItem> allReferences) in YamlMetadataResolver.cs:105                    
  at MetadataItem GenerateNestedToc(IEnumerable<KeyValuePair<string, MetadataItem>> namespaces, Dictionary<string, ReferenceItem> allReferences) in YamlMetadataResolver.cs:162                             
  at MetadataItem GenerateToc(Dictionary<string, MetadataItem> allMembers, Dictionary<string, ReferenceItem> allReferences, NamespaceLayout namespaceLayout) in YamlMetadataResolver.cs:56                  
  at MetadataModel ResolveMetadata(Dictionary<string, MetadataItem> allMembers, Dictionary<string, ReferenceItem> allReferences, NamespaceLayout namespaceLayout) in YamlMetadataResolver.cs:33             
  at void <CreateManagedReference>g__ResolveAndExportYamlMetadata|2(Dictionary<string, MetadataItem> allMembers, Dictionary<string, ReferenceItem> allReferences) in DotnetApiCatalog.ManagedReference.cs:51
  at void CreateManagedReference((ValueTuple<IAssemblySymbol, Compilation> symbol) assemblies, ExtractMetadataConfig config, DotnetApiOptions options) in DotnetApiCatalog.ManagedReference.cs:45           
  at async Task <Exec>g__Build|4_0(ExtractMetadataConfig config, DotnetApiOptions options) in DotnetApiCatalog.cs:123                                                                                       
  at async Task Exec(MetadataJsonConfig config, DotnetApiOptions options, string configDirectory, string outputDirectory) in DotnetApiCatalog.cs:75                                                         
  at void <Execute>b__0() in DefaultCommand.cs:38                                                                                                                                                           
  at int Run(LogOptions options, Action run) in CommandHelper.cs:44                                                                                                                                         
  at int Execute(CommandContext context, Options options) in DefaultCommand.cs:30                                                                                                                           
  at Task<int> Execute(CommandContext context, CommandSettings settings) in CommandOfT.cs:40                                                                                                                
  at Task<int> Execute(CommandTree leaf, CommandTree tree, CommandContext context, ITypeResolver resolver, IConfiguration configuration) in CommandExecutor.cs:144                                          
  at async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args) in CommandExecutor.cs:83                                                                                               
  at async Task<int> RunAsync(IEnumerable<string> args) in CommandApp.cs:84  
  • .NET info
.NET SDK:
 Version:           8.0.100
 Commit:            57efcf1350
 Workload version:  8.0.100-manifests.6c33ef20

Runtime Environment:
 OS Name:     debian
 OS Version:  12
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/8.0.100/

.NET workloads installed:
 Workload version: 8.0.100-manifests.6c33ef20
There are no installed workloads to display.

Host:
  Version:      8.0.0
  Architecture: x64
  Commit:       5535e31a71

.NET SDKs installed:
  8.0.100 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 8.0.0 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 7.0.14 [/usr/share/dotnet/shared/Microsoft.NETCore.App]
  Microsoft.NETCore.App 8.0.0 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  DOTNET_ROOT       [/usr/share/dotnet]

global.json file:
  /workspaces/gw2sdk/global.json

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download
@sliekens sliekens added bug A bug to fix dotnet Generate .NET API reference docs labels Dec 5, 2023
@sliekens
Copy link
Author

sliekens commented Dec 5, 2023

A few minutes of debugging tells me that the problem occurs because I have a (generated) type in the System namespace, which causes a conflict in GenerateNestedTocStructure because allReferences already contains "System", so there is a duplicate key error when trying to add the namespace to namespacedItems and again to allReferences.

@xakep139
Copy link

xakep139 commented Apr 29, 2024

We have a similar problem, but the namespace-specific:

ArgumentException: An item with the same key has already been added. Key: <...>.HttpClient
  at bool TryInsert(TKey key, TValue value, InsertionBehavior behavior)
  at void Add(TKey key, TValue value)
  at MetadataItem GenerateNestedTocStructure(IEnumerable<KeyValuePair<string, MetadataItem>> namespaces, Dictionary<string, ReferenceItem> allReferences) in YamlMetadataResolver.cs:105
  at MetadataItem GenerateNestedToc(IEnumerable<KeyValuePair<string, MetadataItem>> namespaces, Dictionary<string, ReferenceItem> allReferences) in YamlMetadataResolver.cs:162
  at MetadataItem GenerateToc(Dictionary<string, MetadataItem> allMembers, Dictionary<string, ReferenceItem> allReferences, NamespaceLayout namespaceLayout) in YamlMetadataResolver.cs:56
  at MetadataModel ResolveMetadata(Dictionary<string, MetadataItem> allMembers, Dictionary<string, ReferenceItem> allReferences, NamespaceLayout namespaceLayout) in YamlMetadataResolver.cs:33
  at void <CreateManagedReference>g__ResolveAndExportYamlMetadata|2(Dictionary<string, MetadataItem> allMembers, Dictionary<string, ReferenceItem> allReferences) in DotnetApiCatalog.ManagedReference.cs: 
     51
  at void CreateManagedReference((ValueTuple<IAssemblySymbol, Compilation> symbol) assemblies, ExtractMetadataConfig config, DotnetApiOptions options) in DotnetApiCatalog.ManagedReference.cs:45
  at async Task <Exec>g__Build|5_0(ExtractMetadataConfig config, DotnetApiOptions options) in DotnetApiCatalog.cs:120
  at async Task Exec(MetadataJsonConfig config, DotnetApiOptions options, string configDirectory, string outputDirectory) in DotnetApiCatalog.cs:72
  at void <Execute>b__0() in MetadataCommand.cs:18
  at int Run(LogOptions options, Action run) in CommandHelper.cs:48
  at int Execute(CommandContext context, MetadataCommandOptions options) in MetadataCommand.cs:14
  at Task<int> Execute(CommandContext context, CommandSettings settings) in CommandOfT.cs:40
  at Task<int> Execute(CommandTree leaf, CommandTree tree, CommandContext context, ITypeResolver resolver, IConfiguration configuration) in CommandExecutor.cs:144
  at async Task<int> Execute(IConfiguration configuration, IEnumerable<string> args) in CommandExecutor.cs:83
  at async Task<int> RunAsync(IEnumerable<string> args) in CommandApp.cs:84

I replaced the actual namespace with <...>.
In our case we have a couple of assemblies that offer different extensions for HttpClient, but share the same namespace.
With "namespaceLayout": "flattened" we don't have any issues.

@trb5016
Copy link

trb5016 commented Jun 12, 2024

A few minutes of debugging tells me that the problem occurs because I have a (generated) type in the System namespace, which causes a conflict in GenerateNestedTocStructure because allReferences already contains "System", so there is a duplicate key error when trying to add the namespace to namespacedItems and again to allReferences.

Just chiming in to say that I have pretty much the same issue - an extension method in the System namespace residing in my own assembly prompts the same error. (Whether I should be doing that or not is a separate question...)

@filzrev
Copy link
Contributor

filzrev commented Jun 20, 2024

It seems original reported issue can be resolved by updating PolySharp to PolySharp 1.14.1

If there are another issue that relating to namespace and "namespaceLayout": "nested".
Please provide minimal reproduceable project files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A bug to fix dotnet Generate .NET API reference docs
Projects
None yet
Development

No branches or pull requests

4 participants