none
Problem sending very large files to WCF Restful Web Service.

    Question

  • Hi,

    I having created a Restful Web Service under Windows Azure.

    I'm am caught with this problem sending larger files over the rest web service.

    My remote database is having a attribute under the Datatype of VarBinary(MAX).
    By using Varbinary(MAX), it means my database can store very very large (up to 2 gb) file right?

    The problem is:
    When i try to do a POST method in XML format via Restful WebService with a 2kb file, i can successfully post
    and store the file into the database, when i change the file into a 500kb file and using exactly
    the same code, i am unable to do POST.
    I will get a 400 bad command from the other side.

    Does anyone know where could have gone wrong? Why is it that a small file can be sent over but not a big file?
    Below is my code snippet when i do POST:

    In C#
    FileStream fsBLOBFile = 
    new FileStream("C:/smile2.jpg", 
                             FileMode.Open, 
                             FileAccess.Read);
    
    Byte[] ImageData = new Byte[fsBLOBFile.Length];
    fsBLOBFile.Read(ImageData, 0, ImageData.Length);
    fsBLOBFile.Close();
    
    FileStream fsBLOBFile2 = 
    new FileStream("C:/Record000.amr", 
                            FileMode.Open, 
                            FileAccess.Read);
    Byte[] VoiceData = new Byte[fsBLOBFile2.Length];
    fsBLOBFile2.Read(VoiceData, 0, VoiceData.Length);
    fsBLOBFile2.Close();
    
    
    //My own class
    Activity evt = new Activity(1001, "A1B2C3D4",
                                            "Incident", "2",
                                            date, "ChipID-88",
                                            "TP001", "1",
                                            ImageData, VoiceData,
                                            //VoiceData, ImageData,
                                            "5", "From C-Sharp");
    
    DataContractSerializer serializer
                    = new DataContractSerializer(typeof(Activity));
    
    MemoryStream ms = new MemoryStream();
    serializer.WriteObject(ms, evt);
    ms.Position = 0;
    StreamReader reader = new StreamReader(ms);
    string str = reader.ReadToEnd();
    client.Headers.Add("Content-Type", "application/xml; charset=utf-8");
    
    WebClient client = new WebClient();
    result = client.UploadString
                ("http://127.0.0.1:81/EventHandler.svc/PostActivity", str);




    Can anyone help me on this? I seriously need some help here as i am working alone on this project..
    Really grateful for any help... Please..

    RTC
    Friday, August 21, 2009 2:07 AM

Answers

  • Hi,

    Well... your tutorial is asking you to use the WebServiceHostFactory class, and that's why they also tell you to comment the configuration section for WCF.
    The WebServiceHostFactory is a shortcut way to create and expose WCF services by using the WebHttpBinding (for the WCF Web model), so you don't need any configuration for that.

    You have 2 options here.

    1. Keep the configuration section commented and extend the WebServiceHostFactory with your own factory class to customize the binding settings. You should create something like this class:

    public class MyWebServiceHostFactory : WebServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses);
            WebHttpBinding webBinding = (WebHttpBinding)host.Description.Endpoints[0].Binding;
            webBinding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas() {
                                                        MaxArrayLength = 0,
                                                        MaxBytesPerRead = 0,
                                                        MaxDepth = 0,
                                                        MaxStringContentLength = 0
                                                    };
            return host;
        }
    }
    Then in the Factory attribute of the ServiceHost directive.. instead of using the WebServiceHostFactory you should specify your class.


    2. Revert to the default ServiceHostFactory and uncomment the configuration section. This would be the same as creating any WCF service but you should specify the webHttpBinding in your endpoint configuration (note in the other post you were using the wsHttpBinding and that's why it doesn't work). Configuration should look like this:

    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="Rest_EventHandler_WebRole.EventHandlerBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
               <behavior name="webBehavior">
                    <enableWebScript />
               </behavior>
            </endpointBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="Rest_EventHandler_WebRole.EventHandlerBehavior"
                name="Rest_EventHandler_WebRole.EventHandler">
                <endpoint address="" binding="webHttpBinding" contract="Rest_EventHandler_WebRole.IEventHandler">
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
            </service>
        </services>
    </system.serviceModel>

    Hope it helps.
    Regards,
    Rodrigo.
    Friday, August 21, 2009 1:21 PM
  • .... I forgot to add the following in the config:


    <bindings>
        <webHttpBinding>
            <binding name="webBinding">
              <readerQuotas maxArrayLength="0" maxBytesPerRead="0" maxStringContentLength="0" />
            </binding>
        </webHttpBinding>
     </bindings>

    And then make sure to add the following to the <endpoint> element: bindingConfiguration="webBinding" behaviorConfiguration="webBehavior".

    Finally adjust the reader quotas values as required (instead of 0).

    Regards,
    Rodrigo.
    Friday, August 21, 2009 1:26 PM

All replies

  • Hi,

    Did you configure the quotas (message size restrictions) for your service?... Make sure you configure your binding with these values big enough to enable larger messages to be sent/received by your service.
    Please take a look here: http://msdn.microsoft.com/en-us/library/ms731325.aspx

    Further reference on sending large files including how to configure streaming can be found here: http://msdn.microsoft.com/en-us/library/ms733742.aspx

    Hope it helps.
    Regards,
    Rodrigo.
    Friday, August 21, 2009 2:16 AM
  • Hi Rodrigo,

    I know i must set the reader quotas. But i have actually commented away the System.ServiceMode section in my service side web.config file.

    The reason why i comment away is because i wasn't able to launch my service (i'm creating WCF in Windows Azure).

    I have post another problem which i think is somehow linked to this problem,
    can i give you the url help me see if its the same problem?

    http://social.msdn.microsoft.com/Forums/en-US/windowsazure/thread/0631a639-cdc5-4bd9-8a49-fdf951a45d2f


    I remove away System.serviceModel section because i was following a tutorial which ask me to do it..
    i've added a Factory attribute in my .svc file's Markup and my service can work.

    Really grateful for your help..

    RTC
    Friday, August 21, 2009 2:50 AM
  • Hi,

    is anyone able to give me a help or 2 here?

    I really need help in this area as i am the only one working on this and there is
    no real life person for me to consult help with..

    Badly need some advices here..

    A million thanks..
    Friday, August 21, 2009 12:38 PM
  • Hi,

    Well... your tutorial is asking you to use the WebServiceHostFactory class, and that's why they also tell you to comment the configuration section for WCF.
    The WebServiceHostFactory is a shortcut way to create and expose WCF services by using the WebHttpBinding (for the WCF Web model), so you don't need any configuration for that.

    You have 2 options here.

    1. Keep the configuration section commented and extend the WebServiceHostFactory with your own factory class to customize the binding settings. You should create something like this class:

    public class MyWebServiceHostFactory : WebServiceHostFactory
    {
        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses);
            WebHttpBinding webBinding = (WebHttpBinding)host.Description.Endpoints[0].Binding;
            webBinding.ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas() {
                                                        MaxArrayLength = 0,
                                                        MaxBytesPerRead = 0,
                                                        MaxDepth = 0,
                                                        MaxStringContentLength = 0
                                                    };
            return host;
        }
    }
    Then in the Factory attribute of the ServiceHost directive.. instead of using the WebServiceHostFactory you should specify your class.


    2. Revert to the default ServiceHostFactory and uncomment the configuration section. This would be the same as creating any WCF service but you should specify the webHttpBinding in your endpoint configuration (note in the other post you were using the wsHttpBinding and that's why it doesn't work). Configuration should look like this:

    <system.serviceModel>
        <behaviors>
            <serviceBehaviors>
                <behavior name="Rest_EventHandler_WebRole.EventHandlerBehavior">
                    <serviceMetadata httpGetEnabled="true" />
                    <serviceDebug includeExceptionDetailInFaults="false" />
                </behavior>
            </serviceBehaviors>
            <endpointBehaviors>
               <behavior name="webBehavior">
                    <enableWebScript />
               </behavior>
            </endpointBehaviors>
        </behaviors>
        <services>
            <service behaviorConfiguration="Rest_EventHandler_WebRole.EventHandlerBehavior"
                name="Rest_EventHandler_WebRole.EventHandler">
                <endpoint address="" binding="webHttpBinding" contract="Rest_EventHandler_WebRole.IEventHandler">
                    <identity>
                        <dns value="localhost" />
                    </identity>
                </endpoint>
                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
            </service>
        </services>
    </system.serviceModel>

    Hope it helps.
    Regards,
    Rodrigo.
    Friday, August 21, 2009 1:21 PM
  • .... I forgot to add the following in the config:


    <bindings>
        <webHttpBinding>
            <binding name="webBinding">
              <readerQuotas maxArrayLength="0" maxBytesPerRead="0" maxStringContentLength="0" />
            </binding>
        </webHttpBinding>
     </bindings>

    And then make sure to add the following to the <endpoint> element: bindingConfiguration="webBinding" behaviorConfiguration="webBehavior".

    Finally adjust the reader quotas values as required (instead of 0).

    Regards,
    Rodrigo.
    Friday, August 21, 2009 1:26 PM