Reputation: 1297
When returning a List of TableEntities using WebAPI, I'm getting a 500 Internal Server Error. When I look at the output in Visual Studio, I see that i'm getting these 'System.Runtime.Serialization.SerializationException'.
Here's my code in the Controller
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;
}
This is my code for the Custom 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; }
}
In the Controller, If I manually create the List of Entities, I get NO Serialization issues.
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;
}
Any ideas why?
Here are the exceptions listed in the output window.
Exception thrown: 'System.Runtime.Serialization.SerializationException' in mscorlib.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in mscorlib.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in Newtonsoft.Json.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in Newtonsoft.Json.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in Newtonsoft.Json.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in Newtonsoft.Json.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in Newtonsoft.Json.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in Newtonsoft.Json.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in mscorlib.dll Exception thrown: 'System.Runtime.Serialization.SerializationException' in mscorlib.dll
Upvotes: 0
Views: 450
Reputation: 3384
An additional alternative to JshL's suggestions, you could change your web api to return IEnumerable of json serialized DynamicTableEntities. And on the client side deserialize the json back to DynamicTableEntity and handle transforming that into your concrete class if you wanted to or just consume it as DynamicTableEntity.
You can have a look at DynamicTableEntity json serializer I implemented here: https://www.nuget.org/packages/DynamicTableEntityJsonSerializer/
Upvotes: 1
Reputation: 1716
Types that inherit from TableEntity cannot be serialized, due to internal delegate members, etc. See below:
You have a few options:
inherit from ITableEntity interface instead of TableEntity... you'll have to implement the core TableEntity behavior yourself (not too bad, generally) and this gives you the opportunity to implement serialization if you want, too
change your Web API to output a separate type that contains only the entity properties you want to return, and implement a transform function for your entity type, something like this:
In the ContactEntity class:
public JObject ToJson()
{
var jo = new JObject();
jo["PartitionKey"] = PartitionKey;
jo["RowKey"] = RowKey;
jo["Email"] = Email;
// etc
return jo;
}
In your controller:
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());
}
Note the switch from returning IEnumerable of ContactEntity to IEnumerable of JObject. You could also define a separate class and use that instead of JObject, if you prefer.
Hope that helps... good luck!
Upvotes: 1