将 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 PayloadFormat
和 DefaultRequestOptions
但没有成功。
有什么建议吗?
堆栈跟踪:
{
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();
如果您有更多类型,您可以创建一个开关函数来获取每种类型的值。
我有一个 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 PayloadFormat
和 DefaultRequestOptions
但没有成功。
有什么建议吗?
堆栈跟踪:
{
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();
如果您有更多类型,您可以创建一个开关函数来获取每种类型的值。