Skip to content

Conversation

@stephentoub
Copy link
Member

No description provided.

}

return Utilities.ToCamelCase(name);
return JsonNamingPolicy.CamelCase.ConvertName(name);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one isn't 100% identical. The System.Text.Json method is almost exactly the same as the ToCamelCase utility being replaced, except that the STJ method looks for ' ' as a separator whereas the ToCamelCase routine looks for anything that's char.IsSeparator. If that difference is important, this part can be reverted.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The separator is of no concern since we're translating .NET identifiers, which have no whitespace.
What is possibly an issue however is that you're adding an STJ dependency in code that runs in non-STJ scenarios, requiring STJ to be loaded where it may not have been before. Visual Studio counts assembly loads, so we deliberately avoid dependencies on particular serialization libraries unless we're in code that already is specific to that library.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, so it's in the transitive graph here but you're able to avoid loading it by avoiding it in some code paths? How are regressions caught other than by your watchful code review eye? After the fact by the perf tooling?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if nothing else than our Perf DDRITs will likely catch it. (or, miss it, if STJ happened to have already loaded for other reasons, but we're actively trying to consolidate serialization technologies to reduce wasted assembly loads).
We also have at least one test that uses AppDomains to verify that we don't load unrelated serialization libraries, but IIRC it's off in our PR builds because it's not entirely stable.

StreamJsonRpc has 3 serialization library dependencies (Newtonsoft.Json, MessagePack-CSharp, and STJ). And it may pick up a 4th by the end of the year. It's unfortunate that in .NET we have to choose between having 3 assemblies (StreamJsonRpc, a serialization library, plus a binding library) or taking a hard dependency in StreamJsonRpc to reduce this to 2 assemblies. I know AOT resolves this, for those apps that can do AOT and for libraries that are AOT safe (StreamJsonRpc is not -- yet). So we try to get the best of both worlds by taking the hard dependency and then avoiding references to it outside of code that really requires it.

The NetArchTest.Rules nuget package includes the ability to functionally prove that certain types or namespaces take no dependencies on other areas (e.g. assemblies). I only recently discovered it and it may help us enforce dependency compartmentalizing for StreamJsonRpc via our functional unit tests.

Copy link
Member

@AArnott AArnott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much for your insights and fixes!

@AArnott AArnott enabled auto-merge March 4, 2025 00:01
@AArnott AArnott merged commit 8c6f27b into microsoft:main Mar 4, 2025
6 of 7 checks passed

// Now go back and fill in the header with the actual content length.
Utilities.Write(this.Writer.GetSpan(sizeof(int)), checked((int)contentSequence.Length));
BinaryPrimitives.WriteInt32BigEndian(this.Writer.GetSpan(sizeof(int)), checked((int)contentSequence.Length));
Copy link
Member Author

@stephentoub stephentoub Mar 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this another one that's going to cause you to load a library you didn't want to?

Hmm, probably not, since you're already using span.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for checking. Ya, we're using System.Memory heavily throughout the library.

Comment on lines 295 to 299
if (rpcInterfaceCode.HasValue)
{
methodName = rpcInterfaceCode + "." + method.Name;
rpcMethodName = rpcInterfaceCode + "." + rpcMethodName;
methodName = $"{rpcInterfaceCode.GetValueOrDefault()}.{method.Name}";
rpcMethodName = $"{rpcInterfaceCode.GetValueOrDefault()}.{rpcMethodName}";
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

                    if (rpcInterfaceCode is { } localRpcInterfaceCode)
                    {
                        methodName = $"{localRpcInterfaceCode}.{method.Name}";
                        rpcMethodName = $"{localRpcInterfaceCode}.{rpcMethodName}";
                    }

/cc @stephentoub 😄

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or why not just:

                    if (rpcInterfaceCode.HasValue)
                    {
                        methodName = $"{rpcInterfaceCode}.{method.Name}";
                        rpcMethodName = $"{rpcInterfaceCode}.{rpcMethodName}";
                    }

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the latter, just because nullable value types are a bit less efficient in interpolated strings. Probably not a big deal, though.

For the former, seems like a stylistic preference.

Copy link

@paulomorgado paulomorgado Mar 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's exactly the same code, but more CSharpy. 😄

It just shows you were used to doing the right thing before C# had pattern matching. 😄

@stephentoub stephentoub deleted the afewnits branch March 18, 2025 13:53
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.

3 participants