7

I have an abstract class called 'Template' defined as:

[DataContract]
public abstract class Template
{
    [DataMember]
    public virtual int? Id { get; set; }
    [DataMember]
    public virtual string Title { get; set; }
    [DataMember]
    public virtual byte[] TemplateDoc { get; set; }
    [DataMember]
    public virtual bool IsSystemTemplate { get; set; }        
}

Two derived classes: UserTemplate and SystemTemplate implements above abstract class, which are defined as:

public class UserTemplate : Template
{
    [DataMember]
    public virtual Int32? OfficeId { get; set; }

    [DataMember]
    public virtual Int32? UserId { get; set; }

    protected UserTemplate() { }

    public UserTemplate(string title, byte[] templateDoc, string templateDocName, TemplateType templateType, int officeId, int? userId)
    {
        this.Title = title;
        this.TemplateDoc = templateDoc;
        this.IsSystemTemplate = false;
        this.OfficeId = officeId;
        this.UserId = userId;
    }
}

public class SystemTemplate : Template
{
    [DataMember]
    public virtual Int32? MultiListGroupId { get; set; }

    protected SystemTemplate() { }

    public SystemTemplate(string title, byte[] templateDoc, string templateDocName, TemplateType templateType, int multiListGroupId)
    {
        this.Title = title;
        this.TemplateDoc = templateDoc;
        this.IsSystemTemplate = true;
        this.MultiListGroupId = multiListGroupId;
    }
}

Now, when I try to call following service method:

List<Template> GetTemplatesByTemplateType(int officeId, int? userId, TemplateType templateType)

I get this error:

System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host

Is it because of the reason that I am trying to return an abstract class?
It runs fine if I try to call this method using unit test.

abatishchev
  • 98,240
  • 88
  • 296
  • 433
inutan
  • 10,558
  • 27
  • 84
  • 126

4 Answers4

4

Yes, the problem is your abstract base class which needs to be decorated with the KnownType and XmlInclude attributes. See here: Link

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
grenade
  • 31,451
  • 23
  • 97
  • 126
  • Dead link, but this other S/O question gives the same solution https://stackoverflow.com/questions/3101756/using-wcf-with-abstract-classes – tgolisch Jun 21 '22 at 20:29
3

In addition to grenade's answer about making those descendant classes known to WCF usign the KnownType (or ServiceKnownType) attribute, you'll also have to decorate the descendant classes with a [DataContract] attribute themselves.

[DataContract]
public class UserTemplate : Template
{
    ......
}

[DataContract]
public class SystemTemplate : Template
{
    ......
}

These attributes are almost never inherited from parent to child in WCF - you need to be very explicit and clear about your intent at every level.

Check this blog post All About KnownTypes for more information on the KnownTypes and ServiceKnownTypes attributes.

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
0

Add this datacontractserializer line in your web config file

<system.serviceModel>
<behaviors>
  <serviceBehaviors>
    <behavior >
        **<dataContractSerializer maxItemsInObjectGraph="2147483646"/>**
     </behavior >
 </serviceBehaviors>
</behaviors>
</system.serviceModel>
animuson
  • 53,861
  • 28
  • 137
  • 147
Chitta
  • 185
  • 2
  • 15
0

I got this error once, and it was quite confusing. My problem was that the Service Reference was for some reason not up to date, so updating the Service Reference helped.

David d C e Freitas
  • 7,481
  • 4
  • 58
  • 67