Silverlight changes the io.Stream to byte[] - wcf

I have created a WCF service for uploading images , which accepts System.IO.Stream as input parameter and am using streaming. When I added the service reference in Silverlight project then it automatically changed the parameter of my WCF method from System.IO.Stream to byte[]. Can anyone suggest if there is a way around this so that I can get System.IO.Stream type rather than byte[].
Thanks in advance

Silverlight does not support transfer mode streamed: http://forums.silverlight.net/forums/t/119340.aspx
So I think that you are stuck with getting a byte array.

Can you verify that you're not hitting one of the reader quotas in the service? You can try increasing all of them to see if this solves your problem.

I think you should set the transferMode property of your basicHttpBinding to the correct value, as described in this article. And then add the service reference to your Silverlight application again.

http://blogs.msdn.com/b/carlosfigueira/archive/2010/07/08/using-transfermode-streamedresponse-to-download-files-in-silverlight-4.aspx

Even I was struggling with the same issue. At last I got a solution by myself. All you can do is:
declare the accepting parameter as string array in the WCF Service.
convert the byte array into string array at client place.
After Sending the converted byte array as string array again convert back it into byte array.
eg. at the WCF side:
[DataContract]
Class FileInfo
{
[DataMember]
string filename;
[DataMember]
string[] StrArr;
}
the receiving function:
public void uploadFile(FileInfo fi)
{
int len=fi.StrArr.len;
byte[] myFileByte=new byte[len];
for(int i=0;i<len;i++)
{
myFileByte[i]=Convert.ToByte(fi.StrArr[i]);
}
//your uploaded File buffer is ready as myFileByte
//proceeding operations are most welcome here......
.........
}
At Client Side:
public void UploadMyFile()
{
//Take the InputStream from the selected File as iStream;
int len=(int)iStream.length;
byte[] buffer=new byte[len];
string[] MyStrArr=new string[len];
for(int i=0;i<len;i++)
{
MyStrArr[i]=Convert.ToString(buffer[i]);
}
//Here your string array is ready to send to the WCF Service....
//I m confident this code will work perfectly with some file limitation consideartions.
}

Related

Restful WCF Service - returning byte[]?

I'm working with a RESTful WCF service. One of the service methods returns byte[] (which contains a file).
On the client side, I have some code that uses the WebRequest class to invoke that particular service method. Using the WebRequest, I'm getting the response stream like:
Stream stream = webReq.GetResponse().GetResponseStream();
From this stream, I am then reconstructing a byte[] and then outputting the File locally. The problem is that the reconstructed file on the client-side doesn't resemble the file that was returned from the service side (I get a corrupt PDF file that is much larger in size than the one sent from the service side). Just before the service method returns the byte[], I outputted that byte[] to disk on the service side and it created the file fine... This points to something going wrong between that method returning the byte[] and my client side reconstructing the byte[] from a Stream on the client side... to reconstruct the byte[] from the Stream, I'm using the following method which someone posted in the past on stackoverflow:
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16*1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Any ideas what could be going wrong?
I guess that the response from the server contains some envelope in addition to the raw bytes. Like a XML envelope or something. Which would of course suppose that the bytes are base64 encoded string in the response because you cannot store binary data into XML. It would also explain why you are getting a bigger buffer on the client than the actual PDF that the server has sent.
This will of course depend on what binding your WCF service uses and how is it configured. When you dump the contents of the MemoryStream you are reading on the client what exactly do you see? This should give you further hints on how the actual PDF file is encoded in the HTTP response body.

resuming files when uploading to a server using wcf

I'm using WCF and I am trying to resume my upload with next code on the server app:
class DataUploader : IDataUploader
{
public void Upload(UploadMessage msg)
{
int speed = msg.AvgSpeed * 1024; // convert to KB
Stream stream= msg.DataStream;
string name = msg.VirtualPath;
int seekPoint; // this is get reading the partial uploaded file
using (FileStream fs = new FileStream(#"C:\savedfile.dat, FileMode.Append))
{
int bufferSize = 4 * 1024; // 4KB buffer
byte[] buffer = new byte[bufferSize];
int bytes;
while ((bytes = stream.Read(buffer, startPoint, bufferSize)) > 0)
{
fs.Write(buffer, 0, bytes);
fs.Flush();
}
stream.Close();
fs.Close();
}
}
}
I'm trying to begin to read the stream from a specified point (startPoint) cause the first bytes have already been uploaded. So I could append only remaining bytes to the file partially uploaded. By this way i get an error with the buffersize and can't use seeking because a method not supported exception so I think maybe this approach is not right. Help!!
My service contract:
[ServiceContract]
interface IDataUploader
{
[OperationContract]
void Upload(UploadMessage msg);
}
My message contract:
[MessageContract]
public class UploadMessage
{
[MessageHeader(MustUnderstand = true)]
public string VirtualPath { get; set; }
[MessageHeader(MustUnderstand = true)]
public int AvgSpeed { get; set; }
[MessageBodyMember(Order = 1)]
public Stream DataStream { get; set; }
}
It seems like you are using a standard soap message rather than the streaming binding. Check out the this link
If you don't want to use WCF's streaming api, which is proprietary to WCF, I would considering creating a 'chunking' method from the client if the client is uploading the file. Similar to how FTP can resume, I would query the server to see the current offset, send up a block or set of blocks, write them to my persistance (memory, db, file, etc), and then continue with multiple calls from the client sending smaller blocks (be careful of serialization as that can introduce unnecessary delays). This technique be something you want to investigate since it sounds like the client is 'streaming' to the server.
Btw, you may want to look at the following article to determine if your use of MessageContract is appropriate, as opposed to a DataContract.
http://blogs.msdn.com/b/drnick/archive/2007/07/25/data-contract-and-message-contract.aspx
If you want resume functionality you cannot do it this way. Your client must send the file in chunks and it must maintain the id of last successfully updated chunk. The service must process chunks and append them to storage.
If the most basic implementation it means that your client must divide file into chunks of well known size and call the upload operation for each chunk. The message must also contains the chunk Id and probably also chunk size (or something identifying the last chunk). This can be also combined with reliable session to allow automatic resend of lost chunks and to enforce in order delivery.
There is also example of channel implementation which does chunking internally.

WCF Streaming: Last byte is lost

I have a WCF service which has one method returning a stream.
[ServiceContract]
public interface IService1
{
[OperationContract]
MyMessage Test();
}
Now, MyMessage is defined like this:
[MessageContract]
public class MyMessage
{
public MyMessage(string file)
{
this.Stream = File.OpenRead(file);
this.Length = Stream.Length;
}
[MessageHeader]
public long Length;
[MessageBodyMember]
public Stream Stream;
}
Peachy.
The service has a streamed response, using basicHttpBinding. This is the binding configuration:
<basicHttpBinding>
<binding name="BasicStreaming"
maxReceivedMessageSize="67108864" maxBufferSize="65536" transferMode="StreamedResponse" />
</basicHttpBinding>
Now this is where things start to get interesting. When calling this service, the last byte is lost if i read the stream in a particular way. Here is the code illustrating the two different approaches:
Service1Client client = new Service1Client();
//this way the last byte is lost
Stream stream1;
var length = client.Test(out stream1);
var buffer1 = new byte[length];
stream1.Read(buffer1, 0, (int)length);
File.WriteAllBytes("test1.txt", buffer1);
stream1.Close();
//here i receive all bytes
Stream stream2;
length = client.Test(out stream2);
var buffer2 = new byte[length];
int c = 0, b;
while ((b = stream2.ReadByte()) != -1)
{
buffer2[c++] = (byte)b;
}
File.WriteAllBytes("test2.txt", buffer2);
stream2.Close();
I am sure I'm missing something, but can anyone point out to me exactly why this is happening? The biggest problem is that in another service, whichever way i read the stream, i lose the last byte, but maybe by identifying the problem here I can solve that one too.
Technical details:
IIS 7.0
.NET 3.5
Basic HTTP Binding
Streamed response mode
Note: I have uploaded the project isolating the problem, so anyone can try it out: mediafire
I don't have an exact answer as to why this works (my brain isn't fully engaged at the moment), however this DOES work:
var buffer1 = new byte[length+2];
stream1.Read(buffer1, 0, buffer1.Length);
(and, yes, you end up with a buffer that's too large. It's just a starting point for further thinking)
In testing I found +1 isn't large enough, but +2 is.
Why passing a count of (length + 1)? It should be length, otherwise you are attempting to read one more byte than what is available.

Getting around base64 encoding with WCF

I'm using WCF, REST and "pretty URI's" as shown in this blog post with the Online Template for VS 2010 .NET 4.0:
http://christopherdeweese.com/blog2/post/drop-the-soap-wcf-rest-and-pretty-uris-in-net-4
I have one problem though.
I want to return a a raw byte[] array but it automatically gets base64 encoded.
Unfortunately for my program base64 encoding is not acceptable because it will be too computationally intensive.
Is there a way for me to tell WCF NOT to base64 encode?
[WebGet(UriTemplate = "{id}")]
public byte[] Get(string id)
{
byte[] data = new byte[1024];
return data;
}
Appears to my web browser as:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==
Use Stream as your return type.

WCF streaming files

I need to pass a memory stream to the WCF server , how do i need to add this data type in my data contract.
I will eventually need to convert this to a memory stream and pass it on to my service layer.
datacontact[DataMember]
Stream str = null;
public Stream File
{
get { return str; }
set { str = value; }
}
Here is the WCF Streaming page. I'm not really sure if (how) you can do this with a DataContract, the normal way is to specify streams in the OperationContract. Wouldn't that work for you?
Short summary:
Sender produces the Stream
Sender does not Close the Stream
Receiver does close the stream
Set the MaxReceivedMessageSize property of the binding to a value larger than the largest item you wish to transfer.