回答

6

一個解決方案是使用反射遍歷實體的所有「自定義」屬性,並將它們序列化爲JSON字符串。

我們可以覆蓋TableEntity的ReadEntityWriteEntity方法來勾去/系列化:

using System; 
using System.Linq; 
using System.Reflection; 
using System.Collections.Generic; 
using Microsoft.WindowsAzure.Storage; 
using Microsoft.WindowsAzure.Storage.Table; 
using Newtonsoft.Json; 
using Newtonsoft.Json.Linq; 

public abstract class CustomEntity : TableEntity 
{ 
    public override IDictionary<string, EntityProperty> WriteEntity (OperationContext operationContext) 
    { 
     var properties = base.WriteEntity(operationContext); 

     // Iterating through the properties of the entity 
     foreach (var property in GetType().GetProperties().Where(property => 
       // Excluding props explicitly marked to ignore serialization 
       !property.GetCustomAttributes<IgnorePropertyAttribute>(true).Any() && 
       // Excluding already serialized props 
       !properties.ContainsKey(property.Name) && 
       // Excluding internal TableEntity props 
       typeof(TableEntity).GetProperties().All(p => p.Name != property.Name))) 
     { 
      var value = property.GetValue(this); 
      if (value != null) 
       // Serializing property to JSON 
       properties.Add(property.Name, new EntityProperty(JsonConvert.SerializeObject(value))); 
     } 

     return properties; 
    } 

    public override void ReadEntity (IDictionary<string, EntityProperty> properties, OperationContext operationContext) 
    { 
     base.ReadEntity(properties, operationContext); 

     // Iterating through the properties of the entity 
     foreach (var property in GetType().GetProperties().Where(property => 
       // Excluding props explicitly marked to ignore serialization 
       !property.GetCustomAttributes<IgnorePropertyAttribute>(true).Any() && 
       // Excluding props which were not originally serialized 
       properties.ContainsKey(property.Name) && 
       // Excluding props with target type of string (they are natively supported) 
       property.PropertyType != typeof(string) && 
       // Excluding non-string table fields (this will filter-out 
       // all the remaining natively supported props like byte, DateTime, etc) 
       properties[property.Name].PropertyType == EdmType.String)) 
     { 
      // Checking if property contains a valid JSON 
      var jToken = TryParseJson(properties[property.Name].StringValue); 
      if (jToken != null) 
      { 
       // Constructing method for deserialization 
       var toObjectMethod = jToken.GetType().GetMethod("ToObject", new[] { typeof(Type) }); 
       // Invoking the method with the target property type; eg, jToken.ToObject(CustomType) 
       var value = toObjectMethod.Invoke(jToken, new object[] { property.PropertyType }); 

       property.SetValue(this, value); 
      } 
     } 
    } 

    private static JToken TryParseJson (string s) 
    { 
     try { return JToken.Parse(s); } 
     catch (JsonReaderException) { return null; } 
    } 
} 

現在,如果我們從CustomEntity類繼承我們的表實體,我們可以自由的使用性能與支持的任何類型由Json.NET提供。

+1

我們已經注意到這個代碼的問題 - 對property.GetType()的調用幾乎所有屬性都返回false,因爲屬性的類型是「Microsoft.WindowsAzure.Storage.Table.EntityProperty」,所以一切落入解析器。 'TryParseJson'然後將看起來像八進制數字的字符串轉換成八進制的十進制表示形式。 –

+1

@ Zhaph-BenDuguid你是對的,感謝修復!我實際上是在生產中使用它,並在很久以前做出了相同的修復,但忘記了更新代碼,這是我的錯。 我還添加了條件來跳過[IgnoreProperty]屬性的屬性的反序列化/序列化。 – Elringus

+0

是的,它會出現我們已經做了類似的:'!Attribute.IsDefined(property,typeof(JsonIgnoreAttribute))' –

相關問題