3/16/11

WCF Service returns (400) Bad Request

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 on 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 the 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. The 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 the 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 a 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.


og-bit.com

3/1/11

Improve Code Maintenance with Visual Studio Code Metrics Analysis

There are several factors that make a code very difficult to maintain. Some of the most common factors are never ending functions that may have hundreds lines of code and functions that have deep nesting if then else statements. Visual Studio comes with a feature call Code Metrics. This is available in the Analyze menu options or by selecting the project you want to analyze and selecting the Calculate Code Metrics context menu option.
Maintainability Index
The main purpose of this utility is to calculate the maintainability index which provides a quick indicator of how difficult it may be to maintain the code. The goal is to get a high value with 100 being the maximum value. There may be an index of 50, but this does not mean the index is a poor one. Instead, there is a rating icon next to the index. This icon represents the category in which the code index falls on. These are the current color codes and ranges:

Green Rating
20-100
Code has good maintainability
Yellow Rating
10-19
Code is moderately maintainable
Red Rating
0-9
Code has poor maintainability

The goal is to achieve a green rating. I have noticed that code with rating below fifty could be easily refactored to improve the index. In your projects, you may want to target anything below 50 or 60.

Cyclomatic Complexity
This measures the number of different paths in the flow of the program. We need to remember that decision paths in a function require more test to get code coverage. A function with no decisions results in a value of one. A function with a value of eight or more should be refactored to improve the maintainability index.  Common problem areas that increase this value are the nesting of if then statements, comparison in a LINQ statement, switch statements.

Depth of Inheritance

This measures how deep classes are located in the inheritance tree. This can sometimes make it more difficult to understand in what parent class certain methods or properties are actually implemented. You should try to keep this value less than five

Class Coupling

This measures the use or coupling of other classes in a class method in the form of parameters, return types, method calls, attribute decoration. High coupling indicates that there is low maintainability because of the interdependencies on other classes that reside in the same assembly or on a different one. Anything over a value of eight should raise a flag, and the code should be reviewed.

Lines of Code

This is the most obvious indicator. Functions over 60 lines of code should be looked and split into more logical functions.

The recommended values I listed on this article should be used only as a suggestion for your projects. To get more accurate results, you should evaluate your projects and create a baseline that works for your goals. The key element here is to not let the code become something that is just too difficult and confusing to maintain.

I hope you find this useful.

og-bit.com