DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world
Transferring Large Files Between .Net & Java: Web Services Interoperability
It seems alot people have been experiencing problems uploading/downloading extremely large files via web services between a .Net web services client and a Java based web service. This note will hopefully put the matter to rest. The JAX-WS / Metro framework requires one to pass/return a Datahandler when accepting/returning streamed data. The problem is that when generating the stub code in Microsoft Visual Studio from the WSDL exported from the Java server, a byte[] array is returned in place of the Data Handler. The reason is that .NET does not know what a Java Datahandler is. When processing a very large file, say. 3 GB, your client will run out of memory. What we really want is for .Net to generate a Stream object in place of the byte array. To accomplish this, we need to employ some trickery. Say you have a class called ServerService and you want to upload a file, specifying the file name as the parameter. You would do this as follows:
@MTOM(enabled = true, threshold = 512)
@StreamingAttachment(parseEagerly=true, memoryThreshold=4000000L)
@WebService
public class ServerService {
@WebMethod
public upload(@WebParam(name="fileStream")StreamBody stream) {
Datahandler dh = stream.getDataHandler();
// copy data from datahandler to file
}
}
The constraint of the above is that the upload method using a stream may have only one parameter. One way around to specify the file name & other attributes in the Data itself. Simply write a FilterInputStream that reads and parses the first few lines. These lines are the attribute/name pairs that describe the data, i.e. filename, etc. When a linefeed is encountered the data itself begins. The below class is necessary to jinx .Net into creating a Stream object:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "StreamBody", namespace = "http://schemas.microsoft.com/Message")
public class StreamBody {
/**
* The data stream.
*/
@XmlValue
public DataHandler dataHandler;
public DataHandler getDataHandler() {
return dataHandler;
}
public void setDataHandler(DataHandler dataHandler) {
this.dataHandler = dataHandler;
}
}
To enable mtom in your Java web services server, modify the sun-jaxws.xml with enable-mtom="true" as follows:
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint name="FileArchiva" implementation="com.stimulus.archiva.file.webservice.FileArchivaWS"
url-pattern="/FileArchivaWS"
wsdl-location="WEB-INF/wsdl/library.wsdl" enable-mtom="true"/>
</endpoints>
To enable streaming and MTOM on the .Net client, modify a file called app.config and add the parameters messageEncoding="Mtom" and transferMode="Streamed".
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="FileArchivaWSPortBinding" closeTimeout="00:01:00"
openTimeout="01:00:00" receiveTimeout="01:00:00" sendTimeout="01:00:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Mtom" textEncoding="utf-8" transferMode="Streamed"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>





