1

I have object like below

public class MyObject
{
   private IEnumerable _data;
   public MyObject(IEnumerable<int> data)
   {
     _data = data;
   }

   public IEnumerable GetData()
   {
     return this._data;
   }
}

the _data property is private. I am storing this object in session as below using jsonserializer

 var val = new MyObject(new int[] {1,2,3})
 HttpContext.Session.SetString("MyKey", JsonConvert.SerializeObject(val));

then im trying to retrieve it as below

     var val = HttpContext.Session.GetString("MyKey");
     var myObject = JsonConvert.DeserializeObject<MyObject>(val);

However MyObject.GetData() returns null. I am assuming since _data property is private JsonSerializer is not able to serialize it.
So what are my options here to store an object in session which has private properties?

LP13
  • 30,567
  • 53
  • 217
  • 400
  • I think you're out of luck, unless you target full .NET Framework or make it public or you wait until .NET Core 1.2 and the `netstandard2.x` is released. `SerializationInfo` and `StreamingContext` which could be used to serialize and deserialize classes as well as binary serialiers aren't in the current `netstandard1.x` api, but with `netstandard2.x` many of them are coming back, including binary serializer – Tseng Nov 08 '16 at 20:14
  • Got to take part of it back. SerializationInfo seems to be already included in www.nuget.org/packages/System.Runtime.Serialization.Formatters/4.0.0-rc3-24212-01, see https://packagesearch.azurewebsites.net/?q=SerializationInfo. Your model would need to implement `ISerializable` and an protected constructor which takes `ModelValidationException(SerializationInfo info, StreamingContext context)`. Could try to put it into a short sample, but not sure it will work on .NET Core/Json.NET, haven't tried it yet on .NET Core – Tseng Nov 08 '16 at 20:23

2 Answers2

1

You can try to make your class serializable like this

[Serializable]
public class MyObject : ISerializable
{
    private IEnumerable _data;
    public MyObject(IEnumerable<int> data)
    {
        _data = data;
    }

    public IEnumerable GetData()
    {
        return this._data;
    }

    protected MyObject(SerializationInfo info, StreamingContext context)
    {
        _data = (IEnumerable<int>)info.GetValue(nameof(_data), typeof(IEnumerable<int>));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        if (info == null)
            throw new ArgumentNullException(nameof(info));

        info.AddValue(nameof(_data), _data, typeof(IEnumerable<int>));
    }
}

For this to work, you have to target a minimum of netstandard1.3 (.NET Framework 4.6 or .NET Core). In your project.json you need to add System.Runtime.Serialization.Formatters dependency

"netstandard1.3": {
  "imports": [ "dnxcore50", "portable-net45+win8" ],
  "dependencies": {
    "NETStandard.Library": "1.6.0",
    "System.Runtime.Serialization.Formatters": "4.0.0-rc3-24212-01"
  }
}

I didn't test it on .NET Core, so no idea if it works. But this is how you implement but JSON.NET actually does support serializing ISerializable objects. I just don't know if the .NET Core version of JSON.NET does support it, because the nuget package targets netstandard1.0 and ISerializable requires System.Runtime.Serialization.Formatters which requires netstandard1.3.

Tseng
  • 61,549
  • 15
  • 193
  • 205
0

I believe this is a standard JSON.Net serialization problem. Private properties aren't serialized unless you provide your own serializer as provided in this answer.

Additionally, you'll need a default constructor, or ensure to tag your constructor correctly (unsure whether that'll work with private fields). This is a good answer to the non-default constructor problem.

I feel like your class is a simple DTO without too much value of keeping this field private. Why not marking it as public? Or if your object is more complex than the example given, you might want to have a dedicated DTO with only public properties and no functionality which you create just for serialization/deserialization and then manually convert into the class you actually want. This way, you can also ensure your DTO stays compatible as you release new versions even if you introduce breaking changes in the other class.

Community
  • 1
  • 1
thoean
  • 1,106
  • 8
  • 15
  • The actual object is actually more complex than example. It has more methods that acts on private data. – LP13 Nov 09 '16 at 06:10
  • Don't mix objects that hold data with classes that provide functionality. – thoean Nov 09 '16 at 06:12