0

Trying to serialize a collection of a custom type with an overloaded Equals(object obj) method. I am using Newtonsoft.Json.JsonConvert.SerializeObject(object value) to achieve this.

This is my abstract base view model from which the view model in question inherits:

public abstract class BaseCollectibleViewModel
{
    protected abstract bool CompareParameters(object item);

    protected abstract List<int> GetParameters();

    public override bool Equals(object obj)
    {
        if (CompareParameters(obj))
        {
            return true;
        }
        return false;
    }

    public override int GetHashCode()
    {
        int hash = 13;
        foreach (var parameter in GetParameters())
        {
            hash = (hash * 7) + parameter.GetHashCode();
        }

        return hash;
    }

    public static bool operator ==(BaseCollectibleViewModel a, BaseCollectibleViewModel b)
    {
        if (a.Equals(b))
        {
            return true;
        }
        return false;
    }

    public static bool operator !=(BaseCollectibleViewModel a, BaseCollectibleViewModel b)
    {
        if (a.Equals(b))
        {
            return false;
        }
        return true;
    }
}

This is the actual view model:

public class ImagesViewModel : BaseCollectibleViewModel, ISourceImage
{
    public string Name { get; private set; }
    public string Type { get; private set; }
    [ScriptIgnore]
    public Stream Content { get; private set; }
    [ScriptIgnore]
    private HttpPostedFileBase _file;
    [ScriptIgnore]
    public HttpPostedFileBase File
    {
        get
        {
            return _file;
        }
        set
        {
            _file = value;
            Name = File.FileName;
            Type = File.ContentType;
            Content = new MemoryStream();
            File.InputStream.CopyTo(Content);
        }
    }

    protected override bool CompareParameters(object obj)
    {
        var temp = obj as ImagesViewModel;
        if(temp == null)
        {
            return false;
        }
        return
            (Name == temp.Name &&
            Type == temp.Type);
    }

    protected override List<int> GetParameters()
    {
        return new List<int>()
        {
            Name.GetHashCode(),
            Type.GetHashCode()
        };
    }
}

Notice the ScriptIgnore attributes. I even have one on the private field. The program breaks on the == operator of the base class because both of the arguments that get passed are null.

This is the serializing code:

[HttpPost]
public string GetSessionImages()
{
    var imagesInSession = _imagesSessionService.GetCollection();
    return JsonConvert.SerializeObject(imagesInSession, Formatting.Indented);
}

Also this: enter image description here

The screenshot is showing the implementation of the abstract CompareParameters(object obj) method on the inheriting view model. That stream is the Content property stream, I have checked. Why is this happening?

EDIT: When not overriding Equals I get a JsonSerializationException stating:

{"Error getting value from 'ReadTimeout' on 'System.IO.MemoryStream'."}

EDIT 2: Per dbc's comment I have replaced the attribute [ScriptIgnore] with [JsonIgnore] and the code worked to an extent. However, I had to comment out the operator implementations because the '==' operator would be passed a null value as the BaseCollectibleViewModel b argument.

dbc
  • 104,963
  • 20
  • 228
  • 340
Jakov
  • 720
  • 1
  • 12
  • 29
  • Or maybe the problem is that you are using `[ScriptIgnore]`. This attribute is for `JavaScriptSerializer`. You need to use [`[JsonIgnore]`](https://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_JsonIgnoreAttribute.htm) with Json.NET. Also, is there any chance you are double-serializing your JSON as shown [here](https://stackoverflow.com/q/25559179/3744182)? – dbc May 05 '18 at 19:08
  • 1
    @dbc The second comment is actually the answer to my question... Honestly the namespace in which `[ScriptIgnore]`resides was a bit weird for me, but I thought Newtonsoft just reused an overridden version or something. I just skimmed through this answer; https://stackoverflow.com/questions/10169648/how-to-exclude-property-from-json-serialization and didn't realize that there is no `Serialize()` method on `Newtonsoft.Json`. Write this as an answer so I can select it. Thank you kindly, sir! – Jakov May 06 '18 at 00:18

1 Answers1

1

Since you are using , you must mark members to ignore with [JsonIgnore]:

using Newtonsoft.Json;

public class ImagesViewModel : BaseCollectibleViewModel, ISourceImage
{
    public string Name { get; private set; }
    public string Type { get; private set; }

    [ScriptIgnore]
    [JsonIgnore]
    public Stream Content { get; private set; }

    [ScriptIgnore]
    [JsonIgnore]
    public HttpPostedFileBase File { get { ... } set { ... } }

It is not necessary to mark entirely private members with [JsonIgnore] as these are not serialized by default by Json.NET.

Alternatively, if you do not want your models to have a dependency on Json.NET, you could use conditional property serialization to unconditionally suppress the same members:

public class ImagesViewModel : BaseCollectibleViewModel, ISourceImage
{
    public string Name { get; private set; }
    public string Type { get; private set; }

    [ScriptIgnore]
    public Stream Content { get; private set; }

    public bool ShouldSerializeContent() { return false; }

    [ScriptIgnore]
    public HttpPostedFileBase File { get { ... } set { ... } }

    public bool ShouldSerializeFile() { return false; }

Note that the ShouldSerializeXXX() conditional serialization pattern is also respected by other serializers including XmlSerializer, as explained in ShouldSerialize*() vs *Specified Conditional Serialization Pattern - a side-effect which may be desirable, or not.

(Incidentally, you might want to check that you are not double-serializing your data as shown in JSON.NET Parser *seems* to be double serializing my objects.)

dbc
  • 104,963
  • 20
  • 228
  • 340
  • 1
    I've checked the output in my browser and no, I'm not double serializing. Also, I feel the `ShouldSerialize` is a better route to take in this case, thanks for the heads up. – Jakov May 07 '18 at 13:37