2

I have an IP address that I need to have as a 4 byte array in my code. However I would like to store it in my JSON settings file as a string, formatted like "192.168.0.1". Then I would also like to do the reverse and deserialize it.

I'd like to do this as the goal of my Settings.json file is that it is human editable.

Is there a way I can do this?

I'm using the Newtonsoft JSON package

Class I am serializing

public class Settings
{
    public string PLCIP;
    public byte[] RightTesterIP;
    public byte[] LeftTesterIP;
}

converter methods I wrote. Just not sure where to implement them.

private string ConvertIPByteArraytoString(byte[] ip)
{
    StringBuilder builder = new StringBuilder();

    builder.Append(ip[0]);

    for (int i = 1; i < ip.Length; i++)
    {
        builder.Append(".");
        builder.Append(ip[i]);

    }
    return builder.ToString();
}

private byte[] ConvertIPStringToByteArray(string ip, string ParameterName)
{
    var blah = new byte[4];

    var split = ip.Split('.');

    if (split.Length != 4)
    {
        //Log.Error("IP Address in settings does not have 4 octets.Number Parsed was {NumOfOCtets}", split.Length);
        //throw new SettingsParameterException($"IP Address in settings does not have 4 octets. Number Parsed was {split.Length}");
    }

    for(int i = 0; i < split.Length; i++)
    {
        if(!byte.TryParse(split[i], out blah[i]))
        {
            //var ex = new SettingsParameterException($"Octet {i + 1} of {ParameterName} could not be parsed to byte. Contained \"{split[i]}\"");
            //Log.Error(ex,"Octet {i + 1} of {ParameterName} could not be parsed to byte. Contained \"{split[i]}\"", i, ParameterName, split[i]);
            //throw ex;
        }

    }

    return blah;
}
1

1 Answer 1

2

You could do it in a custom JsonConverter like so:

public class IPByteArrayConverter : JsonConverter
{
    private static string ConvertIPByteArraytoString(byte[] ip)
    {
        StringBuilder builder = new StringBuilder();

        builder.Append(ip[0]);

        for (int i = 1; i < ip.Length; i++)
        {
            builder.Append(".");
            builder.Append(ip[i]);

        }
        return builder.ToString();
    }

    private static byte[] ConvertIPStringToByteArray(string ip)
    {
        var blah = new byte[4];

        var split = ip.Split('.');

        if (split.Length != 4)
        {
            //Log.Error("IP Address in settings does not have 4 octets.Number Parsed was {NumOfOCtets}", split.Length);
            //throw new SettingsParameterException($"IP Address in settings does not have 4 octets. Number Parsed was {split.Length}");
        }

        for (int i = 0; i < split.Length; i++)
        {
            if (!byte.TryParse(split[i], out blah[i]))
            {
                //var ex = new SettingsParameterException($"Octet {i + 1} of {ParameterName} could not be parsed to byte. Contained \"{split[i]}\"");
                //Log.Error(ex,"Octet {i + 1} of {ParameterName} could not be parsed to byte. Contained \"{split[i]}\"", i, ParameterName, split[i]);
                //throw ex;
            }

        }

        return blah;
    }

    public override bool CanConvert(Type objectType)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var token = JToken.Load(reader);
        if (token.Type == JTokenType.Bytes)
            return (byte[])token;
        return ConvertIPStringToByteArray((string)token);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var bytes = (byte[])value;
        writer.WriteValue(ConvertIPByteArraytoString(bytes));
    }
}

You would then attach it to the appropriate properties or fields using [JsonConverter(IPByteArrayConverter)]:

public class Settings
{
    public string PLCIP;
    [JsonConverter(typeof(IPByteArrayConverter))]
    public byte[] RightTesterIP;
    [JsonConverter(typeof(IPByteArrayConverter))]
    public byte[] LeftTesterIP;
}

Sample fiddle.

Update

Using IPAddress as suggested by @Greg gets you support for IPV6 as well as IPV4. A JsonConverter for this type would look like:

public class IPAddressConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(IPAddress).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var token = JToken.Load(reader);
        if (token.Type == JTokenType.Bytes)
        {
            var bytes = (byte[])token;
            return new IPAddress(bytes);
        }
        else
        {
            var s = (string)token;
            return IPAddress.Parse(s);
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var ip = (IPAddress)value;
        writer.WriteValue(ip.ToString());
    }
}

Then apply it to the Settings class as before, or use it globally in JsonSerializerSettings.Converters:

var jsonSettings = new JsonSerializerSettings
{
    Converters = new [] { new IPAddressConverter() },
};

var json = JsonConvert.SerializeObject(settings, jsonSettings);

Using the class:

public class Settings
{
    public string PLCIP;
    public IPAddress RightTesterIP;
    public IPAddress LeftTesterIP;
}

Sample fiddle.

Sign up to request clarification or add additional context in comments.

3 Comments

@TheColonel26 - answer updated with a converter for the IPAddress type suggested by @Greg
I was looking at implementing @Greg's suggestion but the IPAddress.Parse Method has undesirable behavior, atleast for this implementation. For example if you in enter "65536" it results in an IP of 0.0.255.255. I would rather it not except an entry like that. The reason being that the people using it aren't going to expect that behavior and the only time something like that would be entered is by mistake.
I love you - we had an application failing and it turns out newtsonsoft was turning byte[]'s into stirngs >.<

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.