2. WCF 消息操作

原文:http://www.rainsts.net/article.asp?id=429

WCF 一切都围绕Message进行的,下面我们来看看Message的样子。

服务端:

 

<ServiceContract()> _
Public Interface IService1

    
<OperationContract()> _
    
Function GetData(ByVal value As IntegerAs String
End Interface

Public Class Service1
    
Implements IService1

    
Public Function GetData(ByVal value As IntegerAs String Implements IService1.GetData

        
'打印消息
        Dim msg = OperationContext.Current.RequestContext.RequestMessage
        Console.WriteLine(msg.ToString)

        
Return String.Format("You entered: {0}", value)
    
End Function


End Class

 

 

客户端:
   Dim host As System.ServiceModel.ServiceHost
        host 
= New System.ServiceModel.ServiceHost(GetType(WcfServiceLibrary1.Service1))
        host.AddServiceEndpoint(
GetType(WcfServiceLibrary1.IService1), New System.ServiceModel.BasicHttpBinding, "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex")
        host.Open()
        Console.WriteLine(host.State.ToString)

        
Dim factory = New System.ServiceModel.ChannelFactory(Of WcfServiceLibrary1.IService1)(New ServiceModel.BasicHttpBinding, "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex")
        
Dim o = factory.CreateChannel

        Console.WriteLine(o.GetData(
10))



        Console.ReadKey()

 

输出消息是:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  
<s:Header>
    
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex</To>
    
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService1/GetData</Action>
  
</s:Header>
  
<s:Body>
    
<GetData xmlns="http://tempuri.org/">
      
<value>10</value>
    
</GetData>
  
</s:Body>
</s:Envelope>

 

事实上我们可以直接基于Message layer 进行编程,利用operation.action捕获特定的action消息,注意action的定义是区分大小写的
服务端:

 

<ServiceContract()> _
Public Interface IService1

    
<OperationContract(action:="add", ReplyAction:="add")> _
    
Function GetData(ByVal msg As System.ServiceModel.Channels.Message) As System.ServiceModel.Channels.Message
End Interface

Public Class Service1
    
Implements IService1

    
Public Function GetData(ByVal msg As System.ServiceModel.Channels.Message) As System.ServiceModel.Channels.Message Implements IService1.GetData

        
Dim data = msg.GetBody(Of CompositeType)()

        Console.WriteLine(data.StringValue)


        
Return System.ServiceModel.Channels.Message.CreateMessage(System.ServiceModel.Channels.MessageVersion.Soap11, "add"New CompositeType("zqonline"))
    
End Function


End Class



<DataContract()> _
Public Class CompositeType

    
Private stringValueField As String = String.Empty

    
Public Sub New()

    
End Sub

    
Public Sub New(ByVal str As String)
        
Me.StringValue = str
    
End Sub


    
<DataMember()> _
    
Public Property StringValue() As String
        
Get
            
Return Me.stringValueField
        
End Get
        
Set(ByVal value As String)
            
Me.stringValueField = value
        
End Set
    
End Property

End Class

 

 

客户端:

    
Sub Main()
        
Dim host As System.ServiceModel.ServiceHost
        host 
= New System.ServiceModel.ServiceHost(GetType(WcfServiceLibrary1.Service1))
        host.AddServiceEndpoint(
GetType(WcfServiceLibrary1.IService1), New System.ServiceModel.BasicHttpBinding, "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex")
        host.Open()
        Console.WriteLine(host.State.ToString)

        
Dim factory = New System.ServiceModel.ChannelFactory(Of System.ServiceModel.Channels.IRequestChannel)(New ServiceModel.BasicHttpBinding, "http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex")
        
Dim o = factory.CreateChannel

        
Dim value = New WcfServiceLibrary1.CompositeType("lily")
        
Dim msg = System.ServiceModel.Channels.Message.CreateMessage(System.ServiceModel.Channels.MessageVersion.Soap11, "add", value)

        
Dim r As System.ServiceModel.Channels.Message = o.Request(msg)
        Console.WriteLine(r)
        Debug.WriteLine(r)

        Console.ReadKey()
    
End Sub

 

输出内容是:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  
<s:Header />
  
<s:Body>
    
<CompositeType xmlns="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      
<StringValue>zqonline</StringValue>
    
</CompositeType>
  
</s:Body>
</s:Envelope>

 

正如上面所看到的,所有的调用都被转换成消息后发送。这也符合 SOA 的规范,完全隔离,清晰的边界。(调用 "m.GetBody<Data>()" 后,会导致 Message.State 变更,再次访问会出错,有关详细信息请参考 MSDN 文档。)

这个,我也不能是太理解,只是先照着做个例子,先熟中间的类库了。

 

我们还可以使用 MessageContractAttribute / MessageHeaderAttribute 来控制消息格式,这比 DataContractAttribute 要更加灵活。我们可以设置消息标头、消息体,包括是否对其中某些进行签名和加密处理。

不过这个我没有实现

 


<MessageContract()> _
Public Class CompositeType


    
Private boolValueField As Boolean = True
    
Private stringValueField As String = String.Empty

    
<MessageHeader()> _
    
Public int As Integer = 111

    
Public Sub New()

    
End Sub

    
Public Sub New(ByVal str As String)
        
Me.StringValue = str
    
End Sub

    
<MessageHeader()> _
    
Public Property BoolValue() As Boolean
        
Get
            
Return Me.boolValueField
        
End Get
        
Set(ByVal value As Boolean)
            
Me.boolValueField = value
        
End Set
    
End Property

    
<MessageBodyMember()> _
    
Public Property StringValue() As String
        
Get
            
Return Me.stringValueField
        
End Get
        
Set(ByVal value As String)
            
Me.stringValueField = value
        
End Set
    
End Property

End Class

生成的消息是:

 


<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  
<s:Header />
  
<s:Body>
    
<CompositeType xmlns="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
      
<BoolValue>true</BoolValue>
      
<StringValue>zqonline</StringValue>
      
<int>111</int>
    
</CompositeType>
  
</s:Body>
</s:Envelope>

并没有放在Header头。测试后发现,不能针对Message Layer层进行操作,才可以。

 


<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  
<s:Header>
    
<h:BoolValue xmlns:h="http://tempuri.org/">true</h:BoolValue>
    
<h:int xmlns:h="http://tempuri.org/">111</h:int>
    
<To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:8731/Design_Time_Addresses/WcfServiceLibrary1/Service1/mex</To>
    
<Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">add</Action>
  
</s:Header>
  
<s:Body>
    
<CompositeType xmlns="http://tempuri.org/">
      
<StringValue>lily</StringValue>
    
</CompositeType>
  
</s:Body>
</s:Envelope>

 

 

int,BoolValue都放在了Header中了。

 

好了,先到这里,虽然照着把代码实现了,但是其中还是不能理解。

 

 

posted on 2009-11-13 11:50  zqonline  阅读(285)  评论(0编辑  收藏  举报

导航