[CSHARP-4530] TryParseGenericTypeName error in non generic type Created: 16/Feb/23  Updated: 27/Oct/23  Resolved: 06/Mar/23

Status: Closed
Project: C# Driver
Component/s: Serialization
Affects Version/s: 2.19.0
Fix Version/s: None

Type: Bug Priority: Unknown
Reporter: Andrea Guerrieri Assignee: Boris Dogadov
Resolution: Gone away Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

Prerequisite

I have the following document:

1
{
2
    "State": {
3
        "Date": null,
4
        "Time": null,
5
        "Filters": {
6
            "_t": "System.Collections.Generic.List`1[[JobManager.Common.TimeFilter, JobManager.Common]]",
7
            "_v": [
8
            {
9
                "Type": 2,
10
                "Values": [
11
                6
12
                ],
13
                "Mode": 1
14
            }
15
            ]
16
        }
17
    }
18
}

*irrelevant parts omitted

Mapped to the following c# Type

1
public class ObjectDescriptor
2
{
3
    public string? Id { get; set; }
4
    public string? TypeName { get; set; }
5
    public ObjectState? State { get; set; }
6
}

where ObjectState

1
 public class ObjectState : Dictionary<string, object?>

The actual instance of the dictionary contains a key called Filters ,
with a value of type  List<TimeFilter>

The class TimeFilter

1
public class TimeFilter
2
{
3
    public TimeFilterType Type { get; set; }   //Enum     
4
    public IList<int>? Values { get; set; }        
5
    public TimeFilterMode Mode { get; set; } //Enum
6
}

Problem

The method GetActualType in class TypeNameDiscriminator calls {{TryParseGenericTypeName }}passing the following typeName:

1
System.Collections.Generic.List`1[[JobManager.Common.TimeFilter, JobManager.Common]]

At first call, returns as typeArgumentNames the following string:

[JobManager.Common.TimeFilter, JobManager.Common]

The subsequential recursive call to GetActualType with that argument as typeName,
results in a wrong match in TryParseGenericTypeName (wrongly parsed as generic),
returning an empty string ("") in typeArgumentNames

The empty string causes an exception when is called:

1
Type.GetType(typeName);

The exception is:

1
String cannot have zero length

Framework: .NET 7.0.200-preview.22628.1
MongoDB.Driver: 2.19.0



 Comments   
Comment by PM Bot [ 06/Mar/23 ]

There hasn't been any recent activity on this ticket, so we're resolving it. Thanks for reaching out! Please feel free to comment on this if you're able to provide more information.

Comment by Boris Dogadov [ 17/Feb/23 ]

Hi maillist@eusoft.net 

We only get to that particular recursion call because System.Type.GetType("System.Collections.Generic.List`1[[JobManager.Common.TimeFilter, JobManager.Common]]") call returns null for some reason.

Could you please check whether 

System.Type.GetType("System.Collections.Generic.List`1[[JobManager.Common.TimeFilter, JobManager.Common]]")

returns a valid type, and what does 

typeof(List<JobManager.Common.TimeFilter>).FullName

 return?

If order to investigate further, we would need to reproduce the issue.
Could you please provide a simple repro code in form of 

var x = new MyObject() { ... }
var json = x.ToJson()
var xDeserialized = BsonSerializer.Deserialize<MyObject>(json);

that demonstrates the failure?

Thanks.

 

Comment by Andrea Guerrieri [ 17/Feb/23 ]

the problem seem in the implementation of TryParseGenericTypeName

https://github.com/mongodb/mongo-csharp-driver/blob/5585012affeef6387fd9e65c265776d4bca9174a/src/MongoDB.Bson/Serialization/TypeNameDiscriminator.cs#L76

var leftBracketIndex = typeName.IndexOf('[');
if (leftBracketIndex != -1)
{
   //omitted
   
    return true;
} 

is not enough check for [ to consider the typeName as Generic, you should look imho at  ` symbol to ensure that there is an actual arguments list. Or at worse, return false if typeArgumentNames array is empty or contains only empty strings.

JobManager.Common.TimeFilter exists in the assembly

Comment by Boris Dogadov [ 17/Feb/23 ]

Hi maillist@eusoft.net, thank you for the all detailed info.

I was able to reproduce this behaviour only when type discriminator for the generic type ([JobManager.Common.TimeFilter, JobManager.Common]) was invalid.
As you mentioned, in that case, "String cannot have zero length" is thrown instead of more informative message (tracking that in CSHARP-4533)

My suspicion is that JobManager.Common.TimeFilter type does not exist in JobManager.Common assembly.
If that's not the case, to investigate further, please provide as self contained repro, of a failing serialization roundtrip (where an object is serialized but fails to deserialize)

Generated at Wed Feb 07 21:48:30 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.