Azure Digital Twins中自定义元数据字段$frq创建及读取异常问题
我想给数字孪生体创建一个类似$model的自定义元数据字段$frq,用C#编写了CustomDigitalTwin相关类,调用DigitalTwins.Core SDK创建孪生体时无报错,但该字段在Azure Digital Twins Explorer中不显示,且通过C#检索时FRQ的值始终为null。
测试代码
string twinId = "test-twin"; var initData = new TestDigitalTwin { Id = twinId, Metadata = { ModelId = "dtmi:com:dtwin:test;1", FRQ = "60" }, }; await client.CreateOrReplaceDigitalTwinAsync<CustomDigitalTwin>(twinId, initData); Response<CustomDigitalTwin> getCustomDtResponse = await client.GetDigitalTwinAsync<CustomDigitalTwin>(twinId); CustomDigitalTwin customDt = getCustomDtResponse.Value; Console.WriteLine(customDt.Metadata.FRQ); // FRQ is null here
类定义代码
// Define a custom model type for the twin to be created internal class TestDigitalTwin { [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinId)] public string Id { get; set; } [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinETag)] public string ETag { get; set; } [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinMetadata)] public MyCustomDigitalTwinMetadata Metadata { get; set; } = new MyCustomDigitalTwinMetadata(); } internal class MyCustomDigitalTwinMetadata { [JsonPropertyName(DigitalTwinsJsonPropertyNames.MetadataModel)] public string ModelId { get; set; } [JsonPropertyName(DigitalTwinsJsonPropertyNames.MetadataFRQ)] public string FRQ { get; set; } [JsonPropertyName("temperature")] public DigitalTwinPropertyMetadata Temperature { get; set; } [JsonPropertyName("humidity")] public DigitalTwinPropertyMetadata Humidity { get; set; } } /// <summary> /// String constants for use in JSON de/serialization for custom types. /// </summary> public static class DigitalTwinsJsonPropertyNames { /// <summary> /// The JSON property name for the Id field on a digital twin. /// </summary> public const string DigitalTwinId = "$dtId"; /// <summary> /// The JSON property name for the ETag field on a digital twin. /// </summary> public const string DigitalTwinETag = "$etag"; /// <summary> /// The JSON property name for the metadata field on a digital twin or a component. /// </summary> public const string DigitalTwinMetadata = "$metadata"; /// <summary> /// The JSON property name for the model field on a digital twin metadata. /// </summary> public const string MetadataModel = "$model"; /// <summary> /// The JSON property name for the frequency field on a digital twin metadata. /// </summary> public const string MetadataFRQ = "$frq"; /// <summary> /// The last update time of a digital twin property, used in the $metadata object /// on a digital twin or component about their properties. /// </summary> public const string MetadataLastUpdateTime = "$lastUpdateTime"; /// <summary> /// The last update time of a digital twin property, used in the $metadata object /// on a digital twin or component about their properties. /// </summary> public const string MetadataPropertyLastUpdateTime = "lastUpdateTime"; /// <summary> /// The time the value of a digital twin property was sourced, used in the $metadata /// object on a digital twin or component about their properties. /// </summary> public const string MetadataPropertySourceTime = "sourceTime"; /// <summary> /// The JSON property name for the Id field on a relationship. /// </summary> public const string RelationshipId = "$relationshipId"; /// <summary> /// The JSON property name for the source Id field on a relationship. /// </summary> public const string RelationshipSourceId = "$sourceId"; /// <summary> /// The JSON property name for the target Id field on a relationship. /// </summary> public const string RelationshipTargetId = "$targetId"; /// <summary> /// The JSON property name for the name field on a relationship. /// </summary> public const string RelationshipName = "$relationshipName"; } public class DigitalTwinPropertyMetadata { /// <summary> /// The date and time the property was last updated. /// </summary> [JsonPropertyName(DigitalTwinsJsonPropertyNames.MetadataPropertyLastUpdateTime)] public DateTimeOffset LastUpdatedOn { get; set; } /// <summary> /// The date and time the value of the property was sourced. /// </summary> [JsonPropertyName(DigitalTwinsJsonPropertyNames.MetadataPropertySourceTime)] public DateTimeOffset? SourceTime { get; set; } }
问题原因
Azure Digital Twins(ADT)中所有以$开头的字段都是系统保留字段,仅支持平台预定义的$dtId、$etag、$metadata、$model等字段,不允许自定义以$为前缀的元数据字段。你定义的$frq会被ADT服务自动忽略,不会被存储,因此既无法在Explorer中看到,也无法通过SDK检索到。
修正方案
方案1:将FRQ作为孪生体的普通属性(推荐)
在你的DTMI模型(dtmi:com:dtwin:test;1)中添加frq属性定义,然后在TestDigitalTwin类中直接添加对应的属性,而非放入Metadata对象:
修改后的TestDigitalTwin类:
internal class TestDigitalTwin { [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinId)] public string Id { get; set; } [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinETag)] public string ETag { get; set; } [JsonPropertyName(DigitalTwinsJsonPropertyNames.DigitalTwinMetadata)] public MyCustomDigitalTwinMetadata Metadata { get; set; } = new MyCustomDigitalTwinMetadata(); // 添加普通属性FRQ [JsonPropertyName("frq")] public string FRQ { get; set; } }
创建孪生体时的修改:
var initData = new TestDigitalTwin { Id = twinId, Metadata = { ModelId = "dtmi:com:dtwin:test;1" }, FRQ = "60" // 赋值给普通属性 };
此时通过SDK读取时,直接访问customDt.FRQ即可获取值,且该字段会在Azure Digital Twins Explorer中显示。
方案2:使用非$前缀的自定义元数据字段(不推荐)
如果一定要将该字段放在$metadata下,需去掉$前缀,比如改为frq:
修改DigitalTwinsJsonPropertyNames中的常量:
public const string MetadataFRQ = "frq"; // 去掉$前缀
修改MyCustomDigitalTwinMetadata中的属性:
[JsonPropertyName(DigitalTwinsJsonPropertyNames.MetadataFRQ)] public string FRQ { get; set; }
这种方式虽然能存储,但ADT的$metadata对象设计初衷是存储属性的元数据(如更新时间),而非自定义业务字段,因此更推荐方案1。
内容的提问来源于stack exchange,提问作者Raphael Springer

