Reflection

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

在本次实验中,你将会了解到Data Contract以及有继承关系的Data Contract。打开Data Contract文件夹下的Know Type.sln解决方案。解决方案中包含了一个简单的contract管理的服务端和客户端。在Host项目中的ContractManager文件包含了以下一些服务:

[DataContract]
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中:

class CustomerManager : IContactManager
{
   
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的后台代码简单的调用了它们:

void OnAddContact(object sender, EventArgs e)
{
    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中加入如下的定义:

[DataContract]
class
 Customer : Contact
{
    
int
 m_OrderNumber;
    [DataMember]
    
public int
 OrderNumber
    
{
        
get

        
{
            
return
 m_OrderNumber;
        }

        
set
        
{
            m_OrderNumber 
=
 value;
        }

    }

}

将客户端代码进行修改,现在我们将使用Customer类:

void OnAddContact(object sender, EventArgs e)
{
    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文件中:

[DataContract]
class
 Customer : Contact
{
    
int
 m_OrderNumber;
    [DataMember]
    
public int
 OrderNumber
    
{
        
get

        
{
            
return
 m_OrderNumber;
        }

        
set
        
{
            m_OrderNumber 
=
 value;
        }

    }

}

为Contract类加上KnowType的属性:

[DataContract]
[KnownType(
typeof
(Customer))]
class
 Contact
{……}

同样,在客户端也需要做同样的动作。
编译并运行程序,这个时候应该都正确了。除了客户端的grid中并没有反应出order number来。因为它知道的只是Contract。我们可以在程序中显式的将Contract转型为Customer:

void OnGetContacts(object sender, EventArgs e)
{
    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();
}


现在可以运行程序看看结果了。

posted on 2008-04-11 09:57  Reflection  阅读(775)  评论(1编辑  收藏  举报