【问题标题】:WCF Exception when returning list of interface objects返回接口对象列表时出现 WCF 异常
【发布时间】:2012-02-27 08:24:01
【问题描述】:

当我从 ASP.NET 网站调用 WCF 服务时出现以下异常。我们怎样才能克服它?

注意:通过在服务项目中应用断点,我已验证服务返回两个有效对象。

注意:在服务中,我正在返回 IBankAccount 的列表。 [OperationContract] List<IBankAccount> GetDataUsingDataContract(int userId); IBankAccount 是一个接口。

异常显示“底层连接已关闭:连接已意外关闭”。详细的堆栈跟踪如下图所示。

//网站

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;

}
}

//服务接口

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; }
}
}

//服务实现

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;
    }

}
}

//业务层

 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;
    }

}
}

//数据访问层

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;

    }
}
}

阅读: 1.WCF Object Design - OOP vs SOA

【问题讨论】:

    标签: c# .net wcf datacontract servicecontract


    【解决方案1】:

    根据这篇文章: http://social.msdn.microsoft.com/Forums/eu/wcf/thread/31102bd8-0a1a-44f8-b183-62926390b3c3 你不能返回一个接口——你必须返回一个类。但是,您可以创建一个抽象基类型 - BankAccount 并将 KnownType 属性应用于它。例如:

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

    KnownType 属性让 WCF 知道服务合同中未明确引用的其他类型将成为合同的一部分。

    【讨论】:

    • 从表面上看,这似乎与问题无关但是查看堆栈跟踪,在我看来,传出的异常是一个红鲱鱼和一些奇怪的东西发生在序列化机制中。您的回答是否考虑到了这一点?在这种情况下,这是有道理的并且会得到支持 - 但我保留判断您是否随机回答答案的可能性。
    • @TomW 通常在序列化失败时会出现此类异常。我多次遇到类似的异常。
    • 我想像的一样多,所以在应得的情况下给予信任。这个答案值得注意,因为初学者很可能会认为这是一个连接问题而忽略了潜在的故障。
    • @TomW 通常在序列化失败时会出现此类异常。我多次遇到类似的异常。我遇到的常见问题是忘记在枚举上应用“EnumMember”,或者当我应用“DataMember”而不是“EnumMember”时。在这个问题的情况下,序列化失败是因为,正如 Microsoft 论坛所建议的那样,您不能将接口用作合同中的数据类型。您必须使用实体类型。我不完全确定 Web 服务规范是否根本不支持这一点。但是,WCF 好像不支持。
    猜你喜欢
    • 1970-01-01
    • 2013-03-17
    • 1970-01-01
    • 2011-08-17
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多