如何在WCF SOAP方法上实现curl GET

本文关键字:实现 curl GET 方法 SOAP WCF | 更新日期: 2023-09-27 18:11:01

我有一个使用WCF的服务,在SLES盒子上运行Mono。我用的是BasicHttpBinding。现在,我有一个简单地返回布尔值的方法,我想从SLES框本身调用这个方法并获取布尔值。我正在尝试使用curl,但到目前为止,我还没有成功调用该方法。

假设我的服务名为"RemoteService",我想调用的方法是"CheckProcessRunning"。同样,CheckProcessRunning只是返回一个布尔值,而且返回得非常快。

所以我试过:

curl -H "Content-Type: text/xml; charset=utf-8" -H "SOAPAction:" -X GET http://localhost:4000/RemoteService/CheckProcessRunning
curl --header "Content-Type: text/xml;charset=UTF-8" --header "SOAPAction:RemoteService/CheckProcessRunning" http://localhost:4000/RemoteService/CheckProcessRunning
curl --header "Content-Type: text/xml;charset=UTF-8" --header "SOAPAction:url:CheckProcessRunning" http://localhost:4000/RemoteService

都返回如下内容:

<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body><s:Fault><faultcode xmlns:a="http://schemas.microsoft.com/ws/2005/05/addressing/none">a:DestinationUnreachable</faultcode><faultstring xml:lang="">The request message has the target 'http://localhost:4000/RemoteService/CheckProcessRunning' with action '' which is not reachable in this service contract</faultstring></s:Fault></s:Body></s:Envelope>

所以我的问题是,我如何在WCF服务中对SOAP方法进行curl请求?我需要使用BasicHttpBinding来做到这一点-我已经研究了WebHttpBinding,但我发现我不能使用它,因为它破坏了其他功能。

如何在WCF SOAP方法上实现curl GET

您的帖子中的错误信息显示操作为空或为空。因此,解决方案可能是更改您的服务以支持空操作。服务将需要通过查看请求体来确定调用哪个方法。幸运的是,在WCF中有一个这样的例子。. net 4的WF示例和使用信息。

还有另一篇文章提到了cURL,并专门为这里的空操作定制了相同的示例:WCF、cURL、Java和ASMX。功劳归于原作者,但为了后人,这里是代码……

在操作契约中指定一个空操作:

[OperationContract(Action="")]
ResponseMessage DoOperationA(RequestMessage message);
[OperationContract(Action="")]
ResponseMessage DoOperationB(RequestMessage message);

为业务项目添加EmptyActionBehaviorAttribute类:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
public class EmptyActionBehaviorAttribute : Attribute, IContractBehavior
{
    public void AddBindingParameters(
        ContractDescription contractDescription, 
        ServiceEndpoint endpoint, 
        BindingParameterCollection bindingParameters)
    {
        return;
    }
    public void ApplyClientBehavior(
        ContractDescription contractDescription, 
        ServiceEndpoint endpoint, 
        ClientRuntime clientRuntime)
    {
        return;
    }
    public void ApplyDispatchBehavior(
        ContractDescription contractDescription, 
        ServiceEndpoint endpoint, 
        DispatchRuntime dispatchRuntime)
    {
        var dispatchDictionary = new Dictionary<XmlQualifiedName, string>();
        foreach (var operationDescription in contractDescription.Operations)
        {
            var qname = new XmlQualifiedName(
                operationDescription.Messages[0].Body.WrapperName, 
                operationDescription.Messages[0].Body.WrapperNamespace);
            dispatchDictionary.Add(qname, operationDescription.Name);
        }
        dispatchRuntime.OperationSelector 
            = new EmptyActionOperationSelector(dispatchDictionary);
    }
    public void Validate(
        ContractDescription contractDescription, 
        ServiceEndpoint endpoint)
    {
    }
}

为业务项目添加EmptyActionOperationSelector类:

class EmptyActionOperationSelector : IDispatchOperationSelector
{
    Dictionary<XmlQualifiedName, string> dispatchDictionary;
    public EmptyActionOperationSelector(
        Dictionary<XmlQualifiedName, string> dispatchDictionary)
    {
        this.dispatchDictionary = dispatchDictionary;            
    }
    public string SelectOperation(ref System.ServiceModel.Channels.Message message)
    {
        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(message.ToString());
        var nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
        nsManager.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope/");
        XmlNode node = xmlDoc.SelectSingleNode(
            "/soapenv:Envelope/soapenv:Body", 
            nsManager).FirstChild;
        var lookupQName = new XmlQualifiedName(node.LocalName, node.NamespaceURI);
        return dispatchDictionary.ContainsKey(lookupQName)
            ? dispatchDictionary[lookupQName]
            : node.LocalName;           
    }
}

最后,在服务契约上使用新属性:

[ServiceContract]
[XmlSerializerFormat(Style = OperationFormatStyle.Rpc, Use = OperationFormatUse.Encoded)]
[EmptyActionBehavior]
public interface IMyService

下面是它的工作原理:

我向WCF接口添加了WebInvoke装饰,以指定请求和响应的方法和格式:

[OperationContract]
[WebInvoke(Method = "GET", RequestFormat = WebMessageFormat.Json,
       ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
bool CheckProcessRunning();

我还初始化了另一个主机(使用不同的端口),以使用WebServiceHost:

将我的接口公开为REST服务。
string webHttpAddress = "http://localhost:4001/RemoteService";
WebServiceHost webServiceHost = new WebServiceHost(typeof(RemoteService), new Uri[] { new Uri(webHttpAddress) });
webServiceHost.AddServiceEndpoint(typeof(IRemoteService), new WebHttpBinding(WebHttpSecurityMode.None), webHttpAddress);
webServiceHost.Open();

现在我可以调用CheckProcessRunning方法使用curl:

curl http://localhost:4001/RemoteService/CheckProcessRunning
true