Jonas

Jonas Carlsen Kjær

Sending UTF-8 JSON through TcpClient in C#

C#

I recently had to sent a HTTP request containing some JSON in UTF-8 format.

However, when I received the text it seemed to be cut short.

This is a simple recreation of my code:

// I already have 3 variables:
// string socketIp, integer socketPort and string json.
// Where "json" contains my json string.

using (var socket = new TcpClient(socketIp, socketPort))
{
  var headerContent = new StringBuilder();
  headerContent.AppendLine("POST /someUrl/someReceiver.aspx HTTP/1.0");
  headerContent.AppendLine("Accept: */*");
  headerContent.AppendLine("Host: " + socketIp);
  headerContent.AppendLine("Content-Type: application/javascript; charset=utf8");
  headerContent.AppendLine("Content-Length: " + json.Length);
  headerContent.AppendLine("Connection: Close");
  headerContent.AppendLine();

  var header = Encoding.UTF8.GetBytes(headerContent.ToString());
  var body = Encoding.UTF8.GetBytes(json);

  using (var stream = socket.GetStream())
  {
    stream.Write(header, 0, header.Length);
    stream.Write(body, 0, body.Length);
  }
}

Now this solution simply would not send the whole body to the recipient server. When I got it, it was always cut short.

I did notice, however, that the more non-english characters i added (such as \\u00c6, \\u00d8 and \\u00c5), the less content i would get.

So i thought of the issue of two-byte characters in UTF-8. And found out that i can use the Encoding class to get the real length of the byte arrrays after being encoded with UTF-8, this is done using the GetByteCount() method.

I added this calculation result to my stream.Write length, and my Content-Length header.

using (var socket = new TcpClient(socketIp, socketPort))
{
  var body = Encoding.UTF8.GetBytes(json);
  var bodyLength = Encoding.UTF8.GetByteCount(json);

  var headerContent = new StringBuilder();
  headerContent.AppendLine("POST /someUrl/someReceiver.aspx HTTP/1.0");
  headerContent.AppendLine("Accept: */*");
  headerContent.AppendLine("Host: " + socketIp);
  headerContent.AppendLine("Content-Type: application/javascript; charset=utf-8");
  headerContent.AppendLine("Content-Length: " + bodyLength);
  headerContent.AppendLine("Connection: Close");
  headerContent.AppendLine();

  var headerString = headerContent.ToString();
  var header = Encoding.UTF8.GetBytes(headerString);
  var headerLength = Encoding.UTF8.GetByteCount(headerString);

  using (var stream = socket.GetStream())
  {
    stream.Write(header, 0, headerLength);
    stream.Write(body, 0, bodyLength);
  }
}

And bingo! It works as expected! The length is now correct and the stream is not cut short.