I cant find any good samples for that scenario.
Also, the WCF service used the Entity Framework 6.0 which should return big JSON structures.
For now I am just trying to find a simple example which can call a simple WCF service:
[ServiceContract]
public interface ITest
{
[OperationContract(Name = "Test_GetDate")]
[WebGet(UriTemplate = "/GetDate", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
string GetDate();
...
public class Test : ITest
{
public string GetDate()
{
return (DateTime.UtcNow.ToString());
}
...
Thank you
Yes it can. This scenario worked for me, but I was using XML format (WCF SOAP) not rest/json, but You can try.
-I use soap UI to figure out how soap Envelope should look like. This tool is free http://www.soapui.org/ and it is easy to use.
-Create New Soap UI project and paste WSDL address in the input, application will generate empty XML request - soap envelope.
-You can test your service from this app
-I am using cfhttp to invoke service from cf:
We figured out soap envelope and we put this in cf variable :
<cfsavecontent variable="soapBody">
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:tem="http://tempuri.org/" xmlns:ozon="http://schemas.datacontract.org/blah/prc">
<soapenv:Header/>
<soapenv:Body>
<tem:myservicemethod>
<tem:someParameter1>This is my first param</tem:someParameter1>
<tem:someParameter2>
<blah:AC>This is my second parameter</blah:AC>
</tem:someParameter2>
</tem:myservicemethod>
</soapenv:Body>
</soapenv:Envelope>
</cfsavecontent>
Now invoke service. This I digged from Ben Nadel's blog : http://www.bennadel.com/blog/1809-Making-SOAP-Web-Service-Requests-With-ColdFusion-And-CFHTTP.htm
<cfhttp
url="http:/SomeService/Service.svc"
method="post"
result="httpResponse">
<!---
TIP : Look into your WSDL to figure out SOAPAction value
--->
<cfhttpparam
type="header"
name="SOAPAction"
value="http://tempuri.org/SomeService/myservicemethod"
/>
<cfhttpparam
type="header"
name="accept-encoding"
value="no-compression"
/>
<cfhttpparam
type="xml"
value="#trim( soapBody )#"
/>
</cfhttp>
<cfdump var="#httpResponse#" />
Related
i want to consume soap web serivce in apache camel using Java DSL.Any way without CXF.i have already try using CXF with spring.
Here is a simple example that used only camel http without cxf. If you need to perform some modifications of SOAP request string you can just change "constant" to something like "spel".
<setBody><constant><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header/>
<soapenv:Body>
<MyAction>
<myparam>ABC</myparam>
</MyAction>
</soapenv:Body>
</soapenv:Envelope>]]></constant></setBody>
<setHeader headerName="SOAPAction"><constant>MySOAPAction</constant></setHeader>
<setHeader headerName="CamelHttpMethod"><constant>POST</constant></setHeader>
<setHeader headerName="Content-Type"><constant>text/xml;charset=UTF-8</constant></setHeader>
<to uri="http://myserver:1234" />
Same with Java DSL
public class MyRouteBuilder extends RouteBuilder {
public void configure() {
from("direct:start")
.setBody(constant("")) // String SOAP content from XML example
.setHeader("SOAPAction", constant("MySOAPAction"))
.setHeader("CamelHttpMethod", constant("POST"))
.setHeader("Content-Type", constant("text/xml;charset=UTF-8"))
.to("http://myserver:1234")
.log("SOAP service called"); // Here you can process service response
}
}
I'm very new to WCF and the related technologies. (Using WCF 4.0, by the way.)
Here are some snippets from the WSDL file for a web service that I need to interface with.
<wsdl:binding name="MPGWCSTAOperations_v1_1SoapBinding" type="impl:MPGWCSTAOperations">
<wsdlsoap:binding transport="http://schemas.xmlsoap.org/soap/http" />
...
<wsdl:operation name="MonitorStartLine">
<wsdlsoap:operation soapAction="urn:v1_1.csta.ws.mpgw.gintel.com/MonitorStart" />
<wsdl:input name="MonitorStartLineRequest">
<wsdlsoap:body use="literal" />
</wsdl:input>
<wsdl:output name="MonitorStartLineResponse">
<wsdlsoap:body use="literal" />
</wsdl:output>
</wsdl:operation>
...
</wsdl:binding>
<wsdl:portType name="MPGWCSTAOperations">
...
<wsdl:operation name="MonitorStartLine" parameterOrder="monitorStartLine">
<wsdl:input name="MonitorStartLineRequest" message="impl:MonitorStartLineRequest" />
<wsdl:output name="MonitorStartLineResponse" message="impl:MonitorStartLineResponse" />
</wsdl:operation>
....
</wsdl:portType>
<wsdl:message name="MonitorStartLineResponse" />
My understanding is that the MonitorStartLine operation is defined to return a response message MonitorStartLineResponse, which is defined to be an empty message.
I've used Visual Studio's Project - Add Service Reference facility to generate C# proxy code for this.
Then I do something like this:
MPGWCSTAOperationsClient cstaOperationsClient = new MPGWCSTAOperationsClient();
MonitorStartLine monitorStartLine = new MonitorStartLine();
monitorStartLine.pnis = new string[] {"0000032"};
cstaOperationsClient.MonitorStartLine(monitorStartLine);
This results in the following exception:
System.ServiceModel.CommunicationException was unhandled
HResult=-2146233087
Message=Error in deserializing body of reply message for operation 'MonitorStartLine'.
End element 'Body' from namespace 'http://schemas.xmlsoap.org/soap/envelope/' expected.
Found element 'monitorStartLineResponse' from namespace 'urn:v1_1.csta.ws.mpgw.gintel.com'. Line 1, position 296.
Source=mscorlib
Using Fiddler I'm seeing the response as follows:
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
X-Powered-By: Servlet 2.5; JBoss-5.0/JBossWeb-2.1
Content-Type: text/xml;charset=utf-8
Transfer-Encoding: chunked
Date: Wed, 16 Oct 2013 22:01:44 GMT
149
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<monitorStartLineResponse xmlns="urn:v1_1.csta.ws.mpgw.gintel.com"/>
</soapenv:Body>
</soapenv:Envelope>
Which looks to me like it conforms to the WSDL.
I'm thinking that I can probably just ignore the error (the server will never be the wiser), but I'd prefer to fix the problem if possible.
The message conforms to the WSDL, but in a place where the WSDL specification is ambiguous. .NET is expecting nothing within the Body element, because no message parts were defined. The sender is sending an empty monitorStartLineResponse element instead, as though a single message part were specified, with an element named monitorStartLineResponse.
Because of areas where the WSDL specification is ambiguous, the Web Services Interoperability Organization was formed. The WS-I Basic Profile 1.1 specification was developed to specify a subset of WSDL which is guaranteed to be interoperable across platforms.
This WSDL does not conform to WS-I BP 1.1.
In fact, from reading the WSDL 1.1 spec (section 3.4, soap:operation), I see that this will be taken to be a "document-literal binding" because there are no "style" attributes saying otherwise.
In section 4.4.1, Bindings and Parts, R2213, the WS-I BP 1.1 spec says:
R2213 In a doc-literal description where the value of the parts attribute of soapbind:body is an empty string, the corresponding ENVELOPE MUST have no element content in the soap:Body element.
That is what .NET is expecting, but it's not what .NET is receiving.
Here's the workaround that I implemented. (It is debatable as to whether it's better to implement a workaround or to just ignore the exception - I prefer to do it this way.)
What I'm doing is modifying the response message before WCF invokes SOAP processing on it. I'm simply removing the XML element that WCF/SOAP don't think should be there.
/// <summary>
/// This class is used to provide a workaround for a problem due to the (censored) server sending
/// responses encoded in SOAP which do not, at least according to WCF standards, conform to the
/// WSDL specifications published for the server.
/// </summary>
public class MessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message requestMessage, IClientChannel clientChannel)
{
return null; // Method not needed
}
public void AfterReceiveReply(ref Message replyMessage, object correlationState)
{
if (replyMessage.IsFault)
return; // Avoid distortion of SOAP fault messages
string messageBody;
using (MemoryStream memoryStream = new MemoryStream())
{
using (XmlWriter xmlWriter = XmlWriter.Create(memoryStream))
{
replyMessage.WriteMessage(xmlWriter);
xmlWriter.Flush();
messageBody = Encoding.UTF8.GetString(memoryStream.ToArray());
}
}
messageBody = messageBody.Replace(
"<monitorStartLineResponse xmlns=\"urn:v1_1.csta.ws.mpgw.gintel.com\" />", "");
using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(messageBody)))
{
using (XmlDictionaryReader xmlDictionaryReader =
XmlDictionaryReader.CreateTextReader(memoryStream, new XmlDictionaryReaderQuotas()))
{
Message newMessage =
Message.CreateMessage(xmlDictionaryReader, int.MaxValue, replyMessage.Version);
newMessage.Properties.CopyProperties(replyMessage.Properties);
replyMessage = newMessage;
}
}
}
}
/// <summary>
/// Class needed to inject the above MessageInspector class into the WCF processing of messages.
/// </summary>
public class InjectInspectorBehavior : IEndpointBehavior
{
public void Validate(ServiceEndpoint serviceEndpoint)
{
// Method not needed
}
public void AddBindingParameters(ServiceEndpoint serviceEndpoint,
BindingParameterCollection bindingParameters)
{
// Method not needed
}
public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint,
EndpointDispatcher endpointDispatcher)
{
// Method not needed
}
public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MessageInspector());
}
}
This is put into operation by adding the second line shown here:
_cstaOperationsClient = new MPGWCSTAOperationsClient();
_cstaOperationsClient.Endpoint.Behaviors.Add(new InjectInspectorBehavior());
The above code is largely based on code found in these two locations:
http://blogs.msdn.com/b/kaevans/archive/2008/01/08/modify-message-content-with-wcf.aspx
Replacing content of WCF Message
We have JAX-WS web service like this:
public class NamedDataHandlerContainer {
public String options; // format is option1_name=option1_value;option2_name=option2_value
#XmlMimeType("application/octet-stream") public DataHandler dataHandler;
}
#WebService
public interface mtomserver {
#WebMethod public int saveFile(String name,
#XmlMimeType("application/octet-stream") List<NamedDataHandlerContainer> contents,
#XmlMimeType("application/octet-stream") #WebParam(mode = WebParam.Mode.OUT) Holder<List<NamedDataHandlerContainer>> results);
}
When WSDL for that web service is processed with SvcUtil of .NET 4.0, it generates byte[] type for NamedDataHandlerContainer.dataHandler:
public partial class namedDataHandlerContainer;
{
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, Order = 0)]
public string options;
[System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified, DataType = "base64Binary", Order = 1)]
public byte[] dataHandler;
}
However, in App.config it generates Mtom artifacts:
<basicHttpBinding>
<binding name="mtomserverImplPortBinding" messageEncoding="Mtom" maxReceivedMessageSize="1000000000" />
</basicHttpBinding>
(maxReceivedMessageSize is added by us to allow large attacghments). In fact WCF client sends MTOM attachment to the service - we are dumping HTTP payloads and confirm that:
--uuid:394d798b-e43e-47cc-82dd-64e32ef51edd+id=1
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><saveFile xmlns="http://wsserver.mtomtest/"><arg0 xmlns="">myfile.bin</arg0><arg1 xmlns=""><options>my options from .NET</options><dataHandler><xop:Include href="cid:http://tempuri.org/1/634993057692269386" xmlns:xop="http://www.w3.org/2004/08/xop/include"/></dataHandler></arg1></saveFile></s:Body></s:Envelope>
--uuid:394d798b-e43e-47cc-82dd-64e32ef51edd+id=1
Content-ID: <http://tempuri.org/1/634993057692269386>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
<binary content goes here>
JAX-WS can successfully apply streaming to such payload. However, is there a way to implement streaming on .NET side? I have read MSDN where it is explicitly said that only one parameter with streaming enabled may exist. However, is there a way to have custom message serializer (or something custom, I'm not an expert in WCF) and still avoid loading entire payload into memory.
WCF has a configuration to enable streaming. You don't need to write any additional code to achieve this.
<basicHttpBinding>
<binding name="mtomserverImplPortBinding" messageEncoding="Mtom" maxReceivedMessageSize="1000000000" transferMode="Streamed"/>
</basicHttpBinding>
Source: http://msdn.microsoft.com/en-us/library/ms789010.aspx
What is the use of Action and ReplyAction in OperationContract attribute ?
Action defines your input uri for the soap operation for your service method.
Reply Action defines the output uri for your service method.
They are basically used to customize the uri for both. See below.
[ServiceContract]
public partial interface IServiceContract
{
[OperationContract(
Action = "http://mynamspace/v1/IServiceContract/Input/ServiceMethod",
ReplyAction = "http://mynamspace/v1/IServiceContract/Output/ServiceMethod")]
SomeResponseType ServiceMethod(SomeRequestType x);
In your wsdl you would see
<wsdl:portType name="IServiceContract">
<wsdl:operation name="ServiceMethod">
<wsdl:input wsaw:Action="http://mynamspace/v1/IServiceContract/Input/ServiceMethod" name="SomeRequestType" message="tns:SomeRequestType " />
<wsdl:output wsaw:Action="http://mynamspace/v1/IServiceContract/Output/ServiceMethod" name="SomeResponseType" message="tns:SomeResponseType " />
That make sense?
Its for WS addressing.
Introduction to WS-Addressing: http://www.fpml.org/_wgmail/_bpwgmail/pdfdz3oYx1M9e.pdf
http://www.w3.org/Submission/ws-addressing/
Look at the reply soap message:
http://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontractattribute.action.aspx
We've observed that when we expose a WCF service which uses classes decorated with various xml serialisation attributes, despite the fact that we use the XmlSerializerFormat attribute on the interface any XmlRoot attribute on any of the operation's parameters gets completely ignored.
The namespace of the parameters is always that of the service and not what we specify.
This is causing us problems as it does not seem to be backwards compatible with ASMX and also because we're using BizTalk, and need to have tighter control over the shape of the XML's exchanged.
A few questions then -
Anybody knows what is the rationale
behind this decision?
Anybody knows
how this is happening? I was under
the impressions that WCF, with the
XmlSerializerFormat attribute, uses
the XmlSerialiser to serialise the
types, which would suggest XmlRoot
should be taken into account, how
come this is not the case? (is it
only due to the fact that, taking
the SOAP envelope into account, the
parameter is not root?)
Most
importantly - anybody knows if
there's a way to 'force the issue' -
i.e. get the parameters to be of the
namespace of our choosing?
I've seen this post, but I don't believe it is relevant to my question -
As per Wagner Silveira's request - the contracts I used to test this are -
[ServiceContract(Namespace = "http://servicecontract"),
XmlSerializerFormat(Style = OperationFormatStyle.Document)]
public interface ITestService
{
[OperationContract]
MyOtherType MyTestMethod(MyType obj);
}
// Composite class for DCS and XMLS
[Serializable, XmlType, XmlRoot(Namespace = "http://datacontract")]
public class MyType
{
[XmlAttribute]
public string StringValue { get; set; }
}
// Composite class for DCS and XMLS
[Serializable, XmlType, XmlRoot(Namespace = "http://datacontract")]
public class MyOtherType
{
[XmlAttribute]
public string OtherStringValue { get; set; }
}
I assume you're using SOAP as the message format. In this case, the object you're serializing is not the root of the XML, the soap envelope is. So it makes sense that the XmlRoot would be ignored. By default WCF will create a message contract for you and name the response and it has the namespace of the service. What you can do is create your own message contract to have full control over SOAP.
Create the following two classes:
[MessageContract]
public class MyTestMethodRequest
{
[MessageBodyMember( Namespace = "http://datacontract" )]
public MyType MyType;
}
[MessageContract]
public class MyTestMethodResponse
{
[MessageBodyMember( Namespace = "http://datacontract" )]
public MyOtherType MyOtherType;
}
Then change the signature of your service operation to the following.
[OperationContract]
public MyTestMethodResponse MyTestMethod( MyTestMethodRequest request )
{
return new MyTestMethodResponse {
MyOtherType = new MyOtherType {
OtherStringValue = "bar"
}
};
}
Now if you example the SOAP messages you should see the following:
Request
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<Action xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none"
s:mustUnderstand="1">http://servicecontract/TestService/MyTestMethod</Action>
</s:Header>
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyTestMethodRequest xmlns="http://servicecontract">
<MyType StringValue="foo" xmlns="http://datacontract" />
</MyTestMethodRequest>
</s:Body>
</s:Envelope>
Response
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header />
<s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<MyTestMethodResponse xmlns="http://servicecontract">
<MyOtherType OtherStringValue="bar" xmlns="http://datacontract" />
</MyTestMethodResponse>
</s:Body>
</s:Envelope>
I don't know why WCF ignores XmlRoot, so I can't answer that part of your question. But I do have a couple ways to solve the problem.
start with WSDL first.
If you have a particular set of XML namespaces you would like to apply to the messages that get sent and receieved, use WSDL and XML Schema to explicitly specify them.
Then, generate the Server-side stub code, or the client-side proxy code, directly from that WSDL via the svcutil.exe tool.
use a custom ServiceHost
The other option open to you, described at this link, is to use a custom ServiceHost that overrides WCF's decision to disregard the XmlRoot or XmlType attributes on message types.
If you choose to go for the WSDL-First approach, the WSDL should look like this:
<?xml version="1.0" encoding="utf-8" ?>
<definitions
xmlns="http://schemas.xmlsoap.org/wsdl/"
targetNamespace="urn:The-Service-namespace"
xmlns:tns="urn:The-Service-namespace"
xmlns:s="http://www.w3.org/2001/XMLSchema"
xmlns:n0="urn:The-Request-namespace"
xmlns:n1="urn:The-Response-namespace"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
elementFormDefault= "unqualified"
>
<types>
<s:schema targetNamespace="urn:The-Request-namespace" >
<s:complexType name="Type1">
<s:sequence>
<s:element name="x" minOccurs="1" maxOccurs="1" type="s:string"/>
</s:sequence>
</s:complexType>
<s:element name="Type1" type="n0:Type1" />
</s:schema>
<s:schema targetNamespace="urn:The-Response-namespace" >
<s:complexType name="Type2">
<s:sequence>
<s:element name="x" minOccurs="1" maxOccurs="1" nillable="false" type="s:string"/>
<s:element name="y" minOccurs="1" maxOccurs="1" nillable="false" type="s:int"/>
<s:element name="z" minOccurs="1" maxOccurs="1" nillable="false" type="s:boolean" />
</s:sequence>
</s:complexType>
<s:element name="Type2" type="n1:Type2" />
</s:schema>
</types>
<message name="RequestMessage">
<part name="inPart1" element="n0:Type1" />
</message>
<message name="ResponseMessage">
<part name="outPart1" element="n1:Type2" />
</message>
<portType name="PortTypeName">
<operation name="Method1">
<input message="tns:RequestMessage" />
<output message="tns:ResponseMessage" />
</operation>
</portType>
<binding name="InterfaceName" type="tns:PortTypeName">
<soap:binding
transport="http://schemas.xmlsoap.org/soap/http"
style="rpc" />
<operation name="Method1">
<soap:operation soapAction="" style="document" />
<input> <soap:body use="literal" /> </input>
<output> <soap:body use="literal" /> </output>
</operation>
</binding>
</definitions>
This WSDL is very simple - it defines a single operation, with a single request message and a single response message.
Notice there are three xml namespaces:
urn:The-Service-namespace
used for the element that wraps the request and response - the first element inside the <SOAP:body>
urn:The-Request-namespace
used for the element wrapped inside that request wrapper, which gets deserialized into an instance of Type1.
urn:The-Response-namespace
used for the element wrapped inside that response wrapper, which gets deserialized into an instance of Type2.
If your web services interface is more complicated, has more operations and consequently more request and response message types, you can add more namespaces, if you like, for all those additional types.