我是WCF的新手。我能够使用NetTcpBindings构建一个自托管的WCF服务和4个连接到它的.NET应用程序。现在我需要一个用Python2.7脚本编写的客户端连接到这个提供双工通信的WCF服务。
据我搜索,应使用 WsDualHttpBinding 与 SOAP 1.2 。
这是我的服务界面
namespace GPH_QuickMessageServiceLib
{
/// <summary>
/// GPH Quick Message Service Operations
/// </summary>
[ServiceContract(
Name = "GPH_QuickMessageService",
Namespace = "GPH_QuickMessageServiceLib",
SessionMode = SessionMode.Required,
CallbackContract = typeof(IMessageServiceCallback))]
public interface IMessageServiceInbound
{
[OperationContract]
[WebInvoke]
int JoinTheConversation(string userName);
[OperationContract]
[WebInvoke]
int LeaveTheConversation(string userName);
}
public interface IMessageServiceCallback
{
[OperationContract(IsOneWay = true)]
[WebInvoke]
void NotifyUserJoinedTheConversation(string userName, List<string> SubscriberList);
[OperationContract(IsOneWay = true)]
[WebInvoke]
void NotifyUserLeftTheConversation(string userName, List<string> SubscriberList);
}
}
以下是我的服务行为
namespace GPH_QuickMessageServiceLib
{
/// <summary>
/// GPH Quick Message Service behaviour
/// </summary>
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Single,
InstanceContextMode = InstanceContextMode.PerCall)]
public class GPH_QuickMessageService : IMessageServiceInbound
{
private static List<IMessageServiceCallback> _callbackList = new List<IMessageServiceCallback>();
// number of current users - 0 to begin with
private static int _registeredUsers = 0;
private static List<string> SubscriberList = new List<string>();
private static Dictionary<string, IMessageServiceCallback> NotifyList = new Dictionary<string, IMessageServiceCallback>(); // Default Constructor
// Default Constructor
public GPH_QuickMessageService() { }
public int JoinTheConversation(string userName)
{
// Subscribe the user to the conversation
IMessageServiceCallback registeredUser = OperationContext.Current.GetCallbackChannel<IMessageServiceCallback>();
if (!_callbackList.Contains(registeredUser))
{
_callbackList.Add(registeredUser);
SubscriberList.Add(userName);//Note the callback list is just a list of channels.
NotifyList.Add(userName, registeredUser);//Bind the username to the callback channel ID
}
_callbackList.ForEach(
delegate (IMessageServiceCallback callback)
{
callback.NotifyUserJoinedTheConversation(userName, SubscriberList);
_registeredUsers++;
});
return _registeredUsers;
}
public int LeaveTheConversation(string userName)
{
// Unsubscribe the user from the conversation.
IMessageServiceCallback registeredUser = OperationContext.Current.GetCallbackChannel<IMessageServiceCallback>();
if (_callbackList.Contains(registeredUser))
{
_callbackList.Remove(registeredUser);
NotifyList.Remove(userName);
SubscriberList.Remove(userName);
_registeredUsers--;
}
// Notify everyone that user has arrived.
// Use an anonymous delegate and generics to do our dirty work.
_callbackList.ForEach(
delegate (IMessageServiceCallback callback)
{
callback.NotifyUserLeftTheConversation(userName, SubscriberList);
});
return _registeredUsers;
}
}
}
以下是服务主机应用
中的 App.config<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
<system.serviceModel>
<services>
<service name="GPH_QuickMessageServiceLib.GPH_QuickMessageService"
behaviorConfiguration = "QuickMessageServiceMEXBehavior">
<endpoint address ="soap"
binding="wsDualHttpBinding"
contract="GPH_QuickMessageServiceLib.IMessageServiceInbound" />
<endpoint address ="service"
binding="netTcpBinding"
contract="GPH_QuickMessageServiceLib.IMessageServiceInbound" />
<!-- Enable the MEX endpoint -->
<endpoint address="mex"
binding="mexTcpBinding"
contract="IMetadataExchange" />
<!-- Need to add this so MEX knows the address of our service -->
<host>
<baseAddresses>
<add baseAddress="http://localhost:2709/GPH_QuickMessageService/soap"/>
<add baseAddress="net.tcp://localhost:8868/GPH_QuickMessageService"/>
</baseAddresses>
</host>
</service>
</services>
<!-- A behavior definition for MEX -->
<behaviors>
<serviceBehaviors>
<behavior name="QuickMessageServiceMEXBehavior" >
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
以下是我在Python2.7脚本中的内容(我使用suds-jurko 0.6和hack将SOAP 1.2用作.NET wsDualHttpBinding only supports SOAP 1.2)
from suds.client import Client
from suds.bindings import binding
import logging
# Just for debugging purposes.
logging.basicConfig(level=logging.INFO)
logging.getLogger('suds.client').setLevel(logging.DEBUG)
# Telnic's SOAP server expects a SOAP 1.2 envelope, not a SOAP 1.1 envelope
# and will complain if this hack isn't done.
binding.envns = ('SOAP-ENV', 'http://www.w3.org/2003/05/soap-envelope')
client = Client('http://localhost:2709/GPH_QuickMessageService/soap?wsdl',
headers={'Content-Type': 'application/soap+xml'})
# This will now work just fine.
result = client.service.JoinTheConversation('RIDE')
print client
print 'result = %s' % result
正如我猜的那样,我的python客户端已绑定到服务器并获取可用操作列表,但无法从这些操作中获取结果。它总是返回无
C:\Python27\python.exe C:/Users/sev_user/PycharmProjects/WcfInteration/venv/Scripts/suds_client.py
DEBUG:suds.client:sending to (http://localhost:2709/GPH_QuickMessageService/soap/soap)
message:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns0="GPH_QuickMessageServiceLib" xmlns:ns1="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope">
<SOAP-ENV:Header/>
<ns1:Body>
<ns0:JoinTheConversation>
<ns0:userName>RIDE</ns0:userName>
</ns0:JoinTheConversation>
</ns1:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:headers = {'SOAPAction': '"GPH_QuickMessageServiceLib/GPH_QuickMessageService/JoinTheConversation"', 'Content-Type': 'application/soap+xml'}
Suds ( https://fedorahosted.org/suds/ ) version: 0.6
Service ( GPH_QuickMessageService ) tns="http://tempuri.org/"
Prefixes (3)
ns0 = "GPH_QuickMessageServiceLib"
ns1 = "http://schemas.microsoft.com/2003/10/Serialization/"
ns2 = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"
Ports (2):
(WSDualHttpBinding_GPH_QuickMessageService)
Methods (7):
JoinTheConversation(xs:string userName)
LeaveTheConversation(xs:string userName)
NotifyUserJoinedTheConversation()
NotifyUserLeftTheConversation()
NotifyUserOfMessage()
ReceiveMessage(xs:string userName, ns2:ArrayOfstring addressList, xs:string userMessage)
sum(xs:int a, xs:int b)
Types (4):
ns2:ArrayOfstring
ns1:char
ns1:duration
ns1:guid
(NetTcpBinding_GPH_QuickMessageService)
Methods (7):
JoinTheConversation(xs:string userName)
LeaveTheConversation(xs:string userName)
NotifyUserJoinedTheConversation()
NotifyUserLeftTheConversation()
NotifyUserOfMessage()
ReceiveMessage(xs:string userName, ns2:ArrayOfstring addressList, xs:string userMessage)
sum(xs:int a, xs:int b)
Types (4):
ns2:ArrayOfstring
ns1:char
ns1:duration
ns1:guid
result = None
DEBUG:suds.client:HTTP succeeded:
Process finished with exit code 0
我尝试过除了肥皂水之外的其他几种方式,例如ZSI,zeep,但始终将结果显示为'无'或' 0 ”。我在这些SOAP客户端进程上附加了记录器,并始终获得“ HTTP成功”或“ 202接受”。无法弄清楚自己在这里应该出现什么问题。
身体是否面临同样的问题?请给我一些线索来解决这个问题。
或者在Python2.7和WCF之间进行双工通信的任何其他想法总是受到赞赏。