Increasing Size Limit with WCF

Posts   
 
    
Cookie avatar
Cookie
User
Posts: 4
Joined: 29-Nov-2013
# Posted on: 29-Nov-2013 04:17:46   

I am using WCF to save Entities through a Web Service. Trying to save a screenshot as a byte[] into an entity, but keeps returning " The remote server returned an unexpected response: (413) Request Entity Too Large."

I've tried increasing the size limit by editing the maxRequestLength, MaxBufferSize, MaxRecievedMessageSize all to 2147483647 with no change in actual limit.

Not all that familiar with Web Services so any help with the proper way to do this is appreciated.

Here's the Error:

System.ServiceModel.ProtocolException: The remote server returned an unexpected response: (413) Request Entity Too Large. ---> System.Net.WebException: The remote server returned an error: (413) Request Entity Too Large.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---

Server stack trace: 
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory`1 factory, WebException responseException, ChannelBinding channelBinding)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]: 
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at TPG.Service.ITpgDataService.SaveErrorLogEntity(ErrorLogEntity& entErrorLog)
   at TPG.WindowsClient.Program.Application_ThreadException(Object sender, ThreadExceptionEventArgs e) in e:\TPG\TPG.WindowsClient\Program.cs:line 131

Here's the save function

      ErrorLogEntity entError = new ErrorLogEntity();
                entError.ErrorText = e.Exception.ToString();
                entError.ErrorScreenCap = stream.GetBuffer(); //Database Data Type varbinary(MAX)
 wcf.dataService.SaveErrorLogEntity(ref entError); //calls to the service via [OperationContract] in an interface project.


        public bool SaveErrorLogEntity(ref ErrorLogEntity entity)
        {
            bool Success = false;
            using (DataAccessAdapter adapter = new DataAccessAdapter())
            {
                Success = adapter.SaveEntity((ErrorLogEntity)entity, true);
            }
            return Success;
        }

Here's the wcf.cs file in the Client to create the connection to the service

    class wcf
    {
        public static TPG.Service.ITpgDataService dataService;

        public static void InitialiseWcf(string url)
        {
            EndpointAddress endpointAddress = new EndpointAddress(url);

            //check if we have to make a http or https binding to the webservice
            if (url.StartsWith("https"))
            {
                BasicHttpsBinding basicHttpsBinding = new BasicHttpsBinding();
                basicHttpsBinding.Name = "basicHttpsBinding";
                basicHttpsBinding.MaxReceivedMessageSize = 2147483647;
                basicHttpsBinding.MaxBufferSize = 2147483647;
                ChannelFactory<TPG.Service.ITpgDataService> cf = new ChannelFactory<TPG.Service.ITpgDataService>(basicHttpsBinding, endpointAddress);
                dataService = cf.CreateChannel();
            }
            else {
                BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
                basicHttpBinding.Name = "basicHttpBinding";
                basicHttpBinding.MaxReceivedMessageSize = 2147483647;
                basicHttpBinding.MaxBufferSize = 2147483647;
                //basicHttpBinding.ReaderQuotas.MaxStringContentLength = 2147483647;
                ChannelFactory<TPG.Service.ITpgDataService> cf = new ChannelFactory<TPG.Service.ITpgDataService>(basicHttpBinding, endpointAddress);
                dataService = cf.CreateChannel();
            }
        }
    }

And here's the full Web.Config in the Web Service Project

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="ConnectionString.SQL Server (SqlClient)" value="data source=localhost;initial catalog=ThePestGuys;integrated security=SSPI;persist security info=False;packet size=32768;"/> <!--4096-->
  </appSettings>
  <system.web>
     <httpRuntime maxRequestLength="2147483647" useFullyQualifiedRedirectUrl="true"   executionTimeout="14400"/>
    <compilation debug="true" targetFramework="4.0"/>
    <!--<httpRuntime/>-->
    
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpsBinding" scheme="https"/>
      <add binding="basicHttpBinding" scheme="http"/>
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="false" multipleSiteBindingsEnabled="true"/>

      <bindings>
        <webHttpBinding >
          <binding name="FileTransferServicesBinding" maxBufferSize="2147483647"  maxReceivedMessageSize="2147483647">
            <readerQuotas maxStringContentLength="2147483647"  maxArrayLength="2147483647" />
          </binding>
        </webHttpBinding>
      </bindings>

    <services/>
  </system.serviceModel>
  <system.webServer>
    
    <modules runAllManagedModulesForAllRequests="true"/>
    <security>
      <requestFiltering allowDoubleEscaping="true">
        <requestLimits maxAllowedContentLength="2147483647"/>
        <fileExtensions allowUnlisted="true"/>
        <verbs allowUnlisted="true"/>
      </requestFiltering>
    </security>
    <!--
        To browse web app root directory during debugging, set the value below to true.
        Set to false before deployment to avoid disclosing web app folder information.
      -->
    <directoryBrowse enabled="true"/>
  </system.webServer>
</configuration>

Using: .NET Version 4.0 LLBLGen Pro Version 3.5 Final (Adapter) Microsoft SQL Server 2012 (SQL Server 11.0.2100) Visual Studio 2012

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 29-Nov-2013 07:05:27   

Yes this is a WCF thing. I think maybe you are missing some config values on readerQuotas. Please try something like this:

<basicHttpBinding>
  <binding
    name="CoreSoapSecure"
    closeTimeout="00:01:00"
    openTimeout="00:01:00"
    receiveTimeout="00:10:00"
    sendTimeout="00:01:00"
    allowCookies="false"
    bypassProxyOnLocal="false"
    hostNameComparisonMode="StrongWildcard"
    maxBufferSize="524288"
    maxBufferPoolSize="524288"
    maxReceivedMessageSize="524288"
    messageEncoding="Text"
    textEncoding="utf-8"
    transferMode="Buffered"
    useDefaultWebProxy="true">
    <readerQuotas
      maxDepth="2147483647"
      maxStringContentLength="2147483647"
      maxArrayLength="2147483647"
      maxBytesPerRead="2147483647"
      maxNameTableCharCount="2147483647" />
    <security mode="Transport">
      <transport
        clientCredentialType="None"
        proxyCredentialType="None"
        realm="" />
      <message clientCredentialType="UserName" algorithmSuite="Default" />
    </security>
  </binding>

</basicHttpBinding>

... investigate the configuration, as it might be not suitable for you. If you specify the configuration in your config, it's not needed to write it again in code. Be sure that you are loading the configuration when using the service.

David Elizondo | LLBLGen Support Team
Cookie avatar
Cookie
User
Posts: 4
Joined: 29-Nov-2013
# Posted on: 29-Nov-2013 09:11:55   

I've added this using both my own binding name and yours, without the security. Still no luck.

I just tried adding the configuration name when creating the HTTP Binding in the client. Changed it in wcf.cs to this

BasicHttpBinding basicHttpBinding = new BasicHttpBinding("basicHttpBinding");

and instead I get this Error

System.Collections.Generic.KeyNotFoundException was unhandled
  HResult=-2146232969
  Message=No elements matching the key 'basicHttpBinding' were found in the configuration element collection.
  Source=System.ServiceModel
  StackTrace:
       at System.ServiceModel.Configuration.ServiceModelConfigurationElementCollection`1.get_Item(Object key)
       at System.ServiceModel.BasicHttpBinding.ApplyConfiguration(String configurationName)
       at System.ServiceModel.BasicHttpBinding..ctor(String configurationName)
       at TPG.WindowsClient.wcf.InitialiseWcf(String url) in e:\TPG\TPG.WindowsClient\wcf.cs:line 34
       at TPG.WindowsClient.Program.Main() in e:\TPG\TPG.WindowsClient\Program.cs:line 39
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel)
       at System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()
       at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
       at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext)
       at System.Activator.CreateInstance(ActivationContext activationContext)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

