JSRuntime.Invoke APIs aren't correctly annotated for trimming
See original GitHub issueFollow up to https://github.com/dotnet/aspnetcore/pull/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 a JsonTypeInfo
to go with it. Something like so:
TValue IJSRuntime.InvokeAsync<TArg, TValue>(string method, TArg arg, JsonTypeInfo<TArg> t1, JsonTypeInfo<TValue> t2, CancellationToken cancellationToken)
At the very least, we could require that all code in the framework uses this API for it’s interop.
Issue Analytics
- State:
- Created 2 years ago
- Comments:9 (6 by maintainers)
Top GitHub Comments
Yes, those are separate problems. Solving internal client side interop will fix CSP of Blazor as a framework. This is problem with
IJSRuntime
which will not go away by solving CSP.If users adopted new runtime interop with
JSImportAttribute
instead ofIJSRuntime
it would help. ButJSImportAttribute
is not available on server side (hybrid Blazor), so it’s not complete solution.Adding new trimming friendly signatures to the
IJSRuntime
is way to go. And maybe marking the old signatures obsolete ?I think that implementing Roslyn code analyzer to hint or force users to pass
JsonTypeInfo
orJsonSerializerContext
would be good.I wanted to file a similar issue, as I essentially wanted to advise something very close to the one outlined here.
IJSRuntime.InvokeAsync
methods need the[RequiresUnreferencedCode]
attribute applied, as theIJSInProcessRuntime
already does on theInvoke
method.IJSRuntime
is not correctly annotated, I guess people expect it to just work, but it will fail if the argument types aren’t preserved. The question then (after fixing the annotations) becomes how to actually fix these issues in code, as [RequiresUnreferencedCode] will mitigate it to the caller (still the user) and [UnconditionalSuppressMessage] will just suppress it, but neither will actually solve the problem of actually keeping the correct types in the assemblies (although my point no. 2 above could solve that problem).I hope @guardrex won’t mind me pinging.
DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties
, as it is defined in https://github.com/dotnet/aspnetcore/blob/main/src/Shared/LinkerFlags.cs asJsonSerialized
. But in fact, serialization requires onlyDynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.PublicProperties
(reading them, so only theget
accessors), and only deserialization (so, return types) requiresDynamicallyAccessedMemberTypes.PublicConstructors
as well (and writing the properties, soset
accessors).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.