views:

174

answers:

3

Hi!

I have to send a file to my webservice, but the webservice assumes the file (byte Array) as a base64Binary.

Before the encoding, the byteArrayFile is saved on disk as a regular File. (I'm doing it just for testing)

So, in my Java client for webservice, I'm sending the information this way:

String file = new sun.misc.BASE64Encoder().encode(byteArrayFile);
port.sendFileToWebService(file);

The webservice have to decode the information and save the received file on disk.

    [WebMethod]
    public string sendFileToWebService(string file)
    {

        string dirname = HttpContext.Current.Request.PhysicalApplicationPath + "\\Attachments\\";
        if (!System.IO.Directory.Exists(dirname))
        {
            System.IO.Directory.CreateDirectory(dirname);
        }
        string filename = dirname + "/" + "file.sim";
        WebClient myWebClient = new WebClient();
        myWebClient.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
        byte[] byteArray = null;

        byteArray = Convert.FromBase64String(file.Replace("\n", ""));

        byte[] responseArray = myWebClient.UploadData(filename, "POST", byteArray);
        return "Webservice says OK";
    }

The problem is:

The file saved on disk (before encoding) and the file decoded with C# are not equals. I don't know if it's a problem in Java encoding or C# decoding.

Any suggestions, including changing file types or logic process, will always be appreciated.

Thanks in advance!

EDIT - File comparison:

Original File

Decoded File (after Java encoding)

A: 

I'm probably wrong bit I think that you need to convert the file to a string format for a proper base64 conversion.

Don't know this is necesary in java but in javascript You have to cast first to string and then convert to base64.

Ecarrion
Don't understand the negative vote, just tried to help. :S
Ecarrion
Yeah, here are so many stupid morons around..
Sylar
@Ecarrion You were expecting an up vote becase you were trying to help? Don't you think that defeats the purpose of voting?
bzlm
Did I say that I don't understand why I'm not gettig a positive vote? please dont asume things about other people.
Ecarrion
+1  A: 

Try use normal file i/o instead of a WebClient

public string sendFileToWebService(string file)
{

    string dirname = HttpContext.Current.Request.PhysicalApplicationPath + "\\Attachments\\";
    if (!System.IO.Directory.Exists(dirname))
    {
        System.IO.Directory.CreateDirectory(dirname);
    }
    string filename = dirname + "/" + "file.sim";
    byte[] byteArray = Convert.FromBase64String(file);
    File.WriteAllBytes(filename, byteArray ); //might wanna catch exceptions that could occur here
    return "Webservice says OK";
}
nos
+1  A: 

I know that the XSD standard specifies a data type called base64Binary. What this should allow for, is your [WebMethod] parameter to be a byte[]. Then the underlying service stack will encode the byte array to a base64 string.

For example, I just did a quick Java service like this

   @WebMethod(operationName = "TestByteArray")
    public void testByteArray(byte[] data) {

    }

And the relevant parts of the generated WSDL look like this:

<operation name="TestByteArray">
    <input wsam:Action="jordan.services/EncodingTests/TestByteArrayRequest" message="tns:TestByteArray"/>
    <output wsam:Action="jordan.services/EncodingTests/TestByteArrayResponse" message="tns:TestByteArrayResponse"/>
</operation>

And

<xs:complexType name="TestByteArray">
    <xs:sequence>
        <xs:element name="arg0" type="xs:base64Binary" nillable="true" minOccurs="0"/>
    </xs:sequence>
</xs:complexType>

I have also done a test in .Net:

[WebMethod]
public void testByteArray(byte[] bytes) {
}

Relevant parts of the generated WSDL:

<wsdl:portType name="TestWSSoap">
    <wsdl:operation name="testByteArray">
        <wsdl:input message="tns:testByteArraySoapIn"/>
        <wsdl:output message="tns:testByteArraySoapOut"/>
    </wsdl:operation>
</wsdl:portType>

And

<wsdl:types>
    <s:schema elementFormDefault="qualified" targetNamespace="http://tempuri.org/"&gt;
        <s:element name="testByteArray">
            <s:complexType>
                <s:sequence>
                    <s:element minOccurs="0" maxOccurs="1" name="bytes" type="s:base64Binary"/>
                </s:sequence>
            </s:complexType>
        </s:element>
        <s:element name="testByteArrayResponse">
            <s:complexType/>
        </s:element>
    </s:schema>
</wsdl:types>
Jordan S. Jones
Thank you. Very helpful comment.My problem is related to encoding and decoding in base64 between Java and C#
CalypsOOO
@CalypsOOO - Right, my suggestion is that you don't need to do the base64 encoding before/after the WS call. Just send the raw byte array. When you receive it in c#, just post the byte array (or, write it out directly). If you encode before, then you are sending a xsd:string over the wire instead of xsd:base64Binary as you mentioned in the first sentence of your question.
Jordan S. Jones
@Jordan S. Jones - Hum, Ok. Sorry, I hadn't understood your suggestion.Did you already tested it before? I thought base64Binary was a String, because encoding anything to base64Binary returns a String.Similiar question here: http://stackoverflow.com/questions/2551525/failed-sending-bytes-array-to-jax-ws-web-service-on-axis
CalypsOOO
@CalypsOOO, Yes I have tested it before. When you pass a byte array through a webservice where the type is base64Binary, the underlying webservice stack will convert the binary array to a base64 string for you. Then on the server, when the request comes it, it will base64 decode it back to a byte array for you. My suggestion is to try it.
Jordan S. Jones
Thank you very much!You're totally right! If it's defined as a byteArray, we have to send a byteArray.Thank you!
CalypsOOO