There's got to be something not linking up here and I'm getting stumped as to what.

daelmo wrote:

Yes this is a WCF thing. I think maybe you are missing some config values on readerQuotas. Please try something like this:

<basicHttpBinding>
  <binding
    name="CoreSoapSecure"
    closeTimeout="00:01:00"
    openTimeout="00:01:00"
    receiveTimeout="00:10:00"
    sendTimeout="00:01:00"
    allowCookies="false"
    bypassProxyOnLocal="false"
    hostNameComparisonMode="StrongWildcard"
    maxBufferSize="524288"
    maxBufferPoolSize="524288"
    maxReceivedMessageSize="524288"
    messageEncoding="Text"
    textEncoding="utf-8"
    transferMode="Buffered"
    useDefaultWebProxy="true">
    <readerQuotas
      maxDepth="2147483647"
      maxStringContentLength="2147483647"
      maxArrayLength="2147483647"
      maxBytesPerRead="2147483647"
      maxNameTableCharCount="2147483647" />
    <security mode="Transport">
      <transport
        clientCredentialType="None"
        proxyCredentialType="None"
        realm="" />
      <message clientCredentialType="UserName" algorithmSuite="Default" />
    </security>
  </binding>

</basicHttpBinding>

... investigate the configuration, as it might be not suitable for you. If you specify the configuration in your config, it's not needed to write it again in code. Be sure that you are loading the configuration when using the service.

