在带有 ASP.NET 5 DNX 核心的 Azure 表中使用自定义 属性 类型

Using custom property types in Azure Tables with ASP.NET 5 DNX Core

A​​zure Table 存储 does not support 许多 属性 类型(List<>、TimeSpan 等)。

有 Lucifure Stash 和 Lokad.Cloud 等解决方案,但它们没有针对 DNX Core 5.0 进行编译。

是否可以通过 DNX Core 在 Azure Table 中添加对自定义 属性 类型的支持?

一种解决方案是使用反射遍历实体的所有“自定义”属性并将它们序列化为 JSON 字符串。

我们可以覆盖 TableEntity 的 ReadEntityWriteEntity 方法来挂钩 de-/serialization:

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 class 继承我们的 table 实体,我们可以自由地使用 Json.NET 支持的任何类型的属性。