-
Notifications
You must be signed in to change notification settings - Fork 10.3k
JSRuntime.Invoke APIs aren't correctly annotated for trimming #39839
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
Comments
FYI @TanayParikh |
Thanks for contacting us. We're moving this issue to the |
I wanted to file a similar issue, as I essentially wanted to advise something very close to the one outlined here.
public interface IJSRuntime
{
// Existing signature, but this should also have [RequiresUnreferencedCode] as the "args" are dynamically referenced.
ValueTask<TValue> InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue>(string identifier, object?[]? args);
// Added overloads, with default implementation, doesn't break trimming (probably can use [UnconditionalSuppressMessage] or similar).
ValueTask<TValue> InvokeAsync<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] TValue>(string identifier) => InvokeAsync<TValue>(identifier, null);
ValueTask<TValue> InvokeAsync<[DynamicallyAccessedMembers(JsonSerialized)] TValue, [DynamicallyAccessedMembers(JsonSerialized)] TArg>(string identifier, TArg argument) => InvokeAsync<TValue>(identifier, new object?[] { argument });
// And so on, for multiple arguments with <TArg1, TArg2>, up until maybe 3 or 4?
I hope @guardrex won't mind me pinging.
This probably doesn't make too much difference in most cases, but it might trim out some unused public constructors, leaving us with a smaller assembly size in the end. |
@pavelsavara would this still be applicable once we update to using the new JS interop with [JSImportAttribute] to make it CSP friendly? |
Yes, those are separate problems. Solving internal client side interop will fix CSP of Blazor as a framework. If users adopted new runtime interop with Adding new trimming friendly signatures to the I think that implementing Roslyn code analyzer to hint or force users to pass |
Also wanted to mention there are some incorrect suppressions too, which can and do break functionality. I found one here, but I slightly remember more void-returning ones having this mistake: aspnetcore/src/JSInterop/Microsoft.JSInterop/src/JSInProcessObjectReferenceExtensions.cs Line 20 in 1c385f4
The justification states "The method returns void, so nothing is deserialized.". Although the method indeed returns void, but the A generic typed alternative would go a long way. @pavelsavara I started to migrate to the new
👍👍👍 |
That's there on purpose, making OOP calls over interop boundary is usually bad design because those tend to be chatty interactions. Especially talking to DOM. Instead you are better off if you aggregate the logic into single JS method and call that. Also for first version of the interop we limitted the scope. We started with low level and fast scenarios. We will collect feedback about use cases and see if they could be solved by code generators developed by the community or if there need to be runtime improvements. That said, what is the specific use case in which you think it's good idea to call methods on JS instances ? |
There isn't really a definite "gotcha", but obviously sometimes you need the context of the object to execute a function... That's how object-oriented programming was born. Yes, I can "simulate" object-oriented design by making global/static methods in JavaScript and passing the context object as its first parameter. But that defeats the whole purpose of object-oriented features in both JavaScript and C#. I'd rather not bind to JavaScript's I'm not saying it's effectively a "good idea" to call methods on instances, but for example I create typed proxy instances for JavaScript managed instances for third party libraries. I store the Bootstrap plugin "ScrollSpy" instance instantiated along with my Blazor component, so their lifecycles are synchronized, and event handling can be delegated this way from the component through to the third party library. I could mess with lookup dictionaries on both sides and generated IDs, but that's just me writing the framework for something that could be in it anyway.
This is exactly right. But I will call the interaction anyways (because I need to), whether the framework provides the API for it or not. It's just harder to do and more inconvenient if there is no way to call methods directly on objects. If it's an artificial limitation, then it's just making harder for users to generalize code, or write dependent libraries. If the user calls DOM queries with each method call in a loop, that's on them, their mistake. But preventing calling methods in object instances won't prevent this in any way, in my opinion. |
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process. |
Thanks for contacting us. We're moving this issue to the |
Follow up to #39838. JSRuntime's API (excluding the unmarshalled ones) use JSON serialization to serialize the args array and as such are subject to being trimmed away. S.T.Js API for its serialization are annotated with RequiresUnreferencedCode with a recommendation to use the source-generator based overload to avoid this.
Blazor's APIs suppress STJ's warnings (since it happens deep in its bowels) and don't have a trimmer safe alternative. Perhaps one option is to annotate all of the JSRuntime APIs with
RequiresUnferencedCode
and add an JSRuntime.InvokeAsync overload that accepts exactly one argument aJsonTypeInfo
to go with it. Something like so:At the very least, we could require that all code in the framework uses this API for it's interop.
The text was updated successfully, but these errors were encountered: