WCF Serialization problems with WSDL file created by Java tools - java

My team is tasked with getting several in-house developed .NET client applications to connect to some new Java web services. The Java web service is a third party, vendor supplied WSDL file that our team has a limited ability to modify/control...meaning we probably have the power to request our vendor to make slight tweaks to the WSDL, but major changes would probably be either unfeasible or difficult to request.
That said, we are attempting to utilize WCF/.NET 4.0 to generate the .NET proxy class files we need on the client side. The proxy client class file generation process executes without issues.
The problem is when we attempt to use the proxy class file in a client app. I have verified through the web trace tool, Fiddler, that the raw SOAP message request fails to get sent across the wire to the server.
The specific .NET exception message I get when attempting to call the web service method in question, looks like this:
System.InvalidOperationException was unhandled
Message=XmlSerializer attribute System.Xml.Serialization.XmlAttributeAttribute is not valid in baseLanguage. Only XmlElement, XmlArray, XmlArrayItem, XmlAnyAttribute and XmlAnyElement attributes are supported when IsWrapped is true.
Source=System.ServiceModel
When I examine the .NET autogenerated proxy class file, Reference.cs, I noticed that the request and response messages for my web service method looks something like this:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(WrapperName="QueryPBOT_MXWO_OS", WrapperNamespace="http://www.ibm.com/maximo", IsWrapped=true)]
public partial class QueryPBOT_MXWO_OSRequest {
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=0)]
public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=1)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string baseLanguage;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=2)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string transLanguage;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=3)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string messageID;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=4)]
[System.Xml.Serialization.XmlAttributeAttribute()]
public string maximoVersion;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=5)]
[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute(false)]
public bool uniqueResult;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=6)]
[System.Xml.Serialization.XmlAttributeAttribute(DataType="positiveInteger")]
public string maxItems;
[System.ServiceModel.MessageBodyMemberAttribute(Namespace="http://www.ibm.com/maximo", Order=7)]
[System.Xml.Serialization.XmlAttributeAttribute(DataType="integer")]
[System.ComponentModel.DefaultValueAttribute("0")]
public string rsStart;
public QueryPBOT_MXWO_OSRequest() {
}
public QueryPBOT_MXWO_OSRequest(ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery, string baseLanguage, string transLanguage, string messageID, string maximoVersion, bool uniqueResult, string maxItems, string rsStart) {
this.PBOT_MXWO_OSQuery = PBOT_MXWO_OSQuery;
this.baseLanguage = baseLanguage;
this.transLanguage = transLanguage;
this.messageID = messageID;
this.maximoVersion = maximoVersion;
this.uniqueResult = uniqueResult;
this.maxItems = maxItems;
this.rsStart = rsStart;
}
}
I know that people reading this post will want to see the actual WSDL file we're trying to consume, but it is quite large, and I'm concerned the sheer size of it would make pinpointing the error quite difficult.
I'm hoping that the autogenerated client proxy file and the .NET exception will help someone recognize this WCF Serialization issue.
We've confirmed from our Java vendor that the style of WSDL they generate is doc-literal. After doing some research on the internet, it appears that WCF, by default. translates WSDL files with doc-literal wrapped, and that this may explain, at least in part, why we're seeing this WCF serialization issue with the WSDL file.
I've discovered, through trial and error, that the following attribute decorator in the proxy class file is the culprit behind the serialization issue:
[System.Xml.Serialization.XmlAttributeAttribute()]
If I comment out all instances of this attribute in the proxy class file and rerun my client app, the SOAP message successfully gets sent across the wire and I get a valid web service response come back from the server.
This fix is better than nothing, but I would very much prefer a solution that doesn't require myself or anyone on my team to constantly tweak these .NET autogenerated proxy class files.
I would like to know if there is something I can do, either through the various WCF tools or by modifying the WSDL file, that prevents that [System.Xml.Serialization.XmlAttributeAttribute()] from being applied to my request and response object properties?
Or at least a high level description of WHY we are seeing this serialization behavior in .NET with the Java WSDL file?
thanks in advance,
John

Use svcutil.exe utility with the /wrapped option on to generate proxy classes.
This will create slightly different classes then those created though Visual Studio in a way described by Ladislav Mrnka here. Resulting proxies should be free from the XmlAttribute issue when using on the client side.
Example:
svcutil /t:code wsdl.xml /out:wsdl.cs /serializer:XmlSerializer /wrapped

Here is how to do Mikhail G's solution within IDE:
Open Reference.svcmap under Service References
Add <Wrapped>true</Wrapped> under <ClientOptions> and Save
Right Click Reference.svcmap and hit "Run Custom Tool"
Visual Studio, where magic happens :)
Note: Tried with VS 2015. Prior versions may have same option with a
different name than "Run Custom Tool"

As a follow-on to stratovarius's answer, in VS 2017 the Service References folder is replaced by Connected Services, so you have to:
Open the {project}/Connected Services folder in Windows Explorer
Find and edit the Reference.svcmap with a text editor
Add <Wrapped>true</Wrapped> to the <ClientOptions> section
Save the file
In VS, right click on the service reference under Connected Services and select "Update Service Reference"
This cleared the exception from my service call.

Based on generated code it looks like your Java service expects request like:
<s:Envelope xmlns:s="...">
...
<s:Body>
<QueryPBOT_MXWO_OS xmlns="http://www.ibm.com/maximo" baseLanguage="..." transLanguage="..." ...>
<PBOT_MXWO_OSQuery>
...
</PBOT_MXWO_OSQuery>
</QueryPBOT_MXWO_OS>
</s:Body>
</s:Envelope>
The problem is that WCF recognized QueryPBOT_MXWO_OS as wrapper element for request. I'm not sure why it fires exception but probably there is some restriction that wrapper element can't have attributes. I'm suspicious that this is just global error handling shared with version which uses IsWrapped=false where usage of attributes is error.
You can try to modify your proxy in this way:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.MessageContractAttribute(IsWrapped=false)]
public partial class QueryPBOT_MXWO_OSRequest
{
[MessageBodyMemberAttribute(Name="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")]
public QueryPBOT_MXWO_OS QueryPBOT_MXWO_OS { get; set; }
}
[XmlRoot(ElementName="QueryPBOT_MXWO_OS", Namespace="http://www.ibm.com/maximo")]
public class QueryPBOT_MXWO_OS
{
[XmlElement(Namespace="http://www.ibm.com/maximo")]
public ConsoleApplication7.wsMaximo.PBOT_MXWO_OSQueryType PBOT_MXWO_OSQuery;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string baseLanguage;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string transLanguage;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string messageID;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string maximoVersion;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
[System.ComponentModel.DefaultValueAttribute(false)]
public bool uniqueResult;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
public string maxItems;
[XmlAttribute(Namespace="http://www.ibm.com/maximo")]
[System.ComponentModel.DefaultValueAttribute("0")]
public string rsStart;
}

I'm using an external "old" Java generated WSDL in my .Net Core app and the auto-generated Reference.cs did not work for me. I had to remove the [System.Xml.Serialization.XmlAttributeAttribute()] in order for it to work.

Related

How to create GRPC server directly from protobuf without compiling it into java code

It is necessary to implement a universal GRPC server as a stub.
Didn't find anything similar for the server, only for the client.
Thank you very much!
If you don't want to process the protobuf messages, then you need to create a Marshaller that serializes to/from byte[], a MethodDescriptor for each method you want to support, and a ServerCallHandler for your application logic. You might find a grpc proxy mockup helpful. Those can be combined together to pass to serverBuilder.addService(ServerServiceDefinition). You can also use ServerCalls to help make a ServerCallHandler.
class ByteMarshaller implements MethodDescriptor.Marshaller<byte[]> {
#Override public byte[] parse(InputStream stream) {
try {
return ByteStreams.toByteArray(stream);
} catch (IOException ex) {
throw new RuntimeException();
}
}
#Override public InputStream stream(byte[] value) {
return new ByteArrayInputStream(value);
}
};
class YourHandler extends ServerCallHandler<byte[],byte[]> {...}
MethodDescriptor<> desc = MethodDescriptor.<byte[], byte[]>newBuilder()
// UNKNOWN is fine, but specify the type if you know it
.setType(MethodDescriptor.MethodType.UNKNOWN)
.setFullMethodName("package.YourService/Method"))
.setRequestMarshaller(new ByteMarshaller())
.setResponseMarshaller(new ByteMarshaller())
.build();
serverBuilder.addService(
ServiceDescriptor.newBuilder("package.YourService")
.addMethod(ServerMethodDefinition.create(desc, new YourHandler()))
.build());
If you want to parse the protobuf, then you can use DynamicMessage with gRPC's Protobuf Marshaller. A similar client-side question explains that process.
I believe you would like to use the generated server for testing purposes? If so, there is a practice called service virtualization or API simulation - a subset of the test double family. It allows you to "simulate" or "stub" the real system for the purpose of testing your system under test. Some of those tools allow importing schema files to generate stubs (i.e. Swagger/OpenAPI/Proto/WSDL/...).
Wikipedia contains a list of those tools. Looking at that list today one of those tools that support gRPC is called Traffic Parrot which allows you to create gRPC mocks based on your Proto files. There are also open-source tools like GripMock but it does not generate stubs based on Proto files, you have to create them manually.
Keep in mind, the stub/mock/simulator generated will be only a test double, it will not replicate the full behavior of the system the Proto file corresponds to. The tool that imports the Proto file and generates a server test double can only know the syntax of the messages, not semantics nor the behaviour of the real system.
If you wanted to also replicate partially the semantics of the messages consider a recording of gRPC messages to create service stubs, that way you can see the sample data as well.

How to make changes in marshalled output in Java web service client

I am trying to interact with a third party web service, who requires me to send a security token as a part of each request. The token is a node by itself, and I acquire it from the response of an initial call.
The web service endpoint is dotNet, and I have a Java client.
Apparently, the server side expects me to send the security token exactly like it was provided to me: literally the same string: so it won't do if its content has a different size, order, etc.
So, in SoapUI, everything works fine. There is a token in the response of the initial 'startSession' call, which I copy into the request of a next call.
But in Java (I tried JAX-WS and CXF generated code, both rely on JAXB) it doesn't work. I receive the token as an object after it is unmarshalled, and I use this object in the next call.
When marshalled and send, it is missing a namespace attribute in a subnode. The server side says it won't continue because the token is incorrect.
So, by using JAXB outbound logical handler functionality, I am able to add the missing namespace without any problems in the DOM source (I was also able to achieve this with a CXF interceptor).
The problem now is, that the attributes, when marshalled, are ordered in such a way that the result still not matches the provided token as it was before it was unmarshalled. Alhough it should not matter, the order of these attributes is crucial.
I have no idea how to solve this, unless it is possible to actually modify the output XML string. I even tried a dirty hack by removing all attributes from the subnode and replacing them with one attribute that visually looks the same; but then the outer two double quotes become single quotes...
I hope anyone has an idea. Because I have none.
Cheers.
UPDATE:
I should have mentioned that the attributes in question are namespace(d) attributes. The node should look like this:
<HawanedoSessionInfo xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c">
However, after using outbound JAXB handler to add the missing xmlns="...", my result looks like this:
<HawanedoSessionInfo xmlns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
In the HawanedoSessionInfo class, I used XmlType.proporder and #XmlAttribute like so:
#XmlType(name = "HawanedoSessionInfo", propOrder = {
"xsd",
"xsi",
"xmlns",
and some other non-attribute sub-elements..
private String xsd;
private String xsi;
private String xmlns;
#XmlAttribute(ns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c")
public String getXsd() {
return xsd;
}
public void setXsd(final String xsd) {
this.xsd = xsd;
}
#XmlAttribute(ns="http://schemas.thecompany.com/Hawanedo/Business/v2.0c")
public String getXsi() {
return xsi;
}
public void setXsi(final String xsi) {
this.xsi = xsi;
}
#XmlAttribute
public String getXmlns() {
return xmlns;
}
public void setXmlns(final String xmlns) {
this.xmlns = xmlns;
}
So apparently the proporder option does not help in this case?
UPDATE 2:
Like I wrote in my answer, it now works. Based on this LINK,
in the HawanedoSessionInfo class I added:
#XmlCustomizer(HawanedoSessionInfoCustomizer.class)
I created the customizer class exactly as described in the linked page, and I added the jaxb.properties.
So I did two things:
1) I added my attributes to (the top of the already existing) propOrder attribute. I added the attributes as instance variables and created the getters/setters. I annotated the getters with XmlAttribute.
2) I implemented the XmlCustomizer solution.
Now comes the strange part. According to Fiddler, the order of the attributes is still not changed! But I must stress that this is now working, ONLY after implementing the Customizer. What is happening here? :)
So in principle you cannot control order of attributes in a standard way, but ....
Depending on jaxb /java version the order can be determined by alphabetical order of the names, the order of declaration.
You could try in your code if a) moving the fields around changes anything, b) renaming the fields (the XMLAttribute than have to map to original name).
If you are lucky, it will work. But of course it is a hack and will work till next jaxb/java update.
The JAXB providers (the actuall implementation can have extra features), that can be used to customized the marshalling process). For example I found that: https://community.oracle.com/thread/977397 abut eclipselink.
I am sure there was a way of intercepting the soap body before it is send or governing the data serialization before it is send. I can think how it was called but try to google the jaxws client customization. If you capture the whole soap message simple xslt transforamation could fix the attributes order.
I feel your pain. The whole point of using xml, jaxws and such is to make our life easier and then someone providers decide not to follow standards and you end up with a mess that you were trying to clean for few days. Good luck and maybe try to contact xml gurus from Eclipse Moxy
I am so happy right now, because I got it working and it only cost me a full week to do so...:) With help of #Zielu, I was pointed to this link with the EclipseLink XMLCustomizer solution as suggested by Blaise Doughan: XMLCustomizer solution
I took the code in my original question (underneath 'UPDATE') and added the exact solution as suggested. Not sure if it is all necessary, but it works. Thanks guys.
It's possible you can control the order by using,
#XmlType (propOrder={"prop1","prop2",..."propN"})

Response from Web Service in Glassfish from C# client

I'm having a problem where my C# client can't parse the data from my webservice in Glassfish.
I have a WSDL and XSD for my webservices as follows:
http://www.consorciovivedigital.com:8080/ServicioInterventoria/ServicioInterventoria?WSDL
http://www.consorciovivedigital.com:8080/ServicioInterventoria/ServicioInterventoria?xsd=1
And I'm using the next C# client to test this webservice:
using System;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Xml.Linq;
using ServicioInterventoria;
public partial class _Default : System.Web.UI.Page
{
ServicioInterventoria.ServicioInterventoria proxy;
protected void Page_Load(object sender, EventArgs e)
{
proxy = new ServicioInterventoria.ServicioInterventoria();
ResultadoMensualIC[] res = proxy.ObtenerResultadosMensuales("Intv12", "2014-07-07T08:08:08");
System.Diagnostics.Debug.WriteLine(res.Length);
System.Diagnostics.Debug.WriteLine(res[0].FechaCorte);
}
}
The problem is that when I execute this code, the res array has the amount of objects that should have, but each value of each object has the default value instead of the correct value. I used Fiddler to check the traffic and it receives the correct SOAP response with the correct data, but it seems that my C# client doesn't know how to parse the data.
I checked with a Java client, and I can get the correct data without any problems, and seems that my C# it's the only one giving problems with this.
Maybe there is a problem with the targetNamespace in the SOAP response, but I don't understand why works correctly in Java but in C# just puts default values.
Anyone have any idea what could be the problem?
If someone needs more information about it, let me know
Thanks beforehand
I solved last week. The problem was that the SOAP response didn't put the namespace for each attribute, then, the C# client doesn't know how to match this (seems like a limitation of C#). And, the other problem was the order of the SOAP response, because, the C# client was expecting each object as was defined in the WSDL, but the response it's ordered alphabetically, in this way, the C# client, doesn't match correctly each attribute.
I did some modifications to the client. First, in each model, for each attribute I added the namespace, something like this:
#XmlElement(name = "IdInterventor", namespace = "http://ws.bigdatasolutions.co/")
public String getIdInterventor() {
return IdInterventor;
}
With this, the SOAP response always puts the namespace for each attribute, which was neccesary for the C# client.
After that, at the beginning of each model class I add this tag, to define the order as defined in the WSDL and expected for the C# client.
#XmlRootElement(name = "AspectosFinancieros")
#XmlType(propOrder={"idInterventor", "numeroContrato", "ano", "valorContratoOperador", "fechaFirmaContrato",
"valorAdicion", "fechaProrrogaAdicion", "valorDesembolso", "fechaPagoDesembolso",
"valorAnticipo", "fechaAnticipo", "valorUtilizacion", "numeroActaAprobacion",
"fechaUtilizacion", "valorRendimiento", "fechaRendimiento", "numeroComprobanteRendimiento",
"valorComision", "fechaComision", "valorGastosAdministrativos", "fechaGastosAdministrativos",
"nombreFiducia", "numeroContratoFiducia", "fechaContratoFiducia", "fechaProrrogaAdicionFiducia",
"marcaTiempo"})
public class AspectosFinancieros {
I checked the expected order in the auto generated class in the C# client.
I hope someone find this useful.

What's the "proper" and right way to keep Jersey Client API functions and REST (Jersey API) Server functions linked?

I was wondering how people with more experience and more complex projects get along with this "uglyness" in the REST Communication. Imagine the following Problem:
We'll need a fair amount of functionalities for one specific resource within our REST Infrastructure, in my case that's about 50+ functions that result in different querys and different responses. I tried to think of a meaningful resource-tree and assigned these to methods that will do "stuff". Afterwards, the Server Resource Class looks like this:
#Path("/thisResource")
public class SomeResource {
#GET/POST/PUT/DELETE
#Path("meaningfulPath")
public Response resourceFunction1 ( ...lots of Params) {
... logic ....
}
//
// lots of functions ...
//
#GET/POST/PUT/DELETE
#Path("meaningfulPath")
public Response resourceFunctionN ( ...lots of Params) {
... logic ....
}
}
To construct the urls my client will call, I made a little function to prevent Typos and to take better use of Constants
so my Client looks like this:
public class Client() {
public returnType function1 () {
client.resource = ResourceClass.build(Constants.Resouce, "meaningfulPath");
...
return response.getEntity(returnType);
}
}
Now the questions that bothers me is how could I link the client function and the server function better?
The only connection between these two blocks of code is the URL that will be called by the client and mapped by the server, and if even this URL is generated somewhere else, this leads to a lot of confusion.
When one of my colleagues needs to get into this code, he has a hard time figuring out which of the 50+ client functions leads to wich server function. Also it is hard to determine if there are obsolete functions in the code, etc. I guess most of you know about the problems of unclean code better than I do.
How do you deal with this? How would you keep this code clean, maintainable and georgeous?
Normally, this would be addressed by EJB or similar technologies.
Or at least by "real" web services, which would provide at least WSDL and schemas (with kind of mapping to Java interfaces, or "ports").
But REST communication is very loosely typed and loosely structured.
The only thing I can think of now, is: define a project (let's call it "Definitions") which would be referenced (hence known) by client and server. In this project you could define a class with a lot of public static final String, such as:
public static final String SOME_METHOD_NAME = "/someMethodName";
public static final String SOME_OTHER_METHOD_NAME = "/someOtherMethodName";
Note: a static final String can very well be referenced by an annotation (in that case it is considered to be constant by the compiler). So use the "constants" to annotate your #Path, such as:
#Path(Definitions.SOME_METHOD_NAME)
Same for the client:
ResourceClass.build(Constants.Resouce, Definitions.SOME_METHOD_NAME);
You are missing the idea behind REST. What you are doing is not REST but RPC over HTTP. Generally you are not supposed to construct URLs using out of band knowledge. Instead you should be following links received in the responses received from the server. Read about HATEOAS:
http://en.wikipedia.org/wiki/HATEOAS

Restlet modify inbound object and return it or return new copy?

I'm trying to learn about restlets more coming from a soap-rpc background. One thing that I can't seem to figure out how to do (and maybe isn't possible) is to modify objects on requests or send back a copied version with modifications.
I'm trying to do something like this:
public interface AddressService {
#Get
Address addOnZipCode( Address address );
}
The server would be deployed out with the implementation and the client could make use of dynamic proxies to do its work.
The server starts just fine but when the client makes the call there is no indication on the server that the implementing method is being called. Furthermore, the client doesn't error until the call to the server returns - the returned object is null?!?
Is what I'm trying to do here possible with restlets? If so, any ideas on what I might be doing wrong?
I can post more code if necessary.
Thanks in advance.
EDIT #1:
I've even tried simplifying it to not use custom objects:
#Post
String execute( String message );
I get the following:
INFO: Starting the default HTTP client
Exception in thread "main" Method Not Allowed (405) - Method Not Allowed
at org.restlet.resource.ClientResource$1.invoke(ClientResource.java:1615)
at $Proxy5.execute(Unknown Source)
I'm beginning to think this is not possible, thus, I have a hard time seeing how this is a viable alternative to SOAP+RPC web services.
EDIT #2:
It looks like this is possible based on examples in the book: "Restlets in Action"
public interface AccountsResource {
#Get("txt")
public String represent();
#Post("txt")
public String add(String account);
}
EDIT #3:
It turns out that simply hitting the "stop" button in my Eclipse console was not shutting down the server instance. Opening a browser to the server URL showed some fishy results - there were multiple old server instances running. After shutting them all down I got it to work. Ultimately the answer was to use #Post instead of #Get1.
Have a look at this:
http://wiki.restlet.org/docs_2.0/13-restlet/21-restlet/318-restlet/303-restlet.html
On the server side your implementation must be like so:
class AddressServerResource extends ServerResource implements AddressService {
// implementation
}
On the client side:
ClientResource cr = new ClientResource("http://your-api.com/address/123");
AddressService service = cr.wrap(AddressService.class);
// use the service transparently
Edit:
#Post
Address addOnZipCode( Address address );

Categories