-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
App throws TypeLoadException when published trimmed but works fine when published native AOT (no trim warnings) #102796
Comments
Tagging subscribers to this area: @agocke, @sbomer, @vitek-karas |
Here's a minimal repro console app. Publish this native AOT it works, publish it trimmed it throws // Get message via generic method
var message = MessageFactory.GetMessage<TypeWithStaticMessage>();
Console.WriteLine(message);
// Get message directly from type
var message2 = TypeWithStaticMessage2.GetMessage();
Console.WriteLine(message2);
public static class MessageFactory
{
public static string GetMessage<T>() where T : ITypeWithStaticMessage
{
return T.GetMessage();
}
}
public class TypeWithStaticMessage : ITypeWithStaticMessage
{
// Force the string to have dynamic element so that it doesn't get compiled in as a literal
public static string GetMessage() => $"Hello from {nameof(TypeWithStaticMessage)}, the time is {TimeOnly.FromDateTime(DateTime.Now)}";
}
public class TypeWithStaticMessage2 : ITypeWithStaticMessage
{
// Force the string to have dynamic element so that it doesn't get compiled in as a literal
public static string GetMessage() => $"Hello from {nameof(TypeWithStaticMessage2)}, the time is {TimeOnly.FromDateTime(DateTime.Now)}";
}
public interface ITypeWithStaticMessage
{
abstract static string GetMessage();
} |
Figured out a workaround by changing the method name and then make the generated types explicitly implement the interface methods and forcing the non-interface methods to call through a generated factory method that then invokes the explicitly implemented methods via the interface. Fair amount of indirection but doing it this way results in the interface implementation on the types themselves not being stripped. |
More comments too
* hacky hacky hack * More hacky * WIP * Update TODO comment * More WIP * WIP * Supports full trimming now * Update RazorSlices.Samples.WebApp.csproj * Cleanup * More cleanup * Trying to add publish tests * urgh round and round we go * wip * Working again * Tweaks * WIP * Update RazorSliceFactory.cs * Fixes for trimmed/non-AOT mode * Add JSON config for AOT * Remove unused code * Remove more unused code * Update README.md * Source Generator (#41) * Update README.md * Add code generator * Add type name validation --------- Co-authored-by: Damian Edwards <damian@damianedwards.com> * More generator cleanup * More tweaks * More tweaks * Comment tweaks * Remove props & make PathUtils honor OS * Update CSharpCodeValidationTests.cs * Update global.json * Remove net6 * Fix RDG failing * More links in footer * Fix infinite loop in HTML encoding Fixes #37 * Remove unused compiler directives * Layouts working for BufferWriterCase * Update RazorSlice.cs * Add support for layout sections * Ensure slices are disposed when using layouts * Update _build.yml * More fixes for #37 * Add some tests * Update .gitignore * Fix method names on RazorLayoutSlice * WIP use interfaces for declaring use of layouts * Tweaks * Add another encoding test * Update PublishSample.cs * Remove unused code & add comments * More comments * Rename IUseLayout to IUsesLayout. More doc comments & things. * Workaround for dotnet/runtime#102796 More comments too * Ensure response has started before rendering slices * Use PipeWriter directly instead of IBufferWriter<byte> * Suppress warning * Implement auto flushing with a pooled tracking PipeWriter * Make initialize internal & other small tweaks * Move RazorSlice writing methods into separate file * Added benchmarks * Separate benchmarks into separate apps * Use default HtmlEncoder * Refactor benchmarks * Remove blank line * Add benchmark using RazorSlices from nuget * Add pride & prejudice benchmark * Try to use build configurations for benchmarks * Revert "Try to use build configurations for benchmarks" This reverts commit b83495e. * Try to use build configuration for benchmarks * Benchmarks working * More benchmarks updates * More benchmarks * Added lorem25 impl for RazorComponents * Delete unused image files * Move common benchmark props to Directory.Build.props * Add a WriteHtml overload for writing a string value without HTML encoding * Add more benchmarks * Add BlazorSSR lorem to benchmarks * Fix sln build configuration * Add a micro benchmark comparing prev to local FIxed stack overflow when rendering with layout to TextWriter too * Add profiling harness console app * Update README.md --------- Co-authored-by: Oga <m26416083@alumni.petra.ac.id>
Is this a change we'd backport to 8.x? |
Seems reasonable , if we believe risk is low |
@DamianEdwards Does the app work if you just added an explicit implementation that forwards to the public static method? I don't think the call through a factory method should be necessary. I haven't looked into all the usage patterns that would affect trimmed output, but the minimal repro works with this. // Get message via generic method
var message = MessageFactory.GetMessage<TypeWithStaticMessage>();
Console.WriteLine(message);
// Get message directly from type
var message2 = TypeWithStaticMessage2.GetMessage();
Console.WriteLine(message2);
public static class MessageFactory
{
public static string GetMessage<T>() where T : ITypeWithStaticMessage
{
return T.GetMessage();
}
}
public class TypeWithStaticMessage : ITypeWithStaticMessage
{
+ static string ITypeWithStaticMessage.GetMessage() => GetMessage();
// Force the string to have dynamic element so that it doesn't get compiled in as a literal
public static string GetMessage() => $"Hello from {nameof(TypeWithStaticMessage)}, the time is {TimeOnly.FromDateTime(DateTime.Now)}";
}
public class TypeWithStaticMessage2 : ITypeWithStaticMessage
{
+ static string ITypeWithStaticMessage.GetMessage() => GetMessage();
// Force the string to have dynamic element so that it doesn't get compiled in as a literal
public static string GetMessage() => $"Hello from {nameof(TypeWithStaticMessage2)}, the time is {TimeOnly.FromDateTime(DateTime.Now)}";
}
public interface ITypeWithStaticMessage
{
abstract static string GetMessage();
} |
Ah interesting. Let me update my generator to just do that and I'll let you know. |
Yep that worked, thanks! |
* Simplified for the workaround for dotnet/runtime#102796 * Update RazorSlices.Samples.WebApp.csproj
Description
Repo: https://github.com/DamianEdwards/RazorSlices/tree/aot/samples/RazorSlices.Samples.WebApp
I'm updating my Razor Slices library to support native AOT and am running into a scenario where the sample app produces no warnings when published as trimmed or as native AOT, and runs successfully when published native AOT, but throws a
TypeLoadException
when running after publishing trimmed.The issue appears to be an interface implementation being trimmed from a type that's generated by a source generator. The method in question is a static abstract interface member. Notably, this method is not called via the interface in a generic fashion anywhere, which differs from other generated types in this app using the same pattern. I'm assuming this is the cause of the issue.
Note that if the app is also configured to publish self-contained, the error message does not include a description which makes it much harder to diagnose the root cause:
Reproduction Steps
aot
branch.\samples\RazorSlices.Samples.WebApp\
dotnet publish
to publish the app as native AOT.\bin\Release\net8.0\win-x64\publish\RazorSlices.Samples.WebApp.exe
to run the published apphttp://localhost:5000/
and click around the pages of the site, seeing it worksRazorSlices.Samples.WebApp.csproj
file so that<PublishAot>true</PublishAot>
is commented out and<PublishTrimmed>true</PublishTrimmed>
, e.g.:8.Run
dotnet publish
to publish the app trimmed9. Run
.\bin\Release\net8.0\win-x64\publish\RazorSlices.Samples.WebApp.exe
to run the published app10. Open a browser and navigate to
http://localhost:5000/
11. Note the exception message in the terminal the app was run from
Expected behavior
As not trim warnings are produced on publish, and the app works as expected when published native AOT, I expect it to work when published trimmed.
Actual behavior
The app throws an exception at runtime after being published trimmed.
Regression?
Not sure but it repros with both SDK versions 8.0.106 and 8.0.300 on Windows x64
Known Workarounds
None
Configuration
Windows 11 x64
.NET SDK 8.0.106 and 8.0.300
Other information
No response
The text was updated successfully, but these errors were encountered: