3

I have a Windows Phone 7 project that connects to a .NET web service to fetch data on demand. Both the WP7 project and the web service use a copy of the same c# class library. Part of this library is an enum of EmployeeType:

Public enum EmployeeType
{
    Standard = 0,
    TeamLeader = 105
}

Since the app was released, the web service class library has had a change made to it - adding a new enum value. (SeniorManager = 110)

Therefore, when I receive an object on the phone with a property containing the new enum value, I get a SerializationException when attempting to add it to IsolatedStorage. This is because the new enum value cannot be serialized, as the WP7 class library has not had the same update made to it and the enum value does not exist.

What I would like to achieve is to still be able to serialize the object, but ignore the invalid enum value, or replace it with a valid one (ideally Standard = 0).

This will enable me to handle any future additions made to the web service enum, without breaking the functionality of the app.

Notes:

  • The enum/values above are contrived for the purposes of the question and not the actual enum in question.
  • The fact that the value would be serialized with an incorrect value is unimportant for the purposes of the app.

Thanks!

Ian L
  • 5,553
  • 1
  • 22
  • 37
  • Have you tried building a custom ISerializable implementation? – sisve Apr 02 '12 at 09:49
  • No, I haven't (and have never used a custom ISerializable implementation). It's a large class with many properties, so would this be a lot of work to implement? Also, there is a [DataContract] attribute on the class, with [DataMember] attributes on the properties (including the property of the enum type), so not sure if this affects anything? – Ian L Apr 02 '12 at 10:02
  • Can't you just update to the newer version of the library? – svick Apr 02 '12 at 10:05
  • @svick: Yes, I can, and I will be doing so! However, the web service is used by multiple clients, not only the WP7 project. Sometimes, an update is required to the web service and I would like to avoid having to issue an update for that purpose (and the web services team would like to be able to deploy without waiting for the WP7 app approval process to be completed). I know it's not an ideal situation, but I am looking for any useful tips to workaround the issue until the libraries can be synced. – Ian L Apr 02 '12 at 10:09
  • This seems like XMLSerialization, so ISerializable is not applicable here. Only with binary serialization. – leppie Apr 02 '12 at 10:59

2 Answers2

2

I don't understand why you don't update the reference to the WebService in WP7 project, so that you will be able to serialize it.

Anyway, you can try this workaorund:

  1. The real field, not to be serialized

    [NonSerialized]
    public EmployeeType RealType {get; set;} 
    
  2. A fake field, that will be serialized returns Standard if Realfield is SeniorManager or actual RealField value

    public EmployeeType Type 
     {
      get{
           if (RealType== EmployeeType.TeamLeader)
              return  EmployeeType.TeamLeader;
           else 
              return  EmployeeType.Standard;
         } 
      set{RealType=value;}
     }     
    
Emanuele Greco
  • 12,551
  • 7
  • 51
  • 70
  • 1
    Thanks for your answer Emanuele. I did comment that I will be updating the library, but I don't want to have to issue an app update for each change. Also, the web services team don't want to wait for an app to be approved before they can deploy a change. Your answer is interesting and I'm grateful (+1), but my actual enum contains many more values than my question example, not just the three. I am about to answer my own question with how I am working around it. Thanks. – Ian L Apr 03 '12 at 09:58
  • You found an interesting solution; anyway i improved minem so that it works with many EmpoyeeType. You could put a 'switch', too. – Emanuele Greco Apr 03 '12 at 10:51
2

I ended up using JSON.NET to deserialize the data from the server (reader is a StreamReader for the response stream. TResponse is the generic response expected from the server.):

var serializer = new JsonSerializer();
serializer.Converters.Add(new JsonEnumTypeConverter());
this.Response = serializer.Deserialize<TResponse>(new JsonTextReader(reader));

The JsonEnumTypeConverter class checks that the enum value returned from the server is valid for the given type. If not, then it's defaulted to zero. (Always present on enums). This class is defined as follows:

private class JsonEnumTypeConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType.IsEnum;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            var value = Enum.Parse(objectType, reader.Value.ToString(), true);
            if (IsFlagDefined((Enum)value))
            {
                return value;
            }
            else
            {
                return 0;
            }
        }
        catch (Exception)
        {
            return 0;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        writer.WriteValue(value);
    }

    private static bool IsFlagDefined(Enum e)
    {
        decimal d;
        return (!decimal.TryParse(e.ToString(), out d));
    }
}

Note that I use the custom IsFlagDefined method, rather than Enum.IsDefined as my enums include [Flags] attributes which Enum.IsDefined does not handle. (Source: Enum.IsDefined with flagged enums)

Also, credit to Darin Dimitrov's answer in this question for pointing me towards JSON.NET and the JsonConverter.

Community
  • 1
  • 1
Ian L
  • 5,553
  • 1
  • 22
  • 37