Große WCF-Webdienstanforderung schlägt mit (400) HTTP Bad Request fehl

74

Ich bin auf dieses anscheinend häufige Problem gestoßen und konnte es nicht lösen.

Wenn ich meinen WCF-Webdienst mit einer relativ kleinen Anzahl von Elementen in einem Array-Parameter aufrufe (ich habe bis zu 50 getestet), ist alles in Ordnung.

Wenn ich jedoch den Webdienst mit 500 Elementen aufrufe, wird der Fehler "Bad Request" angezeigt.

Interessanterweise habe ich Wireshark auf dem Server ausgeführt und es scheint, dass die Anforderung nicht einmal den Server erreicht - der 400-Fehler wird auf der Clientseite generiert.

Die Ausnahme ist:

System.ServiceModel.ProtocolException: The remote server returned an unexpected response: (400) Bad Request. ---> System.Net.WebException: The remote server returned an error: (400) Bad Request.

Der system.serviceModelAbschnitt meiner Client-Konfigurationsdatei lautet:

<system.serviceModel>
    <bindings>
        <wsHttpBinding>
            <binding name="WSHttpBinding_IMyService" closeTimeout="00:01:00"
                openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
                maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
                messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
                allowCookies="false">
                <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="2147483647"
                    maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                <reliableSession ordered="true" inactivityTimeout="00:10:00"
                    enabled="false" />
                <security mode="None">
                    <transport clientCredentialType="Windows" proxyCredentialType="None"
                        realm="" />
                    <message clientCredentialType="Windows" negotiateServiceCredential="true"
                        establishSecurityContext="true" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://serviceserver/MyService.svc"
            binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IMyService"
            contract="SmsSendingService.IMyService" name="WSHttpBinding_IMyService" />
    </client>
</system.serviceModel>

Auf der Serverseite enthält meine Datei web.config den folgenden system.serviceModelAbschnitt:

<system.serviceModel>
    <services>
        <service name="MyService.MyService" behaviorConfiguration="MyService.MyServiceBehaviour" >
            <endpoint address="" binding="wsHttpBinding" bindingConfiguration="MyService.MyServiceBinding" contract="MyService.IMyService">
            </endpoint>
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
        </service>
    </services>
    <bindings>
      <wsHttpBinding>
        <binding name="MyService.MyServiceBinding">
          <security mode="None"></security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
        <serviceBehaviors>
            <behavior name="MyService.MyServiceBehaviour">
                <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
                <serviceMetadata httpGetEnabled="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>

Ich habe bei sieht eine ziemlich große Anzahl von Antworten auf diese Frage mit keinem Erfolg .

Kann mir jemand dabei helfen?

Damovisa
quelle
Wenn es den Server nicht trifft, stimmt möglicherweise etwas mit den gesendeten Daten nicht. Vielleicht enthält die Anfrage einige illegale Zeichen? Angenommen, dies ist SOAP
Chad Grant
1
Sie haben also versucht, alle Ihre 'max'-Attribute (z. B. maxReceivedMessageSize ...) auf eine wirklich hohe Zahl zu setzen?
mundeep
Ja, es ist Seife. Und es sollte nichts falsch mit der Anfrage sein - wie gesagt, alles funktioniert gut für bis zu 50 Elemente, die mit derselben Anwendung generiert wurden ...
Damovisa
@mundeep - yep - Ich habe versucht, alle auf 2147483647 zu setzen, aber dort kein Glück. Einige der Seiten, auf die ich verlinkt habe, deuteten tatsächlich darauf hin, dass es eine schlechte Sache war, dies für alle Attribute zu tun ...
Damovisa

Antworten:

107

Versuchen Sie, maxReceivedMessageSize auch auf dem Server einzustellen, z. B. auf 4 MB:

    <binding name="MyService.MyServiceBinding" 
           maxReceivedMessageSize="4194304">

Der Hauptgrund, warum der Standard (65535, glaube ich) so niedrig ist, besteht darin, das Risiko von Denial-of-Service-Angriffen (DoS) zu verringern. Sie müssen festlegen, dass die maximale Anforderungsgröße auf dem Server und die maximale Antwortgröße auf dem Client größer sind. Wenn Sie sich in einer Intranet-Umgebung befinden, ist das Risiko von DoS-Angriffen wahrscheinlich gering. Daher ist es wahrscheinlich sicher, einen Wert zu verwenden, der viel höher ist als erwartet.

Übrigens ein paar Tipps zur Fehlerbehebung beim Herstellen einer Verbindung zu WCF-Diensten:

  • Aktivieren Sie die Ablaufverfolgung auf dem Server wie in diesem MSDN-Artikel beschrieben .

  • Verwenden Sie ein HTTP-Debugging-Tool wie Fiddler auf dem Client, um den HTTP-Verkehr zu überprüfen.

Joe
quelle
1
Erstaunlich - das war alles. Vielen Dank für Ihre Antwort!
Damovisa
2
Vielen Dank für den Link zum Aktivieren der Ablaufverfolgung!
Colin Desmond
2
Ich habe am Ende versucht, dasselbe zu tun, konnte aber keinen Erfolg schmecken.
Kangkan
1
Nützlicher Blog-Beitrag: geekswithblogs.net/smyers/archive/2011/10/05/… - Ich möchte die Leute, die diese Antwort lesen, nur darauf hinweisen, dass das obige Code-Snippet in der Antwort in den Bindungsbereich Ihrer Bindung aufgenommen werden sollte. Beispiel: Lassen Sie die Bindung basicHttpBinding sein: <bindings> <basicHttpBinding> <binding ... /> <readerQuotas ... /> </ basicHttpBinding> </ bindings> - möglicherweise auch die <readerQuotas maxArrayLength = "" /> gesetzt werden (ich musste).
Legasthenikeraboko
7

Ich bekam auch dieses Problem, aber keines der oben genannten Probleme funktionierte für mich, da ich nach langem Graben eine benutzerdefinierte Bindung (für BinaryXML) verwendete. Hier fand ich die Antwort: -

Senden von großem XML von Silverlight an WCF

Da ich eine customBinding verwende, muss die maxReceivedMessageSize für das httpTransport-Element unter dem Bindungselement in der web.config festgelegt werden:

<httpsTransport maxReceivedMessageSize="4194304" /> 
Mark Davies
quelle
7

Eine weitere Überlegung bei der Verwendung von .NET 4.0 ist, dass automatisch ein Standardendpunkt erstellt und verwendet wird, wenn in Ihrer Konfiguration kein gültiger Endpunkt gefunden wird.

Der Standardendpunkt verwendet alle Standardwerte. Wenn Sie also glauben, dass Sie eine gültige Dienstkonfiguration mit einem großen Wert für maxReceivedMessageSize usw. haben, aber etwas mit der Konfiguration nicht stimmt, erhalten Sie immer noch die 400 Bad Request, da dies ein Standardendpunkt wäre erstellt und verwendet.

Dies geschieht lautlos, so dass es schwer zu erkennen ist. Diesbezügliche Meldungen (z. B. "Kein Endpunkt für Dienst gefunden, Standardendpunkt erstellen" oder ähnliches) werden angezeigt, wenn Sie die Ablaufverfolgung auf dem Server aktivieren, aber meines Wissens keine andere Anzeige gibt.

user469104
quelle
@ user469104: Sehr guter Tipp. Vielen Dank. Gibt es eine Möglichkeit, den Server zu zwingen, einen von Hand deklarierten Endpunkt zu verwenden, ohne den Standard-ServiceHost zu überschreiben?
RaSor
5

Auf dem Server in .NET 4.0 in web.config müssen Sie auch die Standardbindung ändern. Stellen Sie die folgenden 3 Parameter ein:

 < basicHttpBinding>  
   < !--http://www.intertech.com/Blog/post/NET-40-WCF-Default-Bindings.aspx  
    - Enable transfer of large strings with maxBufferSize, maxReceivedMessageSize and maxStringContentLength
    -->  
   < binding **maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"**>  
      < readerQuotas **maxStringContentLength="2147483647"**/>            
   < /binding>
RaSor
quelle
4

Es kann nützlich sein, den Client zu debuggen, Extras \ Optionen \ Debugging \ Allgemein \ 'Nur meinen Code aktivieren' zu deaktivieren, auf Debug \ Ausnahmen \ 'Alle Ausnahmen der ersten Chance abfangen' für verwaltete CLR-Ausnahmen zu klicken und zu prüfen, ob es eine gibt Ausnahme unter der Haube auf dem Client vor der Protokollausnahme und bevor die Nachricht auf die Leitung trifft. (Meine Vermutung wäre eine Art Serialisierungsfehler.)

Brian
quelle
4

Sie können auch die WCF-Protokollierung aktivieren, um weitere Informationen zum ursprünglichen Fehler zu erhalten. Dies hat mir geholfen, dieses Problem zu lösen.

Fügen Sie Ihrer web.config Folgendes hinzu, um das Protokoll unter C: \ log \ Traces.svclog zu speichern

<system.diagnostics>
    <sources>
        <source name="System.ServiceModel"
                  switchValue="Information, ActivityTracing"
                  propagateActivity="true">
            <listeners>
                <add name="traceListener"
                     type="System.Diagnostics.XmlWriterTraceListener"
                     initializeData= "c:\log\Traces.svclog" />
            </listeners>
        </source>
    </sources>
</system.diagnostics>
Aaron Hoffman
quelle
1
Manchmal sind die einfachsten Antworten die besten. Für mich stellte ich fest, dass ich in einem Stream-Antwortaufruf ein Null-Stream-Objekt zurückgab. Der svclog hat dies in Sekunden gelöst. Vielen Dank.
Der Senator
3

Ich möchte nur darauf hinweisen

Abgesehen von MaxRecivedMessageSize gibt es unter ReaderQuotas auch Attribute. Möglicherweise erreichen Sie die Anzahl der Elemente anstelle der Größenbeschränkung. MSDN Link ist hier

Yuan
quelle
3

Ich habe die Antwort auf das Problem Bad Request 400 gefunden.

Dies war die Standardeinstellung für die Serverbindung. Sie müssten die Standardeinstellung für Server und Client hinzufügen.

Bindungsname = "" openTimeout = "00:10:00" closeTimeout = "00:10:00" receiveTimeout = "00:10:00" sendTimeout = "00:10:00" maxReceivedMessageSize = "2147483647" maxBufferPoolSize = "2147483647 "maxBufferSize =" 2147483647 ">

singh
quelle
1

In meinem Fall funktionierte es nicht, obwohl alle Lösungen ausprobiert und alle Grenzen auf max. Zuletzt fand ich heraus, dass ein Microsoft IIS-Filtermodul Url Scan 3.1 auf IIS / Website installiert wurde, das seine eigene Grenze hat, um eingehende Anforderungen basierend auf der Inhaltsgröße abzulehnen und "404 Not found page" zurückzugeben.

Das Limit kann in der %windir%\System32\inetsrv\urlscan\UrlScan.iniDatei aktualisiert werden, indem MaxAllowedContentLengthder erforderliche Wert festgelegt wird.

Zum Beispiel. Im Folgenden werden bis zu 300 MB-Anforderungen zugelassen

MaxAllowedContentLength = 314572800

Hoffe es wird jemandem helfen!

Sukhdeep Singh
quelle