-
Notifications
You must be signed in to change notification settings - Fork 4.9k
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
[For Discussion] Move JsonData to Core #31769
Conversation
API change check APIView has identified API level changes in this PR and created following API reviews. |
I worry that this view does not scale to large JSON payloads. |
@@ -91,7 +89,7 @@ public void AnalyzeConversation() | |||
#endregion | |||
|
|||
Assert.That(response.Status, Is.EqualTo(200)); | |||
Assert.That(conversationPrediction.GetProperty("topIntent").GetString(), Is.EqualTo("Send")); | |||
Assert.That((string)conversationPrediction.TopIntent, Is.EqualTo("Send")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A string cast is required here for this to succeed right now.
#if !SNIPPET | ||
aspects.Add(summary.GetProperty("aspect").GetString()); | ||
aspects.Add((string)summary.Aspect); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A string cast is required here to succeed.
sdk/core/Azure.Core/src/JsonData.cs
Outdated
/// </summary> | ||
/// <param name="utf8Json">A UTF8 encoded string representing a JSON value.</param> | ||
/// <returns>A <see cref="JsonData"/> representation of the value.</returns> | ||
internal static JsonData Parse(BinaryData utf8Json) => new JsonData(JsonDocument.Parse(utf8Json)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handle IDisposable properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per @AlexanderSher:
I've created a small benchmark. It looks like disposing JsonDocument is quite important:
https://gist.github.com/AlexanderSher/251a035cfbbe539337e4a1c6504ff52b
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlexanderSher, does this address your concern on this? 795e2ff
|
||
Console.WriteLine($"Top intent: {conversationPrediction.GetProperty("topIntent").GetString()}"); | ||
Console.WriteLine($"Top intent: {conversationPrediction.TopIntent}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Discussed with @KrzysztofCwalina offline, but I don't think we should automatically convert camelCase JSON properties to PascalCase .NET properties on responses. Requests don't get the same treatment, so this may be confusing or even misleading. Say you get a response back, want to update it, and then send it back (which you also can't since JsonData is effectively immutable):
var json = response.Content.ToDynamic();
var data = new
{
Id = json.Id,
Foo = "new foo",
};
client.UpdateFoo(Request.Create(data)); // throws RequestFailedException: 400 BadParameter or something because the properties are supposed to be camelCase.
I appreciate we want to be idiomatic, but as soon as customers are having to deal with raw JSON - via System.Text.Json like my samples were before vs. what you're prototyping here with JsonData
(which is a remarkable improvement) - I don't think we should "auto-correct" anything. Python nor JS would since customers are working directly with the JSON data. I don't think C# / .NET should either.
Model classes give us this ability, and once we generate them (for Cadl or otherwise) we can and should do that translation because we can do so consistently.
/cc @tg-msft
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I don't understand the thinking there. We do this in our public models, and the idea is that JsonData is a stand-in until we add those types. Ideally, the customer would have to change very little to move to any types we added to a library. It's not that they're dealing with raw Json (which they can do easily if they want) -- it's a layer over the Json (or Xml, or whatever) that makes it conform to a higher .NET standard for look-and-feel. Is consistency with anonymous types your primary concern here, because I agree that is not good. Are there any other considerations I'm not thinking of?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see that this is a question about round-tripping the type, my apologies for having missed that the first time. We are planning to provide a separate API to handle-round tripping, that may be able to address this. I am still curious to know if there are other considerations here beyond the inconsistency across input/output that we should also be aware of.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assume with my example above that the JSON schema is indeed camelCase, as most services define (and should): the request would accept id
and foo
, not Id
and Foo
. However, by translating from camelCase to PascalCase we could give callers the impression that the properties are indeed Id
and Foo
.
This isn't just about roundtripping, though. It's about perception. If all the response properties are PascalCase, why wouldn't many think that request properties are too?
I appreciate this isn't "raw" JSON. That's not what I intended. But it's a very thin wrapper over raw JSON that is meant to provide a JSON-like interaction for the customer, yes? By morphing into something it's not just to seem idiomatic, we create this confusion of casing for customers. Why not just leave it with the exact shape - casing and all - as the service returns (response) and expects (request)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's totally fair - all good points. It feels like the question hinges on how thin the wrapper is and how well we document and illustrate via samples what the type is actually doing. If, for example, it also wraps other formats like XML, it might be more clear that you can't make too many assumptions about what's underneath.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this supports XML, I don't see my point changing: if an XML document uses camelCase or PascalCase (and in my experience it varies even more than with JSON, which is more often camelCase), we should leave casing as is to avoid confusion. If we start showing that customers can always use PascalCase for responses, why wouldn't they think they can use it for input as well? Or if they use the obj["foo"]["bar"]
pattern it will also vary from obj.Foo.Bar
. Changing cases like that just seems so jarring.
What benefit to the customer does translating the casing have? I can certainly see a lot of cons. The only pro is "it feels like C#", but they aren't working with generated types (C# or otherwise): they are working with thin wrappers over raw JSON, XML, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should ToDynamic
take an optional ObjectSerailizer
so folks can customize this? I feel like that would easily allow this to work for people who wanted it, but then we could get away with less magic by default if we didn't change the case.
Hi @annelo-msft. Thank you for your interest in helping to improve the Azure SDK experience and for your contribution. We've noticed that there hasn't been recent engagement on this pull request. If this is still an active work stream, please let us know by pushing some changes or leaving a comment. Otherwise, we'll close this out in 7 days. |
Context
Requirements
The main work needed, given that we have the prototype, is to:
There is a test showing this capability in the old PR: CanAccessArrayValues
var date = (DateTime)json;
or cast to custom model:var model = (FooModel)json.Foo
There is a proposal regarding an approach to enabling this in this commit. It suffers from the issue that it uses
JsonSerializer.Deserialize<T>
to do the conversion between JsonData and T, and we know that not all of our Azure SDK models are serializable via STJ.Suggested approach (tracked separately by #31943):
If this isn't "good" yet, let's clarify the ask.
We will file issues to track this.
Code sample
Per this comment:
The output of:
is