Stop WCF Deserializing Empty ICollection into Zero Capacity Array

强颜欢笑 提交于 2019-12-04 03:41:05

问题


I'm having a problem using WCF and Entity Framework 4.1 POCO objects (generated using T4 templates). My basic problem is that when sending a POCO object from my client to the service, WCF is deserializing a member variable of type ICollection as a fixed size array.

On the client side I can tell visual studio to use IList instead of T[] - but I cant see any option like this on the server end.

This causes no end of problems with several things, such as persisting these objects back to the database.

Is there any way to tell WCF what object type to deserialize ICollection (or any array) as?


回答1:


I'm surprised that more folks haven't run into this issue, as it hits you smack in the face when you try to use the EF T4-generated POCO objects over WCF. Specifically, the error I was getting said something like:

Exception: "Unable to set field/property Orders on entity type Datalayer.Customers. See InnerException for details."

InnerException: "An item cannot be added to a fixed size Array of type 'Datalayer.Order[]'."

At any rate, the only solution I've been able to come up with is the one that you mention, namely, modifying the T4 templates to use HashSet instead of ICollection. Doesn't strike me as the cleanest, but it seems to work.




回答2:


I'm using Entity Framework 6, and I was able to solve this issue by making the following changes in my T4 template.

I changed the following line where it creates the navigation properties to use a List instead of a collection from

navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("ICollection<" + endType + ">") : endType,

to

navProp.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many ? ("List<" + endType + ">") : endType,

Then I changed the code that sets the navigation property in the constructor to convert the default hashset to a list by adding a call to .ToList(). This line

this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>();

was changed to

this.<#=code.Escape(navigationProperty)#> = new HashSet<<#=typeMapper.GetTypeName(navigationProperty.ToEndMember.GetEntityType())#>>().ToList();

The HashSet<>.ToList() method is an extension, so in order to make that extension method available, I added a using System.Linq statement by modifying the UsingDirectives method:

    public string UsingDirectives(bool inHeader, bool includeCollections = true)
{
    return inHeader == string.IsNullOrEmpty(_code.VsNamespaceSuggestion())
        ? string.Format(
            CultureInfo.InvariantCulture,
            "{0}using System;{1}" + Environment.NewLine +
            "{0}using System.Linq;" + 
            "{2}",
            inHeader ? Environment.NewLine : "",
            includeCollections ? (Environment.NewLine + "using System.Collections.Generic;") : "",
            inHeader ? "" : Environment.NewLine,
            Environment.NewLine)
        : "";
}


来源:https://stackoverflow.com/questions/10244910/stop-wcf-deserializing-empty-icollection-into-zero-capacity-array

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!