Skip to content

Working version#1

Open
NPatch wants to merge 1 commit intoMarcelVersteeg:masterfrom
NPatch:master
Open

Working version#1
NPatch wants to merge 1 commit intoMarcelVersteeg:masterfrom
NPatch:master

Conversation

@NPatch
Copy link

@NPatch NPatch commented Jan 27, 2026

First off, I added MessageImportance.High in Log.LogMessage calls because otherwise they are not displayed and debugging becomes difficult.

Second, I noticed that in:

NpmPackage? npmPackage = RegistryClient.GetPackageData(npmPackageInfo.Name,
null/*ns*/,
CancellationToken.None).
Result;

RegistryClient.GetPackageData is called and Result is asked for instantly when you're supposed to await it.
Instead store in Task<NpmPackage?> var and call .Wait(). Probably the reason why it's not always working right.

I tried a few things to get it working with the JsonSerializerContext, but ultimately, I opted to add a local version of the NpmRegistry.Wrapper and try out stuff. One such case was to switch GetFromJsonAsync(url, context, ...) to GetFromJsonAsync<NpmPackage>(url,...) and it worked, as in it moved on, did not throw the error and tried to get the json data from the registry. But it did fail to get everything correctly. My theory is that it failed to grab fields that were separate classes (DictTags, Versions etc).

This part specifically failed because DistTags was null, and because of Log.LogError it failed after just chart.js:

string? latestVersionString = npmPackage.DistTags?.Latest;
if (null != latestVersionString)

As for the main issue, I think it's because System.Net.Http.Json, among others, is trimmable (iirc, I saw the it in dnspy) and by using the interface to decouple the Task dll from the NpmRegistryClient code basically hides the json stuff,
which likely ends up hiding the call to the assembly, ergo it's trimmed, which also likely ends up trimming types from the NpmRegistry.Wrapper assembly. One more thing that also nudges me towards the trimming
idea is that NpmRegistry.Wrapper, uses generators for the JsonSerializerContext (much like DataTypes and Tasks) and they are likely not generated and propagated through the assembly properly (at least when integrated through the nuget package).

I looked at the _bin/ folders where other libs have no problem generating their own JsonSerializerContext classes, but NpmRegistry.Wrapper's was nowhere to be found.

So to try and test this, I added a console app to call the Task directly for a first test, removed the ModelsSerializerContext, provided my own version of GetFromJsonAsync, basically a function that downloads the whole response first into a byte array and calls deserialize and it worked. The idea was to remove the dependency to the trimmable function call and also by removing the JsonSerializerContext, remove the problem of the generated files being inaccessible to the Task code on runtime. Got the response for all 4 npm packages, fully deserialized.

@MarcelVersteeg
Copy link
Owner

@NPatch Sorry for the late reply, other more important things came up. I looked at your patch, and I still have a few things that bother me.

Implementing your own deserializer is something that has also crossed my mind. However, by disabling the JsonSerializerContext, the NpmRegistryClient is no longer AOT compatible as far as I know. You also suppressed the IL3050 error I see. The addition of the JsonSerializerContext was actually something I contributed to the package, in an attempt to fix the issue you also encountered, that originally it did not return the complete data (indeed especially DistTags property was null), while the complete JSON was indeed received.

The funny thing is though, that when I use my original version and run the Tasks project as an application (that executes the same task code), it DOES succeed. This makes me wonder if trimming is really an issue here. If it would be, I would expect the same issue to occur when the task is executed directly as a console application. I also tried to run the task during the build after explicitly setting the options IsAotCompatible and PublishTrimmed in the root Directory.Build.props to False and this did not resolve the exception (though the NuGet package is of course still marked as IsAotCompatible). I assume that explicitly setting these properties to False would disable all trimming.

You also mention that the JsonSerializerContext might not be propagated correctly via the NuGet package. What I do see when I open the NpmRegistry.Wrapper.dll (as it is in the downloaded NuGet package) in ILSpy, that the NpmRegistry.Wrapper.Models.ModelsSerializerContext is there and contains all the type information of all the classes in the model, including all the generated deserialization code.

I looked at the _bin/ folders where other libs have no problem generating their own JsonSerializerContext classes, but NpmRegistry.Wrapper's was nowhere to be found.
When building it yourself with the default properties as I have defined, I would indeed expect generated files to be saved in _bin/_application/_generated/NpmRegistry.Wrapper/Debug (for a debug build). It is indeed strange that these generated files are not there.

I really appreciate your suggestions, but so far I am not very happy with the proposed solution..

@NPatch
Copy link
Author

NPatch commented Feb 7, 2026

For what it's worth, I managed to compile everything and make it run, again by reconnecting the csproj of the NpmRegistry.Wrapper, setting it to .NET10, but keeping the dependencies on .NET9..........I have no clue why or how, but it does work with the rest as-is, as in using the JsonSerializerContexts provided. Did you make any progress yourself?

@MarcelVersteeg
Copy link
Owner

MarcelVersteeg commented Feb 8, 2026

@NPatch

For what it's worth, I managed to compile everything and make it run, again by reconnecting the csproj of the NpmRegistry.Wrapper, setting it to .NET10, but keeping the dependencies on .NET9..........I have no clue why or how, but it does work with the rest as-is, as in using the JsonSerializerContexts provided. Did you make any progress yourself?

That is good to hear. Unfortunately, I did not have any progress myself yet. As it is for a personal (non work-related project), time is currently very limited as I am also in the middle of a home renovation which takes more time to manage than anticipated.

However it is quite strange that just referencing the NpmRegistry.Wrapper project (instead of the NuGet package) works when setting the project to .NET10. When looking into it earlier I did the following (next to other things BTW);

  1. Fork and clone the NpmRegistry.Wrapper repository
  2. Set a new version number in the project
  3. Compile the project for .NET10
  4. Changed my NuGet.config to also load NuGet packages from the binary output folder of the NpmRegistry.Wrapper project
  5. Changed the package reference to the version I set in step 2.

This still resulted in the same MissingMethodException. It is very strange that directly referencing the csproj and setting it to .NET10 fixes the issue. It indeed seems that something is not completely correct in the NuGet package itself then for whatever reason.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants