Deserialize <ArrayOf> in XML for list <>
I have a problem deserializing the result from my WCF web service. The method returns a List<RecipeEntity> , which is serialized in XML, as shown below. When I try to deserialize, I just get an exception, as shown below. It seems I can't deserialize <ArrayOfRecipe> to List<RecipeEntity> . Note that RecipeEntity displayed by the name of the Recipe contract.
After the search, I see that many offer the XmlArray and XmlElement attributes, but as far as I can tell, they are not applied here using the GetRecipes() method. I only saw that they were used in the fields of serialized classes.
I know that I could wrap List<RecipeEntity> in the RecipeList class and return it instead, but I would prefer to deserialize directly to List <> for any given type.
An exception:
System.InvalidOperationException was caught Message=There is an error in XML document (1, 2). StackTrace: at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, Object events) at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle) at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader) at GroceriesAppSL.Pages.Home.GetRecipesCallback(RestResponse response) InnerException: System.InvalidOperationException Message=<ArrayOfRecipe xmlns='Groceries.Entities'> was not expected. StackTrace: at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderList1.Read5_Recipe() InnerException: Data Contract:
[DataContract(Name = "Recipe", Namespace = "Groceries.Entities")] public class RecipeEntity { [DataMember] public int Id; [DataMember] public string Name; [DataMember] public string Description; } Implementation:
[ServiceContract] public interface IMyService { [OperationContract] [WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "Recipes/{username}")] List<RecipeEntity> GetRecipes(string username); } public class MyService : IMyService { public List<RecipeEntity> GetRecipes(string username) { return _recipeDB.Recipes.Select(ToEntity).ToList(); } } An example XML result, for illustration purposes only.
<ArrayOfRecipe xmlns="Groceries.Entities" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Recipe> <Id>139</Id> <Name>ExampleRecipe</Name> <Description>5 L milk;4 eggs</Description> </Recipe> <Recipe>...</Recipe> <Recipe>...</Recipe> <Recipe>...</Recipe> ... </ArrayOfRecipe> Deserialization Code:
using (var xmlReader = XmlReader.Create(new StringReader(response.Content))) { var xs = new System.Xml.Serialization.XmlSerializer(typeof(List<RecipeEntity>)); var recipes = (List<RecipeEntity>)xs.Deserialize(xmlReader); } You are using DataContractSerializer for serialization and XmlSerializer for deserialization. These two do not use the same approach. You must either use the DataContractSerializer in your deserialization method, or you must mark your operation or service with the XmlSerializerFormat attribute (in this case, WCF will use the XmlSerializer instead of the DataContractSerializer ). The DataContract and DataMember are for the DataContractSerializer only. XmlSerializer uses its own attributes defined in the System.Xml.Serialization namespace.
You just get a response stream first and then use the DataContractSerealizer to defuse it.
Override Code:
using(Stream answer=webResponse.GetResponseStream()) { DataContractSerializer xmlSer = new DataContractSerializer(typeof(RecipeEntity[])); var RecipeList = (RecipeEntity[])xmlSer.ReadObject(answer); }