1

I am getting the following exception when I call the WCF Service from ASP.NET website. How can we overcome it?

Note: By applying break point in service project, I have verified that the service is returning two valid objects.

Note: In service, I am returing List of IBankAccount. [OperationContract] List<IBankAccount> GetDataUsingDataContract(int userId); The IBankAccount is an interface.

The exception says "The underlying connection was closed: The connection was closed unexpectedly". Detailed stack trace is available in the following picture.

enter image description here

//Website

using System;
using ServiceReference1;
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

    Service1Client client = new Service1Client();

    string result = client.GetData(1);
    Response.Write(result);


    client.GetDataUsingDataContract(1);
    int d = 0;

}
}

//Service Interface

using System.Collections.Generic;
using System.ServiceModel;
using DTOProject;
namespace MyServiceApp
{
[ServiceContract]
public interface IService1
{
    [OperationContract]
    string GetData(int value);

    [OperationContract]
    List<IBankAccount> GetDataUsingDataContract(int userId);

}

}

//DTO

using System.Runtime.Serialization;
namespace DTOProject
{
public interface IBankAccount
{
     int Duration { get; set; }
     int AmountDeposited { get; set; }
}
}

using System.Runtime.Serialization;
namespace DTOProject
{
[DataContract]
public class FixedAccount : IBankAccount
{
    [DataMember]
    public int Duration { get; set; }

    [DataMember]
    public int AmountDeposited { get; set; }
}
}

using System.Runtime.Serialization;
namespace DTOProject
{
[DataContract]
public class SavingsAccount : IBankAccount
{
    [DataMember]
    public int Duration { get; set; }

    [DataMember]
    public int AmountDeposited { get; set; }
}
}

//Service Implementation

using System.Collections.Generic;
using DTOProject;
using BusinessLayer;

namespace MyServiceApp
{
public class Service1 : IService1
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }
    public List<IBankAccount> GetDataUsingDataContract(int userId)
    {
        BusinessLayer.AccountManager accManager = new AccountManager();
        List<IBankAccount> accounts = accManager.GetAllAccountsForUser(userId);
        return accounts;
    }

}
}

//Business Layer

 using System.Collections.Generic;
 using DTOProject;
 using DataAccessLayer;
 namespace BusinessLayer
{
public class AccountManager
{
    public List<IBankAccount> GetAllAccountsForUser(int userID)
    {
        DataAccessLayer.AccounutManagerDAL accountManager = new AccounutManagerDAL();
        List<IBankAccount> accountList = accountManager.GetAllAccountsForUser(userID);
        return accountList;
    }

}
}

//Data Access Layer

using System;
using System.Collections.Generic;
using DTOProject;
namespace DataAccessLayer
{

 public class DatabaseRecordSimulation
 {
    public string AccountType { get; set; }
    public int Duration { get; set; }
    public int DepositedAmount { get; set; }
 }

public class AccounutManagerDAL
{

    List<DatabaseRecordSimulation> dbRecords = new List<DatabaseRecordSimulation>()
    {
        new DatabaseRecordSimulation{AccountType="Savings",Duration=6,DepositedAmount=50000},
        new DatabaseRecordSimulation{AccountType="Fixed",Duration=6,DepositedAmount=50000}
    };

    public List<IBankAccount> GetAllAccountsForUser(int userID)
    {

        List<IBankAccount> accountList = new List<IBankAccount>();
        foreach (DatabaseRecordSimulation dbRecrod in dbRecords)
        {
            IBankAccount acc = AccountFactory.GetAccount(dbRecrod);
            accountList.Add(acc);
        }
        return accountList;
    }

}

public static class AccountFactory
{
    public static IBankAccount GetAccount(DatabaseRecordSimulation dbRecord)
    {
        IBankAccount theAccount = null;
        if ( String.Equals(dbRecord.AccountType, "Fixed"))
        {
            theAccount = new FixedAccount();
        }
        if (String.Equals(dbRecord.AccountType, "Savings"))
        {
            theAccount = new SavingsAccount();
        }
        return theAccount;

    }
}
}

READING: 1. WCF Object Design - OOP vs SOA

Community
  • 1
  • 1
LCJ
  • 22,196
  • 67
  • 260
  • 418

1 Answers1

4

As per this post: http://social.msdn.microsoft.com/Forums/eu/wcf/thread/31102bd8-0a1a-44f8-b183-62926390b3c3 You cannot return an interface - you must return a class. However, you can create an abstract base type - BankAccount and apply the KnownType attribute to it. For example:

[DataContract]
[KnowType(typeof(FixedAccount))]
[KnowType(typeof(SavingsAccount))]
abstract class BankAccount { ... }

[DataContract]
class FixedAccount : BankAccount { ... }

[DataContract]
class SavingsAccount : BankAccount { ... }

The KnownType attribute let's WCF know that some other type, not explicitly referenced in the service contract will be a part of the contract.

Coder
  • 376
  • 2
  • 4
  • On the face of it, this doesn't appear to be anything to do with the problem HOWEVER looking at the stack trace, it does appear to me that the outgoing exception is a red herring and something weird is happening in the serialization mechanism. Did you take this into account with your answer? In which case, it makes sense and gets an upvote - but I'm reserving judgement on the off chance that you're shooting randomly at an answer. – Tom W Feb 27 '12 at 14:09
  • @TomW You get such exception typically when serialization fails. I've got similar exception many times. – Coder Feb 27 '12 at 18:10
  • 1
    I'd imagined as much, so credit where credit is due. This answer is worth noting because beginners might well assume that it's a connection problem and miss the underlying fault. – Tom W Feb 27 '12 at 18:12
  • 1
    @TomW You get such exception typically when serialization fails. I've got similar exception many times. The usual problem I had was to forget apply "EnumMember" on an enum or when I apply "DataMember" instead of "EnumMember". In the case of this question serialization fails because, as the Microsoft forum suggests, you cannot use an interface as a data type in a contract. You must use solid types. I'm not completely sure if the web service specification does not support this at all. However, it seems that WCF does not support it. – Coder Feb 27 '12 at 18:17