Christian Klemm
Christian Klemm

Reputation: 1505

Malformed Json for GET

I've written a simple API which is reading a json file and providing this data via GET. My model for the controller looks like this:

public static class ServerListHandler
{
    private static readonly string _serverListPath;
    private static FileSystemWatcher _serverListWatcher;
    private static string _servers;

    public static string Servers
    {
        get
        {
            if(_serverListWatcher == null && File.Exists(_serverListPath))
            {
                InitializeFileWatcher();
                ReadData();
            }

            return _servers;
        }

        private set
        {
            _servers = value;
        }
    }

    static ServerListHandler()
    {
        _serverListPath = Properties.Settings.Default.ServerListPath;

        if(!File.Exists(_serverListPath))
        {
            Debug.WriteLine("Could not find config with path: " + _serverListPath);
        }
        else
        {
            ReadData();
            InitializeFileWatcher();
        }
    }

    private static void InitializeFileWatcher()
    {
        _serverListWatcher = new FileSystemWatcher(Path.GetDirectoryName(_serverListPath));
        _serverListWatcher.EnableRaisingEvents = true;

        _serverListWatcher.Deleted += OnServerListChanged;
        _serverListWatcher.Changed += OnServerListChanged;
        _serverListWatcher.Created += OnServerListChanged;
        _serverListWatcher.Renamed += OnServerListChanged;
    }

    private static void OnServerListChanged(object sender, FileSystemEventArgs e)
    {
        ReadData();
    }

    private static void ReadData()
    {
        try
        {
            string content = File.ReadAllText(_serverListPath);
            Servers = content;
        }
        catch(Exception ex)
        {
            Debug.WriteLine("Could not read server file: " + ex);
        }            
    }
}

I added this line in WebApiConfig.cs to get a json output

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

The original json file looks like this:

[
  {
    "Name": "testing",
    "IP": "127.0.0.1"
  }
]

And the GET result is:

"[\r\n {\r\n \"Name\": \"testing\",\r\n \"IP\": \"127.0.0.1\"\r\n }\r\n]\r\n"

Of course the result is not parsable for Json.NET. Now my question is if I have to parse the json string manually that it fits or if I just forgot to enable/check something to enable a proper json output.

Edit

As requested this is my controller

public class ServersController : ApiController
{
    public HttpResponseMessage GetAllServers()
    {
        if(ServerListHandler.Servers == null)
            return Request.CreateResponse(HttpStatusCode.NoContent);

        return Request.CreateResponse(HttpStatusCode.OK, ServerListHandler.Servers);
    }
}

Upvotes: 1

Views: 512

Answers (1)

Brian Rogers
Brian Rogers

Reputation: 129697

The problem here is that Web API assumes by default that it is responsible for serializing anything you give it. For most use cases, this is exactly what you would want. But if your content is already JSON, Web API has no way of knowing that; it will happily re-serialize the string, adding extra quotes and backslashes in the process.

To return a JSON string untouched, you need to explicitly create the response content object (rather than letting Web API create it), making sure to set the media type to so that downstream clients will still interpret it as JSON (rather than plain text). Here is the revised controller method:

public HttpResponseMessage GetAllServers()
{
    if(ServerListHandler.Servers == null)
        return Request.CreateResponse(HttpStatusCode.NoContent);

    HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
    response.Content = new StringContent(ServerListHandler.Servers, Encoding.UTF8, "application/json");
    return response;
}

Another possible (but less efficient) solution is to deserialize your JSON to an object, then return that object from your controller method, as was suggested by @CathalMF in the comments. Web API will then re-serialize the object back to JSON again when it creates the response.

Upvotes: 2

Related Questions