将 DynamicTableEntity 转换为 Json

Convert DynamicTableEntity to Json

我有一个 MVC 应用程序,我执行查询以获取 table 内容。但是当我尝试 return 结果返回给客户端时,我得到一个 ExceptionMessage: "Cannot return Binary type for a String typed property."

控制器代码:

public IEnumerable<DynamicTableEntity> Get(string table)
{
    var storageAccount = CloudStorageAccount.Parse(<StorageConnectionString>);
    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();
    CloudTable table = tableClient.GetTableReference(table);

    TableQuery<DynamicTableEntity> query = new TableQuery<DynamicTableEntity>()
       .Where("")
       .Take(50);

    return table.ExecuteQuery(query);
}

当我执行 Get table 我得到 500 Internal Server Error

ExceptionMessage: "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."

InnerException:

ExceptionMessage: "Cannot return Binary type for a String typed property."

但是当我调试 "Get" 函数时,我看到所有数据都按预期接收,这是一个 Json 序列化问题。我尝试使用 CloudTableClient PayloadFormatDefaultRequestOptions 但没有成功。

有什么建议吗?

堆栈跟踪:

{
Message: "An error has occurred."
ExceptionMessage: "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."
ExceptionType: "System.InvalidOperationException"
StackTrace: null
InnerException: {
Message: "An error has occurred."
ExceptionMessage: "Error getting value from 'BinaryValue' on 'Microsoft.WindowsAzure.Storage.Table.EntityProperty'."
ExceptionType: "Newtonsoft.Json.JsonSerializationException"
StackTrace: " at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeDictionary(JsonWriter writer, IDictionary values, JsonDictionaryContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty) at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType) at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType) at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding) at System.Net.Http.Formatting.JsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, Encoding effectiveEncoding) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStream(Type type, Object value, Stream writeStream, HttpContent content) at System.Net.Http.Formatting.BaseJsonMediaTypeFormatter.WriteToStreamAsync(Type type, Object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.GetResult() at System.Web.Http.WebHost.HttpControllerHandler.<WriteBufferedResponseContentAsync>d__1b.MoveNext()"
InnerException: {
Message: "An error has occurred."
ExceptionMessage: "Cannot return Binary type for a Boolean typed property."
ExceptionType: "System.InvalidOperationException"
StackTrace: " at Microsoft.WindowsAzure.Storage.Table.EntityProperty.EnforceType(EdmType requestedType) at Microsoft.WindowsAzure.Storage.Table.EntityProperty.get_BinaryValue() at GetBinaryValue(Object ) at Newtonsoft.Json.Serialization.DynamicValueProvider.GetValue(Object target)"
}-
}-
}

遗憾的是,DynamicTableEntity 和 EntityProperty 目前不可序列化。另一方面,POCO 实体是可序列化的。如果反序列化为派生自 TableEntity 的对象,那么这应该是开箱即用的可序列化。如果你想做一个真正的异构查询,你必须处理存储在单个 table 中并作为查询结果返回的不同类型,你可以使用 EntityResolver 解析为适当的类型。

我知道它不能完全回答你的问题,但我设法在 xml 中连载,你可以尝试调整它以使其在 json 中工作。

public static byte[] Serialize(this ITableEntity entity)
{
MemoryStream ms = new MemoryStream();
using(var messageWriter = new ODataMessageWriter(new Message(ms), new ODataMessageWriterSettings()))
{
    // Create an entry writer to write a top-level entry to the message.
    ODataWriter entryWriter = messageWriter.CreateODataEntryWriter();
    var writeODataEntity =typeof(TableConstants).Assembly.GetType("Microsoft.WindowsAzure.Storage.Table.Protocol.TableOperationHttpWebRequestFactory")
        .GetMethod("WriteOdataEntity", BindingFlags.NonPublic | BindingFlags.Static);

    writeODataEntity.Invoke(null, new object[] { entity, TableOperationType.Insert, null, entryWriter });
    return ms.ToArray();
}            
}

public static void Deserialize(this ITableEntity entity, byte[] value)
{
MemoryStream ms = new MemoryStream(value);
using(ODataMessageReader messageReader = new ODataMessageReader(new Message(ms), new ODataMessageReaderSettings()))
{
    ODataReader reader = messageReader.CreateODataEntryReader();
    var readAndUpdateTableEntity = typeof(TableConstants).Assembly.GetType("Microsoft.WindowsAzure.Storage.Table.Protocol.TableOperationHttpResponseParsers")
        .GetMethod("ReadAndUpdateTableEntity", BindingFlags.NonPublic | BindingFlags.Static);
    reader.Read();
    readAndUpdateTableEntity.Invoke(null, new object[] { entity,  reader.Item, 31, null });
}
}

internal class Message : IODataResponseMessage
{
private readonly Stream stream;
private readonly Dictionary<string, string> headers = new Dictionary<string, string>();

public Message(Stream stream)
{
    this.stream = stream;
    SetHeader("Content-Type", "application/atom+xml");
}

public string GetHeader(string headerName)
{
    string value;
    headers.TryGetValue(headerName, out value);
    return value;
}

public void SetHeader(string headerName, string headerValue)
{
    this.headers.Add(headerName, headerValue);
}

public Stream GetStream()
{
    return this.stream;
}

public IEnumerable<KeyValuePair<string, string>> Headers
{
    get
    {
        return this.headers;
    }
}

public int StatusCode
{
    get;
    set;
}
}

我已经实现了一个 API 将 DynamicTableEntity 对象序列化为 Json 字符串并将 Json 字符串反序列化回 DynamicTableEntity 对象。

请看: https://www.nuget.org/packages/DynamicTableEntityJsonSerializer/

用法

//实例化序列化器

DynamicTableEntityJsonSerializer serializer = new DynamicTableEntityJsonSerializer();

//将DynamicTableEntity序列化为Json字符串

string serializedEntity = serializer.Serialize(dynamicTableEntity);

//从Json字符串反序列化DynamicTableEntity

DynamicTableEntity dynamicTableEntity = serializer.Deserialize(serializedEntity);

欢迎任何评论:)

假设所有值都是字符串值,这一行就足够了

var tables = Record.Properties.Select(x => x.Value.StringValue).ToList();

如果您有更多类型,您可以创建一个开关函数来获取每种类型的值。