1

I have a DataMember that I need to be filled in by an api json string...

[DataContract]
public class Values
{
    [DataMember]
    public object value { get; set; }
}

API json string:

[
    {
        "type": "text",
        "values": [
            {
                "value": "Text that is in textfield"
            }
        ]
    },
    {
        "type": "category",
        "values": [
            {
                "value": {
                    "text": "Category title",
                    "color": "#000000"
                }
            }
        ]
    }
]

I map this string to a strong typed object Field like so:

    private List<Field> PrepFieldObject(string response)
    {
        using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(response)))
        {
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Field>));
            return (List<Field>)serializer.ReadObject(stream);
        }
    }

but when it gets to mapping Values.value, it throws a hissy fit... I tried solving it like this:

[DataContract]
public class Values
{
    [DataMember]
    public object value
    {
        get {
            return xamlValue;
        }
        set
        {                     
            xamlValue = new Value();

            if( value is string )
            {
                 xamlValue.text = (string)value; // This works fine
            }
            else
            {

                Value theValue = value as Value;
                try
                {
                    xamlValue.text = theValue.text; // Can't get hold of .text even though it does exist in the json.
                    xamlValue.color = theValue.color;
                }
                catch (Exception e)
                {
                }
            }
        }
    }
    public Value xamlValue { get; set; }
}

[DataContract]
public class Value
{
    [DataMember]
    public string text { get; set; }
    [DataMember]
    public string color { get; set; }
}

But it doesn't let me access properties of the object (I guess because they were never mapped by the DataContract)

I've tried adding

[KnownType(typeof(Value))]
[KnownType(typeof(string))]

but that doesn't help either :'(

Jimmyt1988
  • 20,466
  • 41
  • 133
  • 233
  • 1
    You should avoid putting yourself in the situation where you don't know whether an object will be a string or a complex object with some string property that you need to fetch. Solutions would be dependent on context not shown, but perhaps you should be pulling the string value out of the complex object before storing it in your `value` property. – Servy Jun 11 '14 at 20:02
  • In that case, do you think you could give me a hand with a getter and setter? if value that is set is not of type string, then use an object instead? I'll struggle on if you can't find time. thanks though. – Jimmyt1988 Jun 11 '14 at 20:03
  • 1
    You shouldn't be trying to set a complex type in the first place. Whatever code you have calling this setter and assigning a complex type should be altered to assign a string value of that complex type instead. Without knowing what that code is, I couldn't say what exactly needs to be changed. – Servy Jun 11 '14 at 20:04
  • It's an api that returns a json string. I use a stream alongside newtonsoft json to map to strong type classes. unfortunately on this one particular [DataMember] it maps differently, so I need a clever way of mapping it to strong depending on what it is, or to just do it as dynamic (but that doesn't work with xaml it seems) – Jimmyt1988 Jun 11 '14 at 20:16
  • sorry, I mean DataContractJsonSerializer – Jimmyt1988 Jun 11 '14 at 20:30

6 Answers6

0

You have to cast it to whatever type the text property belongs to.

((SomeType)value).text
Andrew
  • 4,953
  • 15
  • 40
  • 58
0

You will have to use type-casting. Example string:

string abc = (string)value.text;

OR (preferably)

ComplexType comp = value as ComplexType;

UPDATE:

When you are trying to serialize a JSON object and convert it to a strongly-typed object (something my ComplexType is an example of), its important to have the same names for the properties as is in the JSON. After serialization, you should be able to access the property values.

Hope this helps!!!

Satwik Nadkarny
  • 5,086
  • 2
  • 23
  • 41
  • What is the ComplexType bit? – Jimmyt1988 Jun 11 '14 at 20:25
  • ComplexType was just an example of type you must have created for example a Person class, or a Student class. If you were trying to typecast to such a type, then you can make use of 'as' for type-safe typecasting. – Satwik Nadkarny Jun 11 '14 at 20:28
  • Your additional edit doesn't help unfortunately. The serialization is working fine, apart from when it needs to be mapped to a dynamic/object type. – Jimmyt1988 Jun 11 '14 at 20:55
0

You can just use the operator is, but you have to use it for each value that value can assume:

if (value is String)
{
    //do something
}
else if (value is ...)
...

