在本次实验中,你将会了解到Data Contract以及有继承关系的Data Contract。打开Data Contract文件夹下的Know Type.sln解决方案。解决方案中包含了一个简单的contract管理的服务端和客户端。在Host项目中的ContractManager文件包含了以下一些服务:
class Contact
{
string m_FirstName;
string m_LastName;
[DataMember]
public string FirstName
{
get
{
return m_FirstName;
}
set
{
m_FirstName = value;
}
}
[DataMember]
public string LastName
{
get
{
return m_LastName;
}
set
{
m_LastName = value;
}
}
}
[ServiceContract]
interface IContactManager
{
[OperationContract]
void AddContact(Contact contact);
[OperationContract]
Contact[] GetContacts();
}
服务类将contracts储存在一个泛型的List中:
{
static List<Contact> m_Contacts = new List<Contact>();
public void AddContact(Contact contact)
{
m_Contacts.Add(contact);
}
public Contact[] GetContacts()
{
return m_Contacts.ToArray();
}
}
编译并加载应用程序,client端提供了一个简单的UI来测试服务:
点击Add Contract按钮一次或者两次,再点击Get Contracts按钮数据会返回到客户端。
接下来,我们来看看client端的代码。Proxy.cs文件包含了service contract和data contract的定义。Winform的后台代码简单的调用了它们:
{
Contact contact = new Contact();
contact.FirstName = "Juval";
contact.LastName = "Lowy";
ContactManagerClient proxy = new ContactManagerClient();
proxy.AddContact(contact);
proxy.Close();
}
void OnGetContacts(object sender, EventArgs e)
{
ContactManagerClient proxy = new ContactManagerClient();
Contact[] contacts = proxy.GetContacts();
m_ContactsGrid.DataSource = contacts;
proxy.Close();
}
为Data Contract添加子类
假如客户端现在想使用服务来管理客户(Customer)的资料。客户是从Contract继承而来,并新加入了一个订单号的属性。在Proxy.cs中加入如下的定义:
class Customer : Contact
{
int m_OrderNumber;
[DataMember]
public int OrderNumber
{
get
{
return m_OrderNumber;
}
set
{
m_OrderNumber = value;
}
}
}
将客户端代码进行修改,现在我们将使用Customer类:
{
Customer customer = new Customer();
customer.FirstName = "Juval";
customer.LastName = "Lowy";
customer.OrderNumber = 123;
ContactManagerClient proxy = new ContactManagerClient();
proxy.AddContract(customer);
proxy.Close();
}
编译解决方案,没有发现问题。因为Customer类从Contract继承而来,所以service端的代码不需要做什么改变。
加载应用程序,我们却得到了如下错误:
原因是即使我们的改变都可以被.NET和C#接受,可是WCF却不可以。因为服务端不知道如何反序列化Customer这个类型,它不知道有这个类型。
加入Know Type
你需要显式的告诉WCF它所需要知道的全部类型。把Customer的定义加入到ContractManager.cs文件中:
class Customer : Contact
{
int m_OrderNumber;
[DataMember]
public int OrderNumber
{
get
{
return m_OrderNumber;
}
set
{
m_OrderNumber = value;
}
}
}
为Contract类加上KnowType的属性:
[KnownType(typeof(Customer))]
class Contact
{……}
同样,在客户端也需要做同样的动作。
编译并运行程序,这个时候应该都正确了。除了客户端的grid中并没有反应出order number来。因为它知道的只是Contract。我们可以在程序中显式的将Contract转型为Customer:
{
ContactManagerClient proxy = new ContactManagerClient();
Contact[] contacts = proxy.GetContacts();
Customer[] customers = Array.ConvertAll(contacts, delegate(Contact contact)
{
return contact as Customer;
});
m_ContactsGrid.DataSource = customers;
proxy.Close();
}
现在可以运行程序看看结果了。