diff --git a/iothub/device/src/ClientPropertyCollection.cs b/iothub/device/src/ClientPropertyCollection.cs
index e23246d6a9..214889e2ac 100644
--- a/iothub/device/src/ClientPropertyCollection.cs
+++ b/iothub/device/src/ClientPropertyCollection.cs
@@ -170,8 +170,9 @@ public bool Contains(string componentName, string propertyName)
/// The type to cast the object to.
/// The component which holds the required property.
/// The property to get.
- /// The value of the component-level property.
- /// true if the property collection contains a component level property with the specified key; otherwise, false.
+ /// When this method returns true, this contains the value of the component-level property.
+ /// When this method returns false, this contains the default value of the type T passed in.
+ /// True if a component-level property of type T with the specified key was found; otherwise, it returns false.
public virtual bool TryGetValue(string componentName, string propertyName, out T propertyValue)
{
if (Logging.IsEnabled && Convention == null)
@@ -180,35 +181,72 @@ public virtual bool TryGetValue(string componentName, string propertyName, ou
$"TryGetValue will attempt to get the property value but may not behave as expected.", nameof(TryGetValue));
}
+ // If either the component name or the property name is null, empty or whitespace,
+ // then return false with the default value of the type passed in.
+ if (string.IsNullOrWhiteSpace(componentName) || string.IsNullOrWhiteSpace(propertyName))
+ {
+ propertyValue = default;
+ return false;
+ }
+
if (Contains(componentName, propertyName))
{
object componentProperties = Collection[componentName];
+ // If the ClientPropertyCollection was constructed by the user application (eg. for updating the client properties)
+ // then the componentProperties are retrieved as a dictionary.
+ // The required property value can be fetched from the dictionary directly.
if (componentProperties is IDictionary nestedDictionary)
{
- if (nestedDictionary.TryGetValue(propertyName, out object dictionaryElement))
+ // First verify that the retrieved dictionary contains the component identifier { "__t": "c" }.
+ // If not, then the retrieved nested dictionary is actually a root-level property of type map.
+ if (nestedDictionary.TryGetValue(ConventionBasedConstants.ComponentIdentifierKey, out object componentIdentifierValue)
+ && componentIdentifierValue.ToString() == ConventionBasedConstants.ComponentIdentifierValue)
{
- // If the value is null, go ahead and return it.
- if (dictionaryElement == null)
- {
- propertyValue = default;
- return true;
- }
-
- // If the object is of type T or can be cast to type T, go ahead and return it.
- if (dictionaryElement is T valueRef
- || NumericHelpers.TryCastNumericTo(dictionaryElement, out valueRef))
+ if (nestedDictionary.TryGetValue(propertyName, out object dictionaryElement))
{
- propertyValue = valueRef;
- return true;
+ // If the value associated with the key is null, then return true with the default value of the type passed in.
+ if (dictionaryElement == null)
+ {
+ propertyValue = default;
+ return true;
+ }
+
+ // If the object is of type T or can be cast to type T, go ahead and return it.
+ if (dictionaryElement is T valueRef
+ || NumericHelpers.TryCastNumericTo(dictionaryElement, out valueRef))
+ {
+ propertyValue = valueRef;
+ return true;
+ }
}
}
}
else
{
- // If it's not, we need to try to convert it using the serializer.
- Convention.PayloadSerializer.TryGetNestedObjectValue(componentProperties, propertyName, out propertyValue);
- return true;
+ // If the ClientPropertyCollection was constructed by the SDK (eg. when retrieving the client properties)
+ // then the componentProperties are retrieved as the json object that is defined in the PayloadConvention.
+ // The required property value then needs to be deserialized accordingly.
+ try
+ {
+ // First verify that the retrieved dictionary contains the component identifier { "__t": "c" }.
+ // If not, then the retrieved nested dictionary is actually a root-level property of type map.
+ if (Convention
+ .PayloadSerializer
+ .TryGetNestedObjectValue(componentProperties, ConventionBasedConstants.ComponentIdentifierKey, out string componentIdentifierValue)
+ && componentIdentifierValue == ConventionBasedConstants.ComponentIdentifierValue)
+ {
+ // Since the value cannot be cast to directly, we need to try to convert it using the serializer.
+ // If it can be successfully converted, go ahead and return it.
+ Convention.PayloadSerializer.TryGetNestedObjectValue(componentProperties, propertyName, out propertyValue);
+ return true;
+ }
+ }
+ catch
+ {
+ // In case the value cannot be converted using the serializer,
+ // then return false with the default value of the type passed in.
+ }
}
}
diff --git a/iothub/device/src/PayloadCollection.cs b/iothub/device/src/PayloadCollection.cs
index 1943264358..a6ab45581a 100644
--- a/iothub/device/src/PayloadCollection.cs
+++ b/iothub/device/src/PayloadCollection.cs
@@ -107,13 +107,11 @@ public bool Contains(string key)
///
/// Gets the value of the object from the collection.
///
- ///
- /// This class is used for both sending and receiving properties for the device.
- ///
/// The type to cast the object to.
/// The key of the property to get.
- /// The value of the object from the collection.
- /// True if the collection contains an element with the specified key; otherwise, it returns false.
+ /// When this method returns true, this contains the value of the object from the collection.
+ /// When this method returns false, this contains the default value of the type T passed in.
+ /// True if a value of type T with the specified key was found; otherwise, it returns false.
public bool TryGetValue(string key, out T value)
{
if (Logging.IsEnabled && Convention == null)
@@ -122,9 +120,16 @@ public bool TryGetValue(string key, out T value)
$"TryGetValue will attempt to get the property value but may not behave as expected.", nameof(TryGetValue));
}
+ // If the key is null, empty or whitespace, then return false with the default value of the type passed in.
+ if (string.IsNullOrWhiteSpace(key))
+ {
+ value = default;
+ return false;
+ }
+
if (Collection.ContainsKey(key))
{
- // If the value is null, go ahead and return it.
+ // If the value associated with the key is null, then return true with the default value of the type passed in.
if (Collection[key] == null)
{
value = default;
@@ -139,9 +144,18 @@ public bool TryGetValue(string key, out T value)
return true;
}
- // If it's not, we need to try to convert it using the serializer.
- value = Convention.PayloadSerializer.ConvertFromObject(Collection[key]);
- return true;
+ try
+ {
+ // If the value cannot be cast to directly, we need to try to convert it using the serializer.
+ // If it can be successfully converted, go ahead and return it.
+ value = Convention.PayloadSerializer.ConvertFromObject(Collection[key]);
+ return true;
+ }
+ catch
+ {
+ // In case the value cannot be converted using the serializer,
+ // then return false with the default value of the type passed in.
+ }
}
value = default;
diff --git a/iothub/device/tests/ClientPropertyCollectionTests.cs b/iothub/device/tests/ClientPropertyCollectionTests.cs
index f9ea6caa2e..125b792bd2 100644
--- a/iothub/device/tests/ClientPropertyCollectionTests.cs
+++ b/iothub/device/tests/ClientPropertyCollectionTests.cs
@@ -56,6 +56,7 @@ public class ClientPropertyCollectionTests
[TestMethod]
public void ClientPropertyCollection_CanAddSimpleObjectsAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection
{
{ StringPropertyName, StringPropertyValue },
@@ -70,6 +71,8 @@ public void ClientPropertyCollection_CanAddSimpleObjectsAndGetBackWithoutDeviceC
{ DateTimePropertyName, s_dateTimePropertyValue }
};
+ // act, assert
+
clientProperties.TryGetValue(StringPropertyName, out string stringOutValue);
stringOutValue.Should().Be(StringPropertyValue);
@@ -107,26 +110,35 @@ public void ClientPropertyCollection_CanAddSimpleObjectsAndGetBackWithoutDeviceC
[TestMethod]
public void ClientPropertyCollection_AddSimpleObjectAgainThrowsException()
{
+ // arrange
var clientProperties = new ClientPropertyCollection
{
{ StringPropertyName, StringPropertyValue }
};
+ // act
Action act = () => clientProperties.AddRootProperty(StringPropertyName, StringPropertyValue);
+
+ // assert
act.Should().Throw("\"Add\" method does not support adding a key that already exists in the collection.");
}
[TestMethod]
public void ClientPropertyCollection_CanUpdateSimpleObjectAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection
{
{ StringPropertyName, StringPropertyValue }
};
+
+ // act, assert
+
clientProperties.TryGetValue(StringPropertyName, out string outValue);
outValue.Should().Be(StringPropertyValue);
clientProperties.AddOrUpdateRootProperty(StringPropertyName, UpdatedPropertyValue);
+
clientProperties.TryGetValue(StringPropertyName, out string outValueChanged);
outValueChanged.Should().Be(UpdatedPropertyValue, "\"AddOrUpdate\" should overwrite the value if the key already exists in the collection.");
}
@@ -134,10 +146,12 @@ public void ClientPropertyCollection_CanUpdateSimpleObjectAndGetBackWithoutDevic
[TestMethod]
public void ClientPropertyCollection_CanAddNullPropertyAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
clientProperties.AddRootProperty(StringPropertyName, StringPropertyValue);
clientProperties.AddRootProperty(IntPropertyName, null);
+ // act, assert
clientProperties.TryGetValue(StringPropertyName, out string outStringValue);
outStringValue.Should().Be(StringPropertyValue);
@@ -149,10 +163,13 @@ public void ClientPropertyCollection_CanAddNullPropertyAndGetBackWithoutDeviceCl
[TestMethod]
public void ClientPropertyCollection_CanAddMultiplePropertyAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
clientProperties.AddRootProperty(StringPropertyName, StringPropertyValue);
clientProperties.AddRootProperty(IntPropertyName, IntPropertyValue);
+ // act, assert
+
clientProperties.TryGetValue(StringPropertyName, out string outStringValue);
outStringValue.Should().Be(StringPropertyValue);
@@ -160,24 +177,57 @@ public void ClientPropertyCollection_CanAddMultiplePropertyAndGetBackWithoutDevi
outIntValue.Should().Be(IntPropertyValue);
}
+ [TestMethod]
+ public void ClientPropertyCollection_TryGetValueShouldReturnFalseIfValueNotFound()
+ {
+ // arrange
+ var clientProperties = new ClientPropertyCollection();
+ clientProperties.AddRootProperty(StringPropertyName, StringPropertyValue);
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(IntPropertyName, out int outIntValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
+ [TestMethod]
+ public void ClientPropertyCollection_TryGetValueShouldReturnFalseIfValueCouldNotBeDeserialized()
+ {
+ // arrange
+ var clientProperties = new ClientPropertyCollection();
+ clientProperties.AddRootProperty(StringPropertyName, StringPropertyValue);
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(StringPropertyName, out int outIntValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
[TestMethod]
public void ClientPropertyCollection_CanAddSimpleObjectWithComponentAndGetBackWithoutDeviceClient()
{
- var clientProperties = new ClientPropertyCollection
+ // arrange
+ var componentLevelProperties = new Dictionary
{
- { ComponentName, new Dictionary {
- { StringPropertyName, StringPropertyValue },
- { BoolPropertyName, BoolPropertyValue },
- { DoublePropertyName, DoublePropertyValue },
- { FloatPropertyName, FloatPropertyValue },
- { IntPropertyName, IntPropertyValue },
- { ShortPropertyName, ShortPropertyValue },
- { ObjectPropertyName, s_objectPropertyValue },
- { ArrayPropertyName, s_arrayPropertyValue },
- { MapPropertyName, s_mapPropertyValue },
- { DateTimePropertyName, s_dateTimePropertyValue } }
- }
+ { StringPropertyName, StringPropertyValue },
+ { BoolPropertyName, BoolPropertyValue },
+ { DoublePropertyName, DoublePropertyValue },
+ { FloatPropertyName, FloatPropertyValue },
+ { IntPropertyName, IntPropertyValue },
+ { ShortPropertyName, ShortPropertyValue },
+ { ObjectPropertyName, s_objectPropertyValue },
+ { ArrayPropertyName, s_arrayPropertyValue },
+ { MapPropertyName, s_mapPropertyValue },
+ { DateTimePropertyName, s_dateTimePropertyValue }
};
+ var clientProperties = new ClientPropertyCollection();
+ clientProperties.AddComponentProperties(ComponentName, componentLevelProperties);
+
+ // act, assert
clientProperties.TryGetValue(ComponentName, StringPropertyName, out string stringOutValue);
stringOutValue.Should().Be(StringPropertyValue);
@@ -216,19 +266,26 @@ public void ClientPropertyCollection_CanAddSimpleObjectWithComponentAndGetBackWi
[TestMethod]
public void ClientPropertyCollection_AddSimpleObjectWithComponentAgainThrowsException()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
+ // act
Action act = () => clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
+
+ // assert
act.Should().Throw("\"Add\" method does not support adding a key that already exists in the collection.");
}
[TestMethod]
public void ClientPropertyCollection_CanUpdateSimpleObjectWithComponentAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
+ // act, assert
+
clientProperties.TryGetValue(ComponentName, StringPropertyName, out string outValue);
outValue.Should().Be(StringPropertyValue);
@@ -240,10 +297,13 @@ public void ClientPropertyCollection_CanUpdateSimpleObjectWithComponentAndGetBac
[TestMethod]
public void ClientPropertyCollection_CanAddNullPropertyWithComponentAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
clientProperties.AddComponentProperty(ComponentName, IntPropertyName, null);
+ // act, assert
+
clientProperties.TryGetValue(ComponentName, StringPropertyName, out string outStringValue);
outStringValue.Should().Be(StringPropertyValue);
@@ -255,10 +315,13 @@ public void ClientPropertyCollection_CanAddNullPropertyWithComponentAndGetBackWi
[TestMethod]
public void ClientPropertyCollection_CanAddMultiplePropertyWithComponentAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
clientProperties.AddComponentProperty(ComponentName, IntPropertyName, IntPropertyValue);
+ // act, assert
+
clientProperties.TryGetValue(ComponentName, StringPropertyName, out string outStringValue);
outStringValue.Should().Be(StringPropertyValue);
@@ -269,12 +332,15 @@ public void ClientPropertyCollection_CanAddMultiplePropertyWithComponentAndGetBa
[TestMethod]
public void ClientPropertyCollection_CanAddSimpleWritablePropertyAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
-
var writableResponse = new NewtonsoftJsonWritablePropertyResponse(StringPropertyValue, CommonClientResponseCodes.OK, 2, WritablePropertyDescription);
clientProperties.AddRootProperty(StringPropertyName, writableResponse);
+ // act
clientProperties.TryGetValue(StringPropertyName, out NewtonsoftJsonWritablePropertyResponse outValue);
+
+ // assert
outValue.Value.Should().Be(writableResponse.Value);
outValue.AckCode.Should().Be(writableResponse.AckCode);
outValue.AckVersion.Should().Be(writableResponse.AckVersion);
@@ -284,12 +350,15 @@ public void ClientPropertyCollection_CanAddSimpleWritablePropertyAndGetBackWitho
[TestMethod]
public void ClientPropertyCollection_CanAddWritablePropertyWithComponentAndGetBackWithoutDeviceClient()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
-
var writableResponse = new NewtonsoftJsonWritablePropertyResponse(StringPropertyValue, CommonClientResponseCodes.OK, 2, WritablePropertyDescription);
clientProperties.AddComponentProperty(ComponentName, StringPropertyName, writableResponse);
+ // act
clientProperties.TryGetValue(ComponentName, StringPropertyName, out NewtonsoftJsonWritablePropertyResponse outValue);
+
+ // assert
outValue.Value.Should().Be(writableResponse.Value);
outValue.AckCode.Should().Be(writableResponse.AckCode);
outValue.AckVersion.Should().Be(writableResponse.AckVersion);
@@ -299,15 +368,65 @@ public void ClientPropertyCollection_CanAddWritablePropertyWithComponentAndGetBa
[TestMethod]
public void ClientPropertyCollection_AddingComponentAddsComponentIdentifier()
{
+ // arrange
var clientProperties = new ClientPropertyCollection();
clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
+ // act
clientProperties.TryGetValue(ComponentName, StringPropertyName, out string outValue);
clientProperties.TryGetValue(ComponentName, ConventionBasedConstants.ComponentIdentifierKey, out string componentOut);
+ // assert
outValue.Should().Be(StringPropertyValue);
componentOut.Should().Be(ConventionBasedConstants.ComponentIdentifierValue);
}
+
+ [TestMethod]
+ public void ClientPropertyCollection_TryGetValueWithComponentShouldReturnFalseIfValueNotFound()
+ {
+ // arrange
+ var clientProperties = new ClientPropertyCollection();
+ clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(ComponentName, IntPropertyName, out int outIntValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
+ [TestMethod]
+ public void ClientPropertyCollection_TryGetValueWithComponentShouldReturnFalseIfValueCouldNotBeDeserialized()
+ {
+ // arrange
+ var clientProperties = new ClientPropertyCollection();
+ clientProperties.AddComponentProperty(ComponentName, StringPropertyName, StringPropertyValue);
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(ComponentName, StringPropertyName, out int outIntValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
+ [TestMethod]
+ public void ClientPropertyCollection_TryGetValueWithComponentShouldReturnFalseIfNotAComponent()
+ {
+ // arrange
+ var clientProperties = new ClientPropertyCollection();
+ clientProperties.AddRootProperty(MapPropertyName, s_mapPropertyValue);
+ string incorrectlyMappedComponentName = MapPropertyName;
+ string incorrectlyMappedComponentPropertyName = "key1";
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(incorrectlyMappedComponentName, incorrectlyMappedComponentPropertyName, out object propertyValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ propertyValue.Should().Be(default);
+ }
}
internal class CustomClientProperty
diff --git a/iothub/device/tests/ClientPropertyCollectionTestsNewtonsoft.cs b/iothub/device/tests/ClientPropertyCollectionTestsNewtonsoft.cs
index 07a820febe..7e12e2c9b8 100644
--- a/iothub/device/tests/ClientPropertyCollectionTestsNewtonsoft.cs
+++ b/iothub/device/tests/ClientPropertyCollectionTestsNewtonsoft.cs
@@ -121,8 +121,11 @@ public class ClientPropertyCollectionTestsNewtonsoft
[TestMethod]
public void ClientPropertyCollectionNewtonsoft_CanGetValue()
{
+ // arrange
var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionToRoundTrip, DefaultPayloadConvention.Instance);
+ // act, assert
+
clientProperties.TryGetValue(StringPropertyName, out string stringOutValue);
stringOutValue.Should().Be(StringPropertyValue);
@@ -162,8 +165,11 @@ public void ClientPropertyCollectionNewtonsoft_CanGetValue()
[TestMethod]
public void ClientPropertyCollectionNewtonsoft_CanGetValueWithComponent()
{
+ // arrange
var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionWithComponentToRoundTrip, DefaultPayloadConvention.Instance);
+ // act, assert
+
clientProperties.TryGetValue(ComponentName, StringPropertyName, out string stringOutValue);
stringOutValue.Should().Be(StringPropertyValue);
@@ -203,9 +209,13 @@ public void ClientPropertyCollectionNewtonsoft_CanGetValueWithComponent()
[TestMethod]
public void ClientPropertyCollectionNewtonsoft_CanAddSimpleWritablePropertyAndGetBack()
{
+ // arrange
var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionWritablePropertyToRoundTrip, DefaultPayloadConvention.Instance);
+ // act
clientProperties.TryGetValue(StringPropertyName, out NewtonsoftJsonWritablePropertyResponse outValue);
+
+ // assert
outValue.Value.Should().Be(StringPropertyValue);
outValue.AckCode.Should().Be(s_writablePropertyResponse.AckCode);
outValue.AckVersion.Should().Be(s_writablePropertyResponse.AckVersion);
@@ -215,9 +225,13 @@ public void ClientPropertyCollectionNewtonsoft_CanAddSimpleWritablePropertyAndGe
[TestMethod]
public void ClientPropertyCollectionNewtonsoft_CanAddWritablePropertyWithComponentAndGetBack()
{
+ // arrange
var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionWritablePropertyWithComponentToRoundTrip, DefaultPayloadConvention.Instance);
+ // act
clientProperties.TryGetValue(ComponentName, StringPropertyName, out NewtonsoftJsonWritablePropertyResponse outValue);
+
+ // assert
outValue.Value.Should().Be(StringPropertyValue);
outValue.AckCode.Should().Be(s_writablePropertyResponse.AckCode);
outValue.AckVersion.Should().Be(s_writablePropertyResponse.AckVersion);
@@ -227,14 +241,85 @@ public void ClientPropertyCollectionNewtonsoft_CanAddWritablePropertyWithCompone
[TestMethod]
public void ClientPropertyCollectionNewtonsoft_CanGetComponentIdentifier()
{
+ // arrange
var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionWithComponentToRoundTrip, DefaultPayloadConvention.Instance);
+ // act
clientProperties.TryGetValue(ComponentName, StringPropertyName, out string outValue);
clientProperties.TryGetValue(ComponentName, ConventionBasedConstants.ComponentIdentifierKey, out string componentOut);
+ // assert
outValue.Should().Be(StringPropertyValue);
componentOut.Should().Be(ConventionBasedConstants.ComponentIdentifierValue);
}
+
+ [TestMethod]
+ public void ClientPropertyCollectionNewtonSoft_TryGetValueShouldReturnFalseIfValueNotFound()
+ {
+ // arrange
+ var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionToRoundTrip, DefaultPayloadConvention.Instance);
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue("thisPropertyDoesNotExist", out int outIntValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
+ [TestMethod]
+ public void ClientPropertyCollectionNewtonSoft_TryGetValueWithComponentShouldReturnFalseIfValueNotFound()
+ {
+ // arrange
+ var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionWithComponentToRoundTrip, DefaultPayloadConvention.Instance);
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(ComponentName, "thisPropertyDoesNotExist", out int outIntValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
+ [TestMethod]
+ public void ClientPropertyCollectionNewtonSoft_TryGetValueShouldReturnFalseIfValueCouldNotBeDeserialized()
+ {
+ var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionToRoundTrip, DefaultPayloadConvention.Instance);
+
+ bool isValueRetrieved = clientProperties.TryGetValue(StringPropertyName, out int outIntValue);
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
+ [TestMethod]
+ public void ClientPropertyCollectionNewtonSoft_TryGetValueWithComponentShouldReturnFalseIfValueCouldNotBeDeserialized()
+ {
+ // arrange
+ var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionWithComponentToRoundTrip, DefaultPayloadConvention.Instance);
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(ComponentName, StringPropertyName, out int outIntValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ outIntValue.Should().Be(default);
+ }
+
+ [TestMethod]
+ public void ClientPropertyCollectionNewtonSoft_TryGetValueWithComponentShouldReturnFalseIfNotAComponent()
+ {
+ // arrange
+ var clientProperties = ClientPropertyCollection.FromTwinCollection(collectionToRoundTrip, DefaultPayloadConvention.Instance);
+ string incorrectlyMappedComponentName = MapPropertyName;
+ string incorrectlyMappedComponentPropertyName = "key1";
+
+ // act
+ bool isValueRetrieved = clientProperties.TryGetValue(incorrectlyMappedComponentName, incorrectlyMappedComponentPropertyName, out object propertyValue);
+
+ // assert
+ isValueRetrieved.Should().BeFalse();
+ propertyValue.Should().Be(default);
+ }
}
internal class RootLevelProperties