You can read more about is here.

  • This assumes that he knows all of the possible types at compile time; that doesn't appear to be the case. – Servy Jun 11 '14 at 20:06
  • He said that it could be a String or a object from an API. Even if it's from an API ho should be able to know at least the public types. – Marco Speziali Jun 11 '14 at 20:09
  • 1
    At runtime, yes, at compile time, not necessarily. He could be creating a type that will be used by other types that don't even exist yet, if other projects are going to end up using the code that he's writing. And for that matter, even if this is an option, which it may or may not be, it's still *really* bad practice. The *far* better solution is to avoid putting yourself in this position to begin with, as my above comment mentions, or at the very least, to leverage polymorphism through the use of, say, an interface. – Servy Jun 11 '14 at 20:12
0

You COULD use a dynamic type:

DataContract]
public class Values
{
    [DataMember]
    public dynamic value { get; set; }
}

More about Dynamics

RyanTimmons91
  • 460
  • 1
  • 5
  • 17
  • In this case, i'm assuming xaml must have strong type in order to display something :( – Jimmyt1988 Jun 11 '14 at 20:02
  • This assumes he knows what property of the object he needs to get, but he *doesn't* necessarily know, that's the problem. – Servy Jun 11 '14 at 20:05
  • Ah, well in that case casting may be your only option – RyanTimmons91 Jun 11 '14 at 20:10
  • I do know actually... only because, there is a property called "type" in a parent class that I switch on to present using my data template selector. when it's type "text", the value will be a string. when it is type "category" the value property needs to be mapped to an object with various other properties... and because I want to use newtonsoft json library and the stream, i'm finding it difficult to find out at what point I can decide what to map as – Jimmyt1988 Jun 11 '14 at 20:19
0

If you want a string or the defined string representation of the object use:

String valueAsString = value.ToString()

That is assuming that the other types (besides string) override the ToString() method to provide a meaningful string representation of the object.

Otherwise you would need to use:

KnownValueType kvt = value as KnownValueType
if(kvt!=null)
{
  //access known type properties here
}
RJ Programmer
  • 788
  • 5
  • 7
0

I think you can use reflection to to access your object's property value. Try changing your setter's else part as

else
    {

        Value theValue = value as Value;
        try
        {   
            // pass the object and the property name you're trying to get hold of
            xamlValue.text = PropertyHasValue(theValue, "text"); // Can't get hold of .text even though it does exist in the json. 
            xamlValue.color = PropertyHasValue(theValue, "color");
        }
        catch (Exception e)
        {
        }
    }

And the reflection method

// using reflection to get the object's property value
public static String PropertyHasValue(object obj, string propertyName)
{
    try
    {
        if (obj != null)
        {
            PropertyInfo prop = obj.GetType().GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public);
            if (prop != null)
            {
                string sVal = String.Empty;
                object val = prop.GetValue(obj, null);

                if (prop.PropertyType != typeof(System.DateTime?))
                    sVal = Convert.ToString(val);
                else // format the date to contain only the date portion of it
                    sVal = Convert.ToDateTime(val).Date.ToString("d"); ;

                if (sVal != null)
                {
                    return sVal;
                 }
             }
        }

        return null;
    }
    catch
    {
        return null;
    }
}
Dennis R
  • 3,195
  • 1
  • 19
  • 24
  • It stopped erroring, which is a step forward (I think), but it is struggling to get values from the object (it just sets those properties as null). I guess because it was never serialized from the json string? – Jimmyt1988 Jun 11 '14 at 23:07
  • Infact, the PropertyHasValue obj parameter comes through as null. – Jimmyt1988 Jun 11 '14 at 23:09
  • If the object you're passing has value ('text and color') the this method should sure to return the value. Check if something else is going wrong. – Dennis R Jun 11 '14 at 23:11
  • The DataContractJsonSerializer seems to work for everything else but this double type property. Is it that DataContractJsonSerializer just doesn't do well with type "object" ? although it does seem to map the string just fine! – Jimmyt1988 Jun 11 '14 at 23:24
  • That's what I think so, it could just map the string well but not sure how DataContractJsonSerializer handles the object mapping. – Dennis R Jun 11 '14 at 23:32