NMackay
User
Posts: 138
Joined: 31-Oct-2011
# Posted on: 29-Nov-2013 12:24:44   

It could be an IIS configuration issue, we had something similar I seem to remember when saving images.

It's discussed here, see the 2nd answer.

http://stackoverflow.com/questions/10122957/iis7-413-request-entity-too-large-uploadreadaheadsize.

It might help.

Walaa avatar
Walaa
Support Team
Posts: 14950
Joined: 21-Aug-2005
# Posted on: 29-Nov-2013 15:03:16   
maxBufferSize="524288"
maxBufferPoolSize="524288"
maxReceivedMessageSize="524288"

Also try increasing the above values as well.

Cookie avatar
Cookie
User
Posts: 4
Joined: 29-Nov-2013
# Posted on: 02-Dec-2013 02:41:21   

OK, I've solved the problem! Turns out I didnt have to touch Web.Config after all. Since I was creating the binding settings in the client programmatically it needed all its values set in the object from there before it was used in the service.

So, I added the System.Runtime.Serialization reference to create a new System.Xml.XmlDictionaryReaderQuotas object and added it to basichttpbinding.ReaderQuotas. Edit the values in the new ReaderQuota object and thats it. Nothing else required.

It was as simple as this

                BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
                XmlDictionaryReaderQuotas reader = new XmlDictionaryReaderQuotas();
                basicHttpBinding.MaxBufferSize = 2147483647;
                basicHttpBinding.MaxBufferPoolSize = 2147483647;
                basicHttpBinding.MaxReceivedMessageSize = 2147483647;
                reader.MaxStringContentLength = 2147483647;
                reader.MaxDepth = 2147483647;
                reader.MaxArrayLength = 2147483647;
                reader.MaxBytesPerRead = 2147483647;
                reader.MaxNameTableCharCount = 2147483647;
                basicHttpBinding.ReaderQuotas = reader;

Thanks for the help, and I hope this will help anybody else creating a config in this way.

Cookie avatar
Cookie
User
Posts: 4
Joined: 29-Nov-2013
# Posted on: 02-Dec-2013 03:09:22   

I'll Revise that. Needed changes in BOTH client config and server config in the wcf and web.config files. You'll get the same error if you're missing one or the other. Needs to be the same change for both.

Cookie wrote:

OK, I've solved the problem! Turns out I didnt have to touch Web.Config after all. Since I was creating the binding settings in the client programmatically it needed all its values set in the object from there before it was used in the service.

So, I added the System.Runtime.Serialization reference to create a new System.Xml.XmlDictionaryReaderQuotas object and added it to basichttpbinding.ReaderQuotas. Edit the values in the new ReaderQuota object and thats it. Nothing else required.

It was as simple as this

                BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
                XmlDictionaryReaderQuotas reader = new XmlDictionaryReaderQuotas();
                basicHttpBinding.MaxBufferSize = 2147483647;
                basicHttpBinding.MaxBufferPoolSize = 2147483647;
                basicHttpBinding.MaxReceivedMessageSize = 2147483647;
                reader.MaxStringContentLength = 2147483647;
                reader.MaxDepth = 2147483647;
                reader.MaxArrayLength = 2147483647;
                reader.MaxBytesPerRead = 2147483647;
                reader.MaxNameTableCharCount = 2147483647;
                basicHttpBinding.ReaderQuotas = reader;

Thanks for the help, and I hope this will help anybody else creating a config in this way.