简体   繁体   中英

WCF 4.5: An unexpected error occurred: The remote server returned an unexpected response: (413) Request Entity Too Large

I know that this question has been asked to death, yet the answer remains elusive. I've been through numerous posts with suggested solutions but this error continues to plague me. Any help would be greatly appreciated.

I have a .Net 4.5 WCF service hosted on IIS which is consumed by an MVC5 web site on another IIS box. Communication works fine for the most part, but I need to allow the web site to upload files to the WCF service and the calls are all bombing out with the following error:

An unexpected error occurred: The remote server returned an unexpected response: (413) Request Entity Too Large

The methods being called in the web service take a single POCO as a parameter. The POCO contains a number of properties including a byte array for the contents of the file being uploaded. For example:

public class ProofOfAddressRequest : RequestBase
{
    public string AddressLine1 { get; set; }
    public string AddressLine2 { get; set; }
    public string Region { get; set; }
    public string City { get; set; }
    public string PostCode { get; set; }
    public string Country { get; set; }
    public string FileName { get; set; }
    public byte[] FileBytes { get; set; }
}

public ProofOfAddressResponse SubmitProofOfAddress(ProofOfAddressRequest data)
{
    // TODO... Save the record
}

The web site's web.config is currently as follows:

<configuration>
  <configSections/>

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IUserService" maxBufferPoolSize="2097152" maxBufferSize="2097152" maxReceivedMessageSize="2097152">
          <readerQuotas maxDepth="32" maxStringContentLength="2097152" maxArrayLength="2097152" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
          <security mode="None"/>
        </binding>
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:58354/Services/UserService.svc"
        binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IUserService"
        contract="UserService.IUserService" name="BasicHttpBinding_IUserService" />
    </client>
  </system.serviceModel>

  <system.web>
    <customErrors mode="Off" />
    <authentication mode="None" />
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" maxRequestLength="4096"/>
  </system.web>

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-5.0.0.0" newVersion="5.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

</configuration>

And the web service's web.config is:

<configuration>

  <configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>  

  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" maxRequestLength="4096"/>
  </system.web>

  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding" maxBufferPoolSize="2097152" maxBufferSize="2097152" maxReceivedMessageSize="2097152">
          <readerQuotas maxDepth="32" maxStringContentLength="2097152" maxArrayLength="2097152" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
          <security mode="None"/>
        </binding>
      </basicHttpBinding>
    </bindings>

    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceWithMetadata">
          <!-- 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" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <protocolMapping>
      <add binding="basicHttpBinding" scheme="http" />
      <add binding="basicHttpsBinding" scheme="https" />
    </protocolMapping>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    <!--
        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>

  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v11.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>

What I would like is to understand HOW to configure my config file(s) to allow a maximum upload size of say 2MB. If it is possible to pass the data in binary format rather than Base64 (or whatever) that would also be advantageous to decrease the bandwidth requirements between servers.

Communication between sites is currently over HTTP in my dev environment, but I'll also need to configure for HTTPS for test/production. Bonus points for pointers on the additional config.

Thanks in advance for any help you can provide on this. It's cost me a fair amount of time already and I'm no closer to a solution.

Found my answer - I originally posted a link to it here, but one of the mods decided to delete the answer (thanks for that!), so I'll post the solution in its entirety instead:


In order to allow payloads (such as files or large arrays of data) OVER the default of 40KB to be sent to a WCF Service method, the changes required are predominantly in the web.config file of the WCF project. There is also one minor tweak required in the client's configuration, so we'll look at that first:

<configuration>
  ...
  <system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <!-- Large Message Upload (Begin) -->
        <binding name="BasicHttpBinding_IUserService" maxBufferPoolSize="2097152" maxReceivedMessageSize="2097152" />
        <!-- Large Message Upload (End) -->
        <binding name="BasicHttpBinding_ISystemService" />
        ...
      </basicHttpBinding>
    </bindings>
    ...
  </system.serviceModel>
</configuration>

When you first add a service reference to your client's project, Visual Studio automatically creates default binding and endpoint nodes in your config file. You'll need to add two new attributes to the binding node for your service: maxBufferPoolSize and maxReceivedMessageSize. Both attributes should have their values set to your desired file upload size limit IN BYTES. You'll also need to take note of the name for the next bit.

That's if for the client configuration, so on to the WCF Service. Here's an extract from mine:

<configuration>
   ...
  <system.serviceModel>

    <bindings>
      <basicHttpBinding>
        <!-- Large Message Upload (Begin) -->
        <binding name="BasicHttpBinding_IUserService"
                 maxBufferSize="2097152"
                 maxBufferPoolSize="2097152"
                 maxReceivedMessageSize="2097152"
                 closeTimeout="00:50:00" 
                 openTimeout="00:50:00" 
                 sendTimeout="00:50:00" 
                 receiveTimeout="00:50:00">
          <readerQuotas maxDepth="32" maxStringContentLength="100000"
                        maxArrayLength="2097152" maxBytesPerRead="4096"
                        maxNameTableCharCount="16384" />
          <security mode="None" />
        </binding>
        <!-- Large Message Upload (End) -->
      </basicHttpBinding>
    </bindings>

    <services>
      <!-- Large Message Upload (Begin) -->
      <service name="BlexEngine.Services.UserService"
               behaviorConfiguration="ServiceWithMetadata">
        <endpoint name="Default"
                  binding="basicHttpBinding"
                  bindingConfiguration="BasicHttpBinding_IUserService"
                  contract="BlexEngine.Services.IUserService" />
      </service>
      <!-- Large Message Upload (End) -->
    </services>

    <behaviors>
      <serviceBehaviors>
        <!-- Large Message Upload (Begin) -->
        <behavior name="ServiceWithMetadata">
          <!-- Large Message Upload (End) -->

          <!-- 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" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    ...
  </system.serviceModel>
  ...
</configuration>

As you can see there are three changes required:

1) Create a binding specifically for the service that you want to enable large file uploads for (my project publishes five services at the moment, but only one requires a larger file upload limit). Ensure that the value of the name attribute matches the name of the binding we noted in the client's web.config file. Copy the attributes and child nodes from the example above and modify as you see fit. All size values are, AKAIK, in bytes.

2) Jumping around a bit, we're going to move to the last change in the config extract next. Visual Studio creates a default behaviour node with all the correct settings, but does NOT set a name on that node, so add a name attribute and give it a value. ServiceWithMetadata was the value in the example I found, so that's what I used - I don't know if it really matters what you call it.

3) Create a service node for your service. The name must be the fully qualified name of your service class and the behaviourConfiguration needs to be the name of the service node, as set in step 2). Within the service node you'll need to configure an endpoint, the bindingConfiguration of which needs to be set to the name of the binding setup in step 1) and the contract of which needs to be set to the fully qualified name of the interface your service class adheres to.

That's it really. Figuring this out has taken far too long and I can't believe how complex the process has been or how little documentation there appears to be out there on this topic. To anyone suffering the same issue as I did: good luck! I hope that this post saves you the time I had to invest figuring this out the hard way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM