Skip to content
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

Examine JsonSerializer behavior for ref structs & pointers #34779

Closed
Tracked by #63918
layomia opened this issue Apr 9, 2020 · 11 comments
Closed
Tracked by #63918

Examine JsonSerializer behavior for ref structs & pointers #34779

layomia opened this issue Apr 9, 2020 · 11 comments
Labels
area-System.Text.Json enhancement Product code improvement that does NOT require public API changes/additions
Milestone

Comments

@layomia
Copy link
Contributor

layomia commented Apr 9, 2020

Related - #34777.

We should detect these types and fail gracefully rather than leaking exceptions from lower level APIs like Type.MakeGenericType.

@layomia layomia added this to the Future milestone Apr 9, 2020
@Dotnet-GitSync-Bot Dotnet-GitSync-Bot added the untriaged New issue has not been triaged by the area owner label Apr 9, 2020
@layomia layomia removed the untriaged New issue has not been triaged by the area owner label Apr 9, 2020
@loligans
Copy link

loligans commented Nov 14, 2020

Any workaround in the meantime? @layomia

Nevermind, I found that I could write my own JsonConverter for the Type.

@layomia
Copy link
Contributor Author

layomia commented Mar 23, 2021

@loligans unfortunately there's no workaround AFAIK. We'd need reflection support for ref structs to be able to support this. Ref structs can't be boxed or be generic parameters, so they are not friendly with System.Reflection APIs.

Nevermind, I found that I could write my own JsonConverter for the Type.

How were you able to do this? A ref struct can't be the T type used in a JsonConverter<T> instance.

@loligans
Copy link

@loligans unfortunately there's no workaround AFAIK. We'd need reflection support for ref structs to be able to support this. Ref structs can't be boxed or be generic parameters, so they are not friendly with System.Reflection APIs.

Nevermind, I found that I could write my own JsonConverter for the Type.

How were you able to do this? A ref struct can't be the T type used in a JsonConverter<T> instance.

@layomia I was able to do this by using ReadOnlyMemory instead

public class MemoryJsonConverter : JsonConverter<ReadOnlyMemory<byte>>
{
    public override ReadOnlyMemory<byte> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return reader.GetBytesFromBase64().AsMemory();
    }

    public override void Write(Utf8JsonWriter writer, ReadOnlyMemory<byte> value, JsonSerializerOptions options)
    {
        if (writer is null) { throw new ArgumentNullException(nameof(writer)); }
        writer.WriteBase64StringValue(value.Span);
    }
}

@layomia layomia changed the title Consider JsonSerializer support for ref structs Consider JsonSerializer support for ref structs & pointers Oct 11, 2021
@layomia
Copy link
Contributor Author

layomia commented Oct 11, 2021

This issue should also consider the scenario from #59936 which necessitated the use of [JsonIgnore]:

using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;

var sampleText = new TypeWithRefString();
var json = JsonSerializer.Serialize(sampleText); // ArgumentException Here
var deserialized = JsonSerializer.Deserialize<TypeWithRefString>(json); // And Here

internal class TypeWithRefString
{
    public ref string NameRef => ref Name;
    public string Name = "How many Richard Landers does it take to write a blog entry? Just one, you rock!";
}

@eiriktsarpalis
Copy link
Member

Is supporting ref structs and pointers important? Fundamentally they represent non-serializable entities (what does serializing byte* mean?) and adding support for them is not cheap, adding complexity to our infrastructure due to the aforementioned restrictions using them as generic parameters.

I would recommend explicitly not supporting these types, but provide escape hatches via the JsonIgnoreAttribute like #60024 is attempting to do. We might want to fail more gracefully with a meaningful error message (rather than the current Type.MakeGenericType throwing)

@eiriktsarpalis eiriktsarpalis modified the milestones: Future, 7.0.0 Oct 12, 2021
@layomia
Copy link
Contributor Author

layomia commented Oct 12, 2021

We might want to fail more gracefully with a meaningful error message (rather than the current Type.MakeGenericType throwing)

Yes this is the intent for these types, to detect them deterministically and fail gracefully.

@layomia layomia changed the title Consider JsonSerializer support for ref structs & pointers Examine JsonSerializer behavior for ref structs & pointers Oct 12, 2021
@eiriktsarpalis eiriktsarpalis added the enhancement Product code improvement that does NOT require public API changes/additions label Oct 15, 2021
@krwq
Copy link
Member

krwq commented Jul 7, 2022

I've added a fix for issue which sounds similar to this one in contract customization PR, can we verify it works as expected now? See test I added here: 5be7092#diff-c0f5d77b22f8bd7e41958095b0e9fc829a00de0104bf283035d81e6bb3d7b30eR599

@krwq
Copy link
Member

krwq commented Jul 7, 2022

I'm closing this for now please create new issue with repro if you feel like we've missed anything in there

@krwq krwq closed this as completed Jul 7, 2022
@eiriktsarpalis
Copy link
Member

@krwq the tests you cite are specific to contract customization. We should add a test that specifically validates the scenario described in, say, #34779 (comment). I would recommend reopening the issue until that is addressed.

@eiriktsarpalis
Copy link
Member

Let's reopen this, since we have failing tests linked to this issue:

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/34779")]
public async Task BindingBetweenRefProps()
{
string json = @"{""NameRef"":""John""}";
await Serializer.DeserializeWrapper<TypeWith_RefStringProp_ParamCtor>(json);
}

@eiriktsarpalis
Copy link
Member

The test in question is related to the issue better described in #46088. I think we should close this one since it's less concrete and address any issues related to unsupported types as they come up.

@ghost ghost locked as resolved and limited conversation to collaborators Sep 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Text.Json enhancement Product code improvement that does NOT require public API changes/additions
Projects
None yet
Development

No branches or pull requests

5 participants