返回 Azure TableEntity 对象列表时出现 SerializationException

SerializationException when returning List of Azure TableEntity objects

使用 WebAPI 返回 TableEntities 列表时,出现 500 内部服务器错误。当我查看 Visual Studio 中的输出时,我发现我得到了这些 'System.Runtime.Serialization.SerializationException'.

这是我在控制器中的代码

 public IEnumerable<ContactEntity> Get()
    {
        var creds = new StorageCredentials("MyAccountName", "MyKey");
        var storageAccount = new CloudStorageAccount(creds, false);

        // Create the table client.
        var tableClient = storageAccount.CreateCloudTableClient();

        // Retrieve a reference to the table.
        var contactsTable = tableClient.GetTableReference("contacts");

        // Create the table if it doesn't exist.
        contactsTable.CreateIfNotExists();

        // Construct the query operation for all contact entities
        var query = new TableQuery<ContactEntity>();

        var items = contactsTable.ExecuteQuery<ContactEntity>(query).ToList();

        return items;
    }

这是我的自定义 TableEntity 代码

    [Serializable]
public class ContactEntity: TableEntity
{

    public ContactEntity(string firstName, string lastName)
    {
        this.PartitionKey = lastName;
        this.RowKey = firstName;
    }

    public ContactEntity() { }

    public string Email { get; set; }

}

在控制器中,如果我手动创建实体列表,我不会遇到序列化问题。

public IEnumerable<ContactEntity> Get()
    {
        var creds = new StorageCredentials("MyAccountName", "MyKey");
        var storageAccount = new CloudStorageAccount(creds, false);

        // Create the table client.
        var tableClient = storageAccount.CreateCloudTableClient();

        // Retrieve a reference to the table.
        var contactsTable = tableClient.GetTableReference("contacts");

        // Create the table if it doesn't exist.
        contactsTable.CreateIfNotExists();

        // Construct the query operation for all contact entities
        var query = new TableQuery<ContactEntity>();

        var items = contactsTable.ExecuteQuery<ContactEntity>(query).ToList();

        var manualList = new List<ContactEntity>() { };

        manualList.Add(new ContactEntity { PartitionKey = items[0].PartitionKey, RowKey = items[0].RowKey, ETag = items[0].ETag, Timestamp = items[0].Timestamp });
        manualList.Add(new ContactEntity { PartitionKey = items[1].PartitionKey, RowKey = items[1].RowKey, ETag = items[1].ETag, Timestamp = items[1].Timestamp });


        return manualList;
    }

知道为什么吗?

这是输出中列出的异常 window。

抛出异常:mscorlib.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:mscorlib.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:Newtonsoft.Json.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:Newtonsoft.Json.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:Newtonsoft.Json.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:Newtonsoft.Json.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:Newtonsoft.Json.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:Newtonsoft.Json.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:mscorlib.dll 中的 'System.Runtime.Serialization.SerializationException' 抛出异常:'System.Runtime.Serialization.SerializationException' in mscorlib.dll

由于内部委托成员等原因,无法序列化从 TableEntity 继承的类型。见下文:

您有几个选择:

  1. 从 ITableEntity 接口而不是 TableEntity 继承...您必须自己实现核心 TableEntity 行为(一般情况下还不错),如果需要,这使您有机会实现序列化, 太

  2. 更改您的 Web API 以输出仅包含您想要 return 的实体属性的单独类型,并为您的实体类型实现一个转换函数,例如这个:

在 ContactEntity 中 class:

public JObject ToJson()
{
    var jo = new JObject();

    jo["PartitionKey"] = PartitionKey;
    jo["RowKey"] = RowKey;
    jo["Email"] = Email;

    // etc

    return jo;
}

在你的控制器中:

public IEnumerable<JObject> Get()
{
    // Create the table client.
    var tableClient = _account.CreateCloudTableClient();

    // Retrieve a reference to the table.
    var contactsTable = tableClient.GetTableReference("contacts");

    // Create the table if it doesn't exist.
    contactsTable.CreateIfNotExists();

    // Construct the query operation for all contact entities
    var query = new TableQuery<ContactEntity>();

    var items = contactsTable.ExecuteQuery<ContactEntity>(query).ToList();

    return items.Select(i => i.ToJson());
}

请注意从 returnContactEntity 的 IEnumerable 到 JObject 的 IEnumerable 的切换。如果愿意,您还可以定义一个单独的 class 并使用它代替 JObject。

希望对您有所帮助...祝您好运!

JshL 建议的另一个替代方法是,您可以将 Web api 更改为 return IEnumerable of json serialized DynamicTableEntities。在客户端将 json 反序列化回 DynamicTableEntity 并处理将其转换为您的具体 class 如果您想要或只是将其作为 DynamicTableEntity 使用。

您可以查看我在此处实现的 DynamicTableEntity json 序列化程序: https://www.nuget.org/packages/DynamicTableEntityJsonSerializer/