xJayLee / protobuf-net

Automatically exported from code.google.com/p/protobuf-net
Other
0 stars 0 forks source link

DataContractJsonSerializer.WriteObject throws exception due to proto repeated (C# list) #76

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
hstahl AT Symantec DOT com
==============
This is a known as-designed issue that Microsoft knows of.
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?
FeedbackID=409970

What steps will reproduce the problem?
1. proto
message ProductDownloadUrl {
  required string url = 1;
  enum Type {
    Direct = 0;
    FSD = 1;
    PDM = 2;
  }
  required Type urlType = 2;
}

// Output from WebDLService.GetLatestProduct
message LatestProductResponse
{
    repeated ProductDownloadUrl url = 1;
}

2. Code that is generated looks like this.
    private readonly 
global::System.Collections.Generic.List<ProductDownloadUrl> _url = new 
global::System.Collections.Generic.List<ProductDownloadUrl>();

  public global::System.Collections.Generic.List<ProductDownloadUrl> Url
    {
      get{return _url; }
    }

the problem here is the "readonly" attribute and the getter should do a 
null check.

3. test code
DataContractJsonSerializer serializerResponse = new 
DataContractJsonSerializer(typeof(LatestProductResponse));

            LatestProductResponse lpr = new LatestProductResponse();
            lpr.Url.Add(new ProductDownloadUrl() { Url="test", 
UrlType=ProductDownloadUrl.Type.Direct });

            MemoryStream ms = new MemoryStream();
            serializerResponse.WriteObject(ms, lpr);
            string json = Encoding.Default.GetString(ms.ToArray());
            ms.Close();

            ms = new MemoryStream(Encoding.Unicode.GetBytes(json));
            LatestProductResponse lpr2 = serializerResponse.ReadObject(ms) 
as LatestProductResponse;
            ms.Close();

            // serialize the request object into a memory stream
            ms = new MemoryStream();
            serializerRequest.WriteObject(ms, requestData); // throws here
            json = Encoding.Default.GetString(ms.ToArray());
            byte[] buffer = Encoding.UTF8.GetBytes(json);
            ms.Close();

FIX:
I changed a few lines in the csharp.xlt file
1) Find the place where you new the list and remove the readonly attribute
2) modify the getter for the list to check to see if the list is null, if 
it is, then new it.

the resultant code should look as follows.

    private global::System.Collections.Generic.List<ProductDownloadUrl> 
_url = new global::System.Collections.Generic.List<ProductDownloadUrl>();

    public global::System.Collections.Generic.List<ProductDownloadUrl> Url
    {
      get 
      {
        if(_url == null)
          _url = new 
global::System.Collections.Generic.List<ProductDownloadUrl>();
        return _url; 
      }

    }

Original issue reported on code.google.com by ghst...@gmail.com on 15 Sep 2009 at 7:25

GoogleCodeExporter commented 9 years ago
typo error:
throws on the ReadObject call.
    LatestProductResponse lpr2 = serializerResponse.ReadObject(ms) as 
LatestProductResponse;

Original comment by ghst...@gmail.com on 15 Sep 2009 at 7:50

GoogleCodeExporter commented 9 years ago

Original comment by marc.gravell on 29 Jan 2010 at 8:27

GoogleCodeExporter commented 9 years ago
It still angers me that someone at MS decided that DataContractSerializers 
would not 
call the constructor or property initializers prior to deserialization... seems 
pretty lame.

MS was nice enough to give you an OnDeserializing method that can be used to 
solve 
this without breaking the readonly lists:

        [OnDeserializing]
        private void OnDeserializing(StreamingContext context)
        {
            _url = new global::System.Collections.Generic.List<ProductDownloadUrl>();
        }

Obviously, all repeated (list) properties would need to be initialized in the 
OnDeserializing method...

Original comment by scoo...@gmail.com on 2 Apr 2010 at 4:52