From a63e84ce1b9080bcc20cb1add6d7a319b9c1c1c4 Mon Sep 17 00:00:00 2001 From: Eamon Hetherton Date: Fri, 8 Feb 2013 08:43:51 +1000 Subject: [PATCH 1/7] Add support for DateTimeOffset to XmlDeserializer --- RestSharp/Deserializers/XmlDeserializer.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/RestSharp/Deserializers/XmlDeserializer.cs b/RestSharp/Deserializers/XmlDeserializer.cs index 346290ce1..392eb721b 100644 --- a/RestSharp/Deserializers/XmlDeserializer.cs +++ b/RestSharp/Deserializers/XmlDeserializer.cs @@ -168,7 +168,12 @@ private void Map(object x, XElement root) } prop.SetValue(x, value, null); - } + } + else if (type == typeof(DateTimeOffset)) + { + var toConvert = value.ToString(); + prop.SetValue(x, XmlConvert.ToDateTimeOffset(toConvert), null); + } else if (type == typeof(Decimal)) { value = Decimal.Parse(value.ToString(), Culture); From 3399efaa3790fc26ba40ba9939c2354a653724e8 Mon Sep 17 00:00:00 2001 From: Eamon Hetherton Date: Fri, 8 Feb 2013 08:51:55 +1000 Subject: [PATCH 2/7] Ignore empty string values --- RestSharp/Deserializers/XmlDeserializer.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/RestSharp/Deserializers/XmlDeserializer.cs b/RestSharp/Deserializers/XmlDeserializer.cs index 392eb721b..83c21838d 100644 --- a/RestSharp/Deserializers/XmlDeserializer.cs +++ b/RestSharp/Deserializers/XmlDeserializer.cs @@ -172,7 +172,10 @@ private void Map(object x, XElement root) else if (type == typeof(DateTimeOffset)) { var toConvert = value.ToString(); - prop.SetValue(x, XmlConvert.ToDateTimeOffset(toConvert), null); + if (!string.IsNullOrEmpty(toConvert)) + { + prop.SetValue(x, XmlConvert.ToDateTimeOffset(toConvert), null); + } } else if (type == typeof(Decimal)) { From 7b4da75afa0e15f5e235dc7b6afbe1781a82756d Mon Sep 17 00:00:00 2001 From: Eamon Hetherton Date: Fri, 8 Feb 2013 08:56:48 +1000 Subject: [PATCH 3/7] Add TypeConverter fallback option --- RestSharp/Deserializers/XmlDeserializer.cs | 46 ++++++++++++++++------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/RestSharp/Deserializers/XmlDeserializer.cs b/RestSharp/Deserializers/XmlDeserializer.cs index 83c21838d..36cb54709 100644 --- a/RestSharp/Deserializers/XmlDeserializer.cs +++ b/RestSharp/Deserializers/XmlDeserializer.cs @@ -22,7 +22,8 @@ using RestSharp.Extensions; using System.Globalization; -using System.Xml; +using System.Xml; +using System.ComponentModel; namespace RestSharp.Deserializers { @@ -217,20 +218,41 @@ private void Map(object x, XElement root) prop.SetValue(x, list, null); } else - { - // nested property classes - if (root != null) - { - var element = GetElementByName(root, name); - if (element != null) - { - var item = CreateAndMap(type, element); - prop.SetValue(x, item, null); - } + { + //fallback to type converters if possible + object result; + if (TryGetFromString(value.ToString(), out result, type)) + { + prop.SetValue(x, value, null); + } + else + { + // nested property classes + if (root != null) + { + var element = GetElementByName(root, name); + if (element != null) + { + var item = CreateAndMap(type, element); + prop.SetValue(x, item, null); + } + } } } } - } + } + + private static bool TryGetFromString(string inputString, out object result, Type type) + { + var converter = TypeDescriptor.GetConverter(type); + if (converter.CanConvertFrom(typeof(string))) + { + result = (converter.ConvertFromInvariantString(inputString)); + return true; + } + result = null; + return false; + } private void PopulateListFromElements(Type t, IEnumerable elements, IList list) { From 0db7b9c8e1d0ec694a9aa01b33f2fe8dbd0f98c8 Mon Sep 17 00:00:00 2001 From: Eamon Hetherton Date: Fri, 8 Feb 2013 09:21:46 +1000 Subject: [PATCH 4/7] Added unit Test for DateTimeOffset XmlDeserialization --- RestSharp.Tests/XmlTests.cs | 38 ++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/RestSharp.Tests/XmlTests.cs b/RestSharp.Tests/XmlTests.cs index 8a3b15a2e..f01e26f90 100644 --- a/RestSharp.Tests/XmlTests.cs +++ b/RestSharp.Tests/XmlTests.cs @@ -640,7 +640,42 @@ public void Can_Deserialize_Mixture_Of_Empty_Elements_With_Attributes_And_Popula Assert.Null(output.Id); Assert.Null(output.StartDate); Assert.Equal(new Guid(GuidString), output.UniqueId); - } + } + + [Fact] + public void Can_Deserialize_DateTimeOffset() + { + var culture = CultureInfo.InvariantCulture; + var doc = new XDocument(culture); + + DateTimeOffset DateTimeOffset = new DateTimeOffset(2013, 02, 08, 9, 18, 22, TimeSpan.FromHours(10)); + DateTimeOffset? NullableDateTimeOffsetWithValue = new DateTimeOffset(2013, 02, 08, 9, 18, 23, TimeSpan.FromHours(10)); + + var root = new XElement("Dates"); + root.Add(new XElement("DateTimeOffset", DateTimeOffset)); + root.Add(new XElement("NullableDateTimeOffsetWithNull", string.Empty)); + root.Add(new XElement("NullableDateTimeOffsetWithValue", NullableDateTimeOffsetWithValue)); + + doc.Add(root); + + var xml = new XmlDeserializer + { + Culture = culture, + }; + + var response = new RestResponse { Content = doc.ToString() }; + + var d = new XmlDeserializer() + { + Culture = culture, + }; + var payload = d.Deserialize(response); + Assert.Equal(DateTimeOffset, payload.DateTimeOffset); + Assert.Null(payload.NullableDateTimeOffsetWithNull); + + Assert.True(payload.NullableDateTimeOffsetWithValue.HasValue); + Assert.Equal(NullableDateTimeOffsetWithValue, payload.NullableDateTimeOffsetWithValue); + } private static string CreateUnderscoresXml() { @@ -934,5 +969,6 @@ private static string CreateXmlWithAttributesAndNullValuesAndPopulatedValues() return doc.ToString(); } + } } From 0ef75b0c9b1ad1e388a36afe725265ec0646b40e Mon Sep 17 00:00:00 2001 From: Eamon Hetherton Date: Fri, 8 Mar 2013 09:14:46 +1000 Subject: [PATCH 5/7] added fallback option for datetimeoffset objects that can't be deserialised by XmlConvert --- RestSharp/Deserializers/XmlDeserializer.cs | 23 ++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/RestSharp/Deserializers/XmlDeserializer.cs b/RestSharp/Deserializers/XmlDeserializer.cs index 36cb54709..4d85080a3 100644 --- a/RestSharp/Deserializers/XmlDeserializer.cs +++ b/RestSharp/Deserializers/XmlDeserializer.cs @@ -175,7 +175,26 @@ private void Map(object x, XElement root) var toConvert = value.ToString(); if (!string.IsNullOrEmpty(toConvert)) { - prop.SetValue(x, XmlConvert.ToDateTimeOffset(toConvert), null); + DateTimeOffset deserialisedValue; + try + { + deserialisedValue = XmlConvert.ToDateTimeOffset(toConvert); + prop.SetValue(x, deserialisedValue, null); + } + catch (Exception) + { + object result; + if (TryGetFromString(toConvert, out result, type)) + { + prop.SetValue(x, result, null); + } + else + { + //fallback to parse + deserialisedValue = DateTimeOffset.Parse(toConvert); + prop.SetValue(x, deserialisedValue, null); + } + } } } else if (type == typeof(Decimal)) @@ -223,7 +242,7 @@ private void Map(object x, XElement root) object result; if (TryGetFromString(value.ToString(), out result, type)) { - prop.SetValue(x, value, null); + prop.SetValue(x, result, null); } else { From c398ea1fa87b405c891d6960a5e0be16b1e35e2f Mon Sep 17 00:00:00 2001 From: Eamon Hetherton Date: Thu, 5 Sep 2013 08:56:44 +1000 Subject: [PATCH 6/7] Fixed Indentation --- RestSharp/Deserializers/XmlAttributeDeserializer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RestSharp/Deserializers/XmlAttributeDeserializer.cs b/RestSharp/Deserializers/XmlAttributeDeserializer.cs index 8d7ca4f8b..9b3f9bec6 100644 --- a/RestSharp/Deserializers/XmlAttributeDeserializer.cs +++ b/RestSharp/Deserializers/XmlAttributeDeserializer.cs @@ -55,7 +55,7 @@ public T Deserialize(IRestResponse response) RemoveNamespace(doc); } - var x = Activator.CreateInstance(); + var x = Activator.CreateInstance(); var objType = x.GetType(); if (objType.IsSubclassOfRawGeneric(typeof(List<>))) From ec4405adeff43f1c89b6d45e5e07086e4ade466f Mon Sep 17 00:00:00 2001 From: Haacked Date: Fri, 6 Sep 2013 18:41:58 -0700 Subject: [PATCH 7/7] Fixed indentation RestSharp uses tabs instead of spaces. Oy! --- RestSharp.Tests/XmlTests.cs | 150 ++++++++++----------- RestSharp/Deserializers/XmlDeserializer.cs | 104 +++++++------- 2 files changed, 127 insertions(+), 127 deletions(-) diff --git a/RestSharp.Tests/XmlTests.cs b/RestSharp.Tests/XmlTests.cs index f01e26f90..c5c942967 100644 --- a/RestSharp.Tests/XmlTests.cs +++ b/RestSharp.Tests/XmlTests.cs @@ -254,47 +254,47 @@ public void Can_Deserialize_Elements_to_Nullable_Values() Assert.Equal(new Guid(GuidString), output.UniqueId); } - [Fact] - public void Can_Deserialize_TimeSpan() - { - var culture = CultureInfo.InvariantCulture; - var doc = new XDocument(culture); - - TimeSpan? nullTimespan = null; - TimeSpan? nullValueTimeSpan = new TimeSpan(21, 30, 7); - - var root = new XElement("Person"); - root.Add(new XElement("Tick", new TimeSpan(468006))); - root.Add(new XElement("Millisecond", new TimeSpan(0, 0, 0, 0, 125))); - root.Add(new XElement("Second", new TimeSpan(0, 0, 8))); - root.Add(new XElement("Minute", new TimeSpan(0, 55, 2))); - root.Add(new XElement("Hour", new TimeSpan(21, 30, 7))); - root.Add(new XElement("NullableWithoutValue", nullTimespan)); - root.Add(new XElement("NullableWithValue", nullValueTimeSpan)); - - doc.Add(root); - - var xml = new XmlDeserializer - { - Culture = culture, - }; - - var response = new RestResponse { Content = doc.ToString() }; - - var d = new XmlDeserializer() - { - Culture = culture, - }; - var payload = d.Deserialize(response); - Assert.Equal(new TimeSpan(468006), payload.Tick); - Assert.Equal(new TimeSpan(0, 0, 0, 0, 125), payload.Millisecond); - Assert.Equal(new TimeSpan(0, 0, 8), payload.Second); - Assert.Equal(new TimeSpan(0, 55, 2), payload.Minute); - Assert.Equal(new TimeSpan(21, 30, 7), payload.Hour); - Assert.Null(payload.NullableWithoutValue); - Assert.NotNull(payload.NullableWithValue); - Assert.Equal(new TimeSpan(21, 30, 7), payload.NullableWithValue.Value); - } + [Fact] + public void Can_Deserialize_TimeSpan() + { + var culture = CultureInfo.InvariantCulture; + var doc = new XDocument(culture); + + TimeSpan? nullTimespan = null; + TimeSpan? nullValueTimeSpan = new TimeSpan(21, 30, 7); + + var root = new XElement("Person"); + root.Add(new XElement("Tick", new TimeSpan(468006))); + root.Add(new XElement("Millisecond", new TimeSpan(0, 0, 0, 0, 125))); + root.Add(new XElement("Second", new TimeSpan(0, 0, 8))); + root.Add(new XElement("Minute", new TimeSpan(0, 55, 2))); + root.Add(new XElement("Hour", new TimeSpan(21, 30, 7))); + root.Add(new XElement("NullableWithoutValue", nullTimespan)); + root.Add(new XElement("NullableWithValue", nullValueTimeSpan)); + + doc.Add(root); + + var xml = new XmlDeserializer + { + Culture = culture, + }; + + var response = new RestResponse { Content = doc.ToString() }; + + var d = new XmlDeserializer() + { + Culture = culture, + }; + var payload = d.Deserialize(response); + Assert.Equal(new TimeSpan(468006), payload.Tick); + Assert.Equal(new TimeSpan(0, 0, 0, 0, 125), payload.Millisecond); + Assert.Equal(new TimeSpan(0, 0, 8), payload.Second); + Assert.Equal(new TimeSpan(0, 55, 2), payload.Minute); + Assert.Equal(new TimeSpan(21, 30, 7), payload.Hour); + Assert.Null(payload.NullableWithoutValue); + Assert.NotNull(payload.NullableWithValue); + Assert.Equal(new TimeSpan(21, 30, 7), payload.NullableWithValue.Value); + } [Fact] public void Can_Deserialize_Custom_Formatted_Date() @@ -496,8 +496,8 @@ public void Can_Deserialize_Names_With_Underscores_Without_Matching_Case_On_Defa Assert.Equal (5, p.Foes.Count); Assert.Equal ("Yankees", p.Foes.Team); } - - [Fact] + + [Fact] public void Can_Deserialize_Lower_Cased_Root_Elements_With_Dashes() { var doc = CreateDashesXml(); @@ -642,40 +642,40 @@ public void Can_Deserialize_Mixture_Of_Empty_Elements_With_Attributes_And_Popula Assert.Equal(new Guid(GuidString), output.UniqueId); } - [Fact] - public void Can_Deserialize_DateTimeOffset() - { - var culture = CultureInfo.InvariantCulture; - var doc = new XDocument(culture); - - DateTimeOffset DateTimeOffset = new DateTimeOffset(2013, 02, 08, 9, 18, 22, TimeSpan.FromHours(10)); - DateTimeOffset? NullableDateTimeOffsetWithValue = new DateTimeOffset(2013, 02, 08, 9, 18, 23, TimeSpan.FromHours(10)); + [Fact] + public void Can_Deserialize_DateTimeOffset() + { + var culture = CultureInfo.InvariantCulture; + var doc = new XDocument(culture); + + DateTimeOffset DateTimeOffset = new DateTimeOffset(2013, 02, 08, 9, 18, 22, TimeSpan.FromHours(10)); + DateTimeOffset? NullableDateTimeOffsetWithValue = new DateTimeOffset(2013, 02, 08, 9, 18, 23, TimeSpan.FromHours(10)); - var root = new XElement("Dates"); - root.Add(new XElement("DateTimeOffset", DateTimeOffset)); - root.Add(new XElement("NullableDateTimeOffsetWithNull", string.Empty)); - root.Add(new XElement("NullableDateTimeOffsetWithValue", NullableDateTimeOffsetWithValue)); - - doc.Add(root); + var root = new XElement("Dates"); + root.Add(new XElement("DateTimeOffset", DateTimeOffset)); + root.Add(new XElement("NullableDateTimeOffsetWithNull", string.Empty)); + root.Add(new XElement("NullableDateTimeOffsetWithValue", NullableDateTimeOffsetWithValue)); + + doc.Add(root); - var xml = new XmlDeserializer - { - Culture = culture, - }; + var xml = new XmlDeserializer + { + Culture = culture, + }; - var response = new RestResponse { Content = doc.ToString() }; + var response = new RestResponse { Content = doc.ToString() }; - var d = new XmlDeserializer() - { - Culture = culture, - }; - var payload = d.Deserialize(response); - Assert.Equal(DateTimeOffset, payload.DateTimeOffset); - Assert.Null(payload.NullableDateTimeOffsetWithNull); + var d = new XmlDeserializer() + { + Culture = culture, + }; + var payload = d.Deserialize(response); + Assert.Equal(DateTimeOffset, payload.DateTimeOffset); + Assert.Null(payload.NullableDateTimeOffsetWithNull); - Assert.True(payload.NullableDateTimeOffsetWithValue.HasValue); - Assert.Equal(NullableDateTimeOffsetWithValue, payload.NullableDateTimeOffsetWithValue); - } + Assert.True(payload.NullableDateTimeOffsetWithValue.HasValue); + Assert.Equal(NullableDateTimeOffsetWithValue, payload.NullableDateTimeOffsetWithValue); + } private static string CreateUnderscoresXml() { @@ -806,10 +806,10 @@ private static string CreateDashesXml() doc.Add(root); return doc.ToString(); } - - private static string CreateLowerCasedRootElementWithDashesXml() + + private static string CreateLowerCasedRootElementWithDashesXml() { - var doc = new XDocument(); + var doc = new XDocument(); var root = new XElement("incoming-invoices", new XElement("incoming-invoice", new XElement("concept-id", 45) diff --git a/RestSharp/Deserializers/XmlDeserializer.cs b/RestSharp/Deserializers/XmlDeserializer.cs index 4d85080a3..dff1c938b 100644 --- a/RestSharp/Deserializers/XmlDeserializer.cs +++ b/RestSharp/Deserializers/XmlDeserializer.cs @@ -125,13 +125,13 @@ private void Map(object x, XElement root) // check for nullable and extract underlying type if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { - // if the value is empty, set the property to null... - if (value == null || String.IsNullOrEmpty(value.ToString())) - { - prop.SetValue(x, null, null); - continue; - } - type = type.GetGenericArguments()[0]; + // if the value is empty, set the property to null... + if (value == null || String.IsNullOrEmpty(value.ToString())) + { + prop.SetValue(x, null, null); + continue; + } + type = type.GetGenericArguments()[0]; } if (type == typeof(bool)) @@ -170,33 +170,33 @@ private void Map(object x, XElement root) prop.SetValue(x, value, null); } - else if (type == typeof(DateTimeOffset)) - { - var toConvert = value.ToString(); - if (!string.IsNullOrEmpty(toConvert)) - { - DateTimeOffset deserialisedValue; - try - { - deserialisedValue = XmlConvert.ToDateTimeOffset(toConvert); - prop.SetValue(x, deserialisedValue, null); - } - catch (Exception) - { - object result; - if (TryGetFromString(toConvert, out result, type)) - { - prop.SetValue(x, result, null); - } - else - { - //fallback to parse - deserialisedValue = DateTimeOffset.Parse(toConvert); - prop.SetValue(x, deserialisedValue, null); - } - } - } - } + else if (type == typeof(DateTimeOffset)) + { + var toConvert = value.ToString(); + if (!string.IsNullOrEmpty(toConvert)) + { + DateTimeOffset deserialisedValue; + try + { + deserialisedValue = XmlConvert.ToDateTimeOffset(toConvert); + prop.SetValue(x, deserialisedValue, null); + } + catch (Exception) + { + object result; + if (TryGetFromString(toConvert, out result, type)) + { + prop.SetValue(x, result, null); + } + else + { + //fallback to parse + deserialisedValue = DateTimeOffset.Parse(toConvert); + prop.SetValue(x, deserialisedValue, null); + } + } + } + } else if (type == typeof(Decimal)) { value = Decimal.Parse(value.ToString(), Culture); @@ -207,12 +207,12 @@ private void Map(object x, XElement root) var raw = value.ToString(); value = string.IsNullOrEmpty(raw) ? Guid.Empty : new Guid(value.ToString()); prop.SetValue(x, value, null); - } - else if (type == typeof(TimeSpan)) - { - var timeSpan = XmlConvert.ToTimeSpan(value.ToString()); - prop.SetValue(x, timeSpan, null); - } + } + else if (type == typeof(TimeSpan)) + { + var timeSpan = XmlConvert.ToTimeSpan(value.ToString()); + prop.SetValue(x, timeSpan, null); + } else if (type.IsGenericType) { var t = type.GetGenericArguments()[0]; @@ -242,7 +242,7 @@ private void Map(object x, XElement root) object result; if (TryGetFromString(value.ToString(), out result, type)) { - prop.SetValue(x, result, null); + prop.SetValue(x, result, null); } else { @@ -261,17 +261,17 @@ private void Map(object x, XElement root) } } - private static bool TryGetFromString(string inputString, out object result, Type type) - { - var converter = TypeDescriptor.GetConverter(type); - if (converter.CanConvertFrom(typeof(string))) - { - result = (converter.ConvertFromInvariantString(inputString)); - return true; - } - result = null; - return false; - } + private static bool TryGetFromString(string inputString, out object result, Type type) + { + var converter = TypeDescriptor.GetConverter(type); + if (converter.CanConvertFrom(typeof(string))) + { + result = (converter.ConvertFromInvariantString(inputString)); + return true; + } + result = null; + return false; + } private void PopulateListFromElements(Type t, IEnumerable elements, IList list) {