none
WCF not returning any error when downloading via Stream and error occurs in the middle RRS feed

  • Question

  • i wonder if anyone encountered this:

    i have a WCF service that returns a Stream (custom i've created).

    during the download, it may be that an error occurs, and i want the client to know it.

    the problem is, that when error occurs during download, the client stream receives "0 bytes" from the Stream.Read, and finishes (successfully) instead of exception / any other error.

    is there any solution for this? it seems that WCF ignores any read errors and just closes the stream afterward.

    code:

    server:

    public interface IService1
       {
    
          [OperationContract]
          [WebInvoke(Method = "GET",
             BodyStyle = WebMessageBodyStyle.Bare,
             ResponseFormat = WebMessageFormat.Json,
             UriTemplate = "Data")]
             Stream GetFileStream();
    }
    
    
    public class Service1 : IService1
       {
    
          public System.IO.Stream GetFileStream()
          {
             return new MyCustomStream();         
          }
    }

    public class MyCustomStream : Stream
       {
          FileStream _Stream;
    
          private bool wasRead = false;
          public MyCustomStream()
          {
             _Stream = new FileStream(@"someFileOnDisk", FileMode.Open,
                                  FileAccess.Read, FileShare.ReadWrite);
    
          }
    
    ~MyCustomStream()
          {
             if (_Stream != null)
             {
                _Stream.Dispose();
             }
    
          }
    
    public override int Read(byte[] buffer, int offset, int count)
          {
             if (!wasRead)
             {
                wasRead = true;
                return _Stream.Read(buffer, offset, count);
             }
             else
             {
                throw new Exception("ERROR!!!!");
             }         
          }
    
    public override void Close()
          {
             _Stream.Close();
          }

    internal static HttpWebRequest InitializeRequest(Uri url, string i_RelativeURL, int i_Timeout, string i_MethodType, string i_ContentType)
          {
    
             System.Net.HttpWebRequest newRequest = (HttpWebRequest)WebRequest.Create(CombineURI(url.AbsoluteUri, i_RelativeURL));
             newRequest.Proxy = null; // We are not using proxy
             newRequest.Timeout = i_Timeout;
             newRequest.Method = i_MethodType;
             newRequest.ContentType = i_ContentType;
    
             return newRequest;
          }
    
    static void Main(string[] args)
          {
             HttpWebRequest request = InitializeRequest(new Uri(@"http://localhost/WCFTest/Service1.svc"), "data", 999999, "GET", "application/json");
    
             using (WebResponse response = request.GetResponse())
             {
                using (Stream curStream = response.GetResponseStream())
                {
                   byte[] buffer = new byte[2000000]; // ~2MB
                   int read = curStream.Read(buffer, 0, buffer.Length);
                   int blockToWrite = read;
                   while (read > 0)
                   {
                      // If we reach to ~1MB of data - write it to the disk
                      if (blockToWrite >= 1000000)
                      {
                         blockToWrite = 0;
                      }
    
                      read = curStream.Read(buffer, blockToWrite, buffer.Length - blockToWrite); // Returns 0 if exception occurs on server side.
                      blockToWrite += read;
                   }
                }
             }
    }

    Sunday, June 28, 2015 11:49 AM

All replies

  • Hi Ariebck,

    According to your discription, in my opinion is that  you can add Try catch sentence in your service and client. May be it looks like this:       

    try 

       {

             HttpWebRequestrequest =InitializeRequest(newUri(@http://localhost/WCFTest/Service1.svc),"data",999999,"GET","application/json");

             using(WebResponseresponse =request.GetResponse())

            {

                using(StreamcurStream =response.GetResponseStream())

             {

                   byte[]buffer =newbyte[2000000];// ~2MB

                   intread =curStream.Read(buffer,0,buffer.Length);

                  intblockToWrite =read;             

                  while (read > 0)

                   {

                       // If we reach to ~1MB of data - write it to the disk

                      if(blockToWrite >=1000000)

                    {

                         blockToWrite =0;

                      }

                        read =curStream.Read(buffer,blockToWrite,buffer.Length-blockToWrite);// Returns 0 if exception occurs on server side.

                        blockToWrite +=read

                    }

                }    

           }   

         catch (Exception ex)

        {         // Trap the error, if any.  

           Console.Writeline("Error : "+ ex.Message);  

       }

    Then,may be you should modify your OperationContract in your server side code like below:

     [OperationContract]
           [WebInvoke(Method = "GET",
           BodyStyle = WebMessageBodyStyle.Wrapped,
           RequestFormat = WebMessageFormat.Json,
           ResponseFormat = WebMessageFormat.Json,
           UriTemplate = "/GetFileStream")]
           Stream GetFileStream();

    #Try catch Reference

    https://msdn.microsoft.com/en-us/library/0yd65esw(VS.80).aspx

    I hope that will be helpful to you.

    Best  Regards,

    Tracy DJ

    Monday, June 29, 2015 7:49 AM
    Moderator
  • Hi Tracy,

    the issue is not that i'm not "catching" exceptions, the issue is that whenever the server "read" fails - the client receives 0 bytes from the stream - and then the client thinks the stream has finished successfully.

    your solution will of course not work, as the client doesn't throw any exception.

    you can try the code yourself, throw exception on the "Stream.Read" in the server side. no matter what you do - the client side will get 0 bytes as read.

    Monday, June 29, 2015 8:45 AM
  • Hi Arielbck,

    According to this case, I'd like to suggest you to check your code.May be you can check your data format,

    May be it looks like this:

    req.ContentType = "application/octet-stream";

    You can try it.

    For more information, please refer to the following links:

    https://msdn.microsoft.com/en-us/library/cc656724.aspx?f=255&MSPPError=-2147217396

    Best Regards,

    Tracy Dj.


    Friday, July 3, 2015 2:49 AM
    Moderator
  • hi Tracy,

    This of course did not work. the client just don't realize that the server threw error. it just reads 0 bytes.

    i have a feeling it's a bug in .net 3.5, because if i moved to 4.5, i do get an error - but sadly the error is IOException from the stream, and i have no idea which error occured on the server.

    if you have time, i've written my complete solution, try to compile it in .net 3.5 server/client - and you'll see you have the same behavior - no errors in the client side.

    Sunday, July 5, 2015 8:20 AM
  • Hi Arielbck,

    First, we need to make sure that following point:

    1.In the web.config , we should add   maxBufferSize  maxBufferPoolSize  maxReceivedMessageSize

    in our bindings both of service and client.

    2.May be the files not be found.

    3.The transferMode must be Streamed in the web.config.

    For more information,please refer to the following articals:

    http://stackoverflow.com/questions/16397534/ioexception-on-streamed-file-upload-via-wcf-over-http

    http://www.seesharpdot.net/?p=214

    Best Regards,

    Tracy Dj


    Best Regards, Tracy Dj

    Monday, July 6, 2015 9:59 AM
    Moderator
  • Hi Tracy,

    again, as i said, i don't have any problems with message size. the Web.config has streaming configured

    part of the web config:

            <binding name="webDownloadHttpBindingConfig" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647" transferMode="Streamed">          <readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647"/>        </binding>

    i'm throwing exception in the server side on purpose, and in .net 3.5 it's ignored, and in 4.5 i get IOException.

    i can't seem to get the correct WebFaultException / FaultException i'm throwing.

    I'm not sure what information i should add besides that...

    Monday, July 6, 2015 3:13 PM
  • hi Arielbck,
       According to your case, you can try like below :

    static void Main(string[] args) { HttpWebRequest request = InitializeRequest(new Uri(@"http://localhost/WCFTest/Service1.svc"), "data", 999999, "GET", "application/json");

    const int bufferSize = 2000000;// ~2MB using (WebResponse response = request.GetResponse()) { using (Stream curStream = response.GetResponseStream()) { byte[] buffer = new byte[bufferSize]; int read = curStream.Read(buffer, 0, bufferSize); int blockToWrite = read; while (read > 0) { // If we reach to ~1MB of data - write it to the disk if (blockToWrite >= 1000000) { //Need to declare for output stream & write like below
    //curoutputStream.Write(buffer, blockToWrite, bufferSize);

    blockToWrite =0; }

    read = curStream.Read(buffer, blockToWrite, bufferSize-blockToWrite); blockToWrite += read; } } }
    }

    Thursday, July 9, 2015 6:27 AM
  • Hi Edwin,

    the only difference in your code is that you added the size as a const.

    anyway, i've tested your code and as expected, same result.

    no exception is received in the client side.

    did you try running your code and got the designated exception?

    i don't think any client side configuration can help resolve this case, and i really start to believe this is a .net bug.

    Thursday, July 9, 2015 10:13 AM