Roger Down
Roger Down

Reputation: 73

ServiceStack Json deserializing with wrong Content-Type

Trying a setup with ServiceStack 3.9.49 and CORS.

A simple Echo Service which returns the POSTed data back++. The code:

[Route("/echo")]
public class EchoRequest
{
    public string Name { get; set; }
    public int? Age { get; set; }
}

public class RequestResponse
{
    public string Name { get; set; }
    public int? Age { get; set; }
    public string RemoteIp { get; set; }
    public string HttpMethod { get; set; }
}

public class EchoService : Service
{
    public RequestResponse Any(EchoRequest request)
    {
        var response = new RequestResponse
            {
                Age = request.Age,
                Name = request.Name,
                HttpMethod = base.Request.HttpMethod,
                RemoteIp = base.Request.RemoteIp
            };
        return response;
    }
}

The AppHost Configure code:

public override void Configure(Container container)
{
    ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;

    SetConfig(new EndpointHostConfig
    {
        DefaultContentType = ContentType.Json,
        GlobalResponseHeaders = new Dictionary<string, string>(),
        DebugMode = true
    });

    Plugins.Add(new CorsFeature());

    PreRequestFilters.Add((httpRequest, httpResponse) => {
        //Handles Request and closes Responses after emitting global HTTP Headers
        if (httpRequest.HttpMethod == "OPTIONS")
            httpResponse.EndServiceStackRequest();
    });

    RequestFilters.Add((httpRequest, httpResponse, dto) =>
    {
        httpResponse.AddHeader("Cache-Control", "no-cache");
    });
}

When sending a POST (with the json object in the body) with Content-Type: application/json, everything works great.

But when sending the same content and setting the Content-Type to text/plain, the correct method gets invoked, but the data in the EchoRequest is null.

Is this the correct behaviour? Must the Content-Type be set to application/json if a json object is sent as a POST?

Is yes, is it possible override this somehow e.g. in the url? From my understanding using ?format=json in the url, only affects the returned data...

Final question, is it possible to modify the Content-Type header of the request before being deserialized to the method, somewhere, something like this:

if (httpRequest.ContentType == "text/plain")
    httpRequest.Headers["Content-Type"] = ContentType.Json;

Upvotes: 2

Views: 507

Answers (1)

bpruitt-goddard
bpruitt-goddard

Reputation: 3324

Deserializing into an empty object is the correct behavior for ServiceStack's serializer. It tends to be very forgiving. It creates an empty deserialized object and proceeds to hydrate it with anything it parses out of the input, meaning if you give it junk data, you will get back an empty object.

You can make the serializer less forgiving by specifying the following option in your AppHost config:

ServiceStack.Text.JsConfig.ThrowOnDeserializationError = true;

I am not aware of any way to modify the URL to indicate to ServiceStack that the request is in JSON format. Furthermore, it doesn't appear there is any way inside ServiceStack to modify the content type before deserialization. Even specifying a PreRequestFilter to modify the header before will not work as the request's ContentType property has been set and is readonly.

PreRequestFilters.Add((req, res) => req.Headers["Content-Type"] = "application/json");

Upvotes: 3

Related Questions