dotnet/templating

InvalidOperationException: Sequence contains more than one element in LocalizationModelDeserializer.cs

KirillOsenkov opened this issue · 3 comments

I'm hitting an InvalidOperationException here:
https://github.com/dotnet/templating/blob/main/src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/LocalizationModelDeserializer.cs#L115

System.InvalidOperationException: Sequence contains more than one matching element
   at TSource System.Linq.Enumerable.SingleOrDefault<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate)
   at IReadOnlyDictionary<string, ParameterChoiceLocalizationModel> Microsoft.TemplateEngine.Orchestrator.RunnableProjects.LocalizationModelDeserializer.LoadChoiceModels(IEnumerable<(IEnumerable<string> NameParts, string LocalizedString)> strings)
   at IReadOnlyDictionary<string, IParameterSymbolLocalizationModel> Microsoft.TemplateEngine.Orchestrator.RunnableProjects.LocalizationModelDeserializer.LoadSymbolModels(List<(string Key, string Value)> localizedStrings)
   at ILocalizationModel Microsoft.TemplateEngine.Orchestrator.RunnableProjects.LocalizationModelDeserializer.Deserialize(IFile file)
   at IList<ITemplate> Microsoft.TemplateEngine.Orchestrator.RunnableProjects.RunnableProjectGenerator.GetTemplatesAndLangpacksFromDir(IMountPoint source, out IList<ILocalizationLocator> localizations)
   at ScanResult Microsoft.TemplateEngine.Edge.Settings.Scanner.ScanMountPointForTemplatesAndLangpacks(MountPointScanSource source)
   at ScanResult Microsoft.TemplateEngine.Edge.Settings.Scanner.Scan(string mountPointUri, bool scanForComponents)
   at Task<TemplateCache> Microsoft.TemplateEngine.Edge.Settings.TemplatePackageManager.UpdateTemplateCacheAsync(bool needsRebuild, CancellationToken cancellationToken)+(int index) => { }
   at ParallelLoopResult System.Threading.Tasks.Parallel.ForWorker<TLocal>(int fromInclusive, int toExclusive, ParallelOptions parallelOptions, Action<int> body, Action<int, ParallelLoopState> bodyWithState, Func<int, ParallelLoopState, TLocal, TLocal> bodyWithLocal, Func<TLocal> localInit, Action<TLocal> localFinally)+() => { }

When scanning this file:
C:\Program Files\dotnet\templates\8.0.3\microsoft.dotnet.web.projecttemplates.8.0.8.0.3.nupkg

It returns 2 elements for choices/None/description for this file:

image

rough sample code to hit this:

            using (var templateEngineBootstrapper = new TemplateEngineBootstrapper())
            {
                var dotNetSdkInfo = new DotNetSdkInfo();
                templateEngineBootstrapper.AddComponent(typeof(ITemplatePackageProviderFactory), new DotNetTemplatePackageProviderFactory(dotNetSdkInfo));

                var filters = new Func<ITemplateInfo, MatchInfo>[]
                {
                    WellKnownSearchFilters.TypeFilter("project"),
                    WellKnownSearchFilters.LanguageFilter("C#")
                };
                var templateMatches = templateEngineBootstrapper.GetTemplatesAsync(filters, true, CancellationToken.None).Result;
                return templateMatches.Select(match => new DotNetProjectTemplate(this, match.Info, dotNetSdkInfo));
            }

@MiYanni since you've recently fixed a similar bug

Or is it the same exact issue as #7147?

Can confirm that updating to https://www.nuget.org/packages/Microsoft.TemplateEngine.IDE/8.0.202 fixes the issue.

@KirillOsenkov It was a latent bug that didn't manifest until certain template packages were published. At least I added a unit test so it shouldn't happen again.