If you implement a WCF service using the default values and expect to be able to send to the server a large XML file, you may encounter an intermittent bad request error from the server. This error basically tells you that the server refuses to handle your request because it thinks that the request is not compliant with the HTTP protocol. The request however may be well formatted, but the message size restrictions may be exceeded on some requests.
To examine this problem, let’s create a simple WCF service application using Visual Studio. After the project is created, we should refactor the interface and class implementation to match the following:
Interface:
[ServiceContract]
public interface IHandleLargeString
{
[OperationContract]
bool SetData(string xml);
}
Class:
public class HandleLargeString : IHandleLargeString
{
public bool SetData(string xml)
{
return true;
}
}
This service expects an XML string. For our test, we can use any string because we are not really doing anything with the XML. Compile the code to make sure all is OK. We can now edit the Web.config file using the WCF Service Configuration editor. When a new project is just created, a right click on the config file does now show the editor on the context menu, but the editor is available from the Tools menu. Once the editor is opened, the association is made, and the context menu now has the editor entry. After opening the config file with the editor, we can create a new binding configuration. Select the binding node (left pane) and click on New binding configuration (right pane). Select wsHttpBinding which matches the default service end-point binding (see services, Endpoints node). Give the new entry a name. Now click on Services.Endpoints and select the end point that uses the wsHttpBinding
definition. This is usually the first node. Make sure to set the BindingConfiguration dropdown to the recently created configuration. This should be the only option available on the dropdown.
We just configured our service to use the new binding configuration. Opening the binding configuration (from the Bindings node left pane) reveals several settings. We are interested in two settings:
MaxReceivedMessageSize
: This property is used to limit the overall message size which includes the message content and header information.MaxStringContentLength
: This is used by the XmlReader
to deserialize the message content.
A message can be sent to the Web Service that does not exceed the message size setting, but it may be bigger than the message content setting. When this is the case, the server returns a deserialization error which is created by the XmlReader
because the max content length of the XML has been exceeded. So to address the 400 bad request errors, we must be mindful of how big the message content can be, and the message size should be bigger than the content size. Another thing to note is that when using the basicHttp
binding, the default TransferMode
is set to buffered. When this is the case, both MaxBufferSize
and MaxReceivedMessageSize
should be the same.
We can now write a console application that will consume our service. Create the console application, add the service reference (use service reference not web reference and name it TestClient), and add the following code to the program file:
static void Main(string[] args)
{
TestStringContent();
TestMessageContent();
Console.Read();
}
public static void TestStringContent()
{
string data = "1234567890";
for (int idx = 0; idx < 5; idx++)
{
data += data;
}
SendRequest("TestStringContent", data);
}
public static void TestMessageSize()
{
string data = "1234567890";
for (int idx = 0; idx < 10; idx++)
{
data += data;
}
SendRequest("TestMessageSize", data);
}
public static void SendRequest(string action, string data)
{
Console.WriteLine( String.Format("test: {0} Length: {1}",
action, data.Length));
try
{
TestClient.HandleLargeStringClient client =
new TestClient.HandleLargeStringClient();
client.SetData(data);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This console application sends two messages to the service. TestStringContent
sends a string with a content length of 320. The TestMessageSize
function sends a content length of 10240. Do not run this yet. We now need to change the default service settings. Using the WCF configuration editor, set MaxStringContentLength
to 300 and MaxReceivedMessageSize
to 10000. You can save the current values because we will need to restore them after our test is done. Compile and run the application. You should now see two exceptions. The first one indicates that there was an error deserializing the message. This is because we exceeded the 300 content length, but we did not exceed the message size. The second one is just a bad request message with no detail. This is because the second message was well over 10000, so we exceeded both limits.
Let’s now fix this problem. Using the WCF configuration editor, set MaxStringContentLength
to 10500 and MaxReceivedMessageSize
to 20000 (always bigger than the potential content to account for message headers) or just restore the original values. We can use an HTTP sniffer like Fiddler to analyze and accurately identify the values. Run the application again, and all the errors should be gone.
I hope this provides some help in addressing the 400 Bad Request error.