Property 'format' does not exist on type (POST Request)

We are updating from ServiceStack 4.0.52 to 4.5.14, obviously realizing that this is a major upgrade we’ve thoroughly reviewed Release Notes and tested services extensively. One behavior that we’re seeing that we’re not able to explain is the following.

We use the builtin ?format=json URL param or .json extension instead of Accept header from some 3rd party clients where we cannot control the request headers. There are now exceptions being thrown like:

Exception: WARN: Property 'format' does not exist on type 'XX.Dto'

Similarly there are other URL params that we pass in POST request like “X-Client-Id” that are not a fields with DTOs but used globally to identify calling client, etc. These are throwing similar errors.

Example:

POST /note/add.json?X-Client_Id=123

with JSON body like

{
"id": 1,
"content":"foo"
}

This appears to be resulting in a 400 “Bad Request”. We’re seeing correlated errors like:

Message: Unable to bind to request 'Note'
Source: ServiceStack.Client

Has this behavior changed? Please advise. I know this is unrelated but we’ve already turned StrictMode=false for other reasons.

What’s the full StackTrace for the Exception? and what’s the best way to reproduce it?

Are you sure an Exception is being thrown or just logged? The only place I see this is logged as a warning which shouldn’t be throwing an Exception unless you’re using a Custom Logger that throws Exceptions on Warnings?

In the request logs we are seeing 400 errors. This is also resulting in an elevated error rate in our APM New Relic.

  1. How do I generate a stack trace for a binding error / warning?
  2. Here are the request details from the request logger (that we send into ElasticSearch / Kibana from Redis)

Screenshot of request log

Can you see if the Request Body contains the StackTrace? You should be in DebugMode and your Response DTO should have a ResponseStatus property.

Are you able to reproduce this locally using a ServiceClient? If so can you provide the Request/Response DTOs and the client source code that causes the Exception.

There were two issues:

  1. We had not seen the WARN for nonexistent property before, so we assumed this was part of the issue. However as you indicated this was just a warning, and after ignoring that those are no longer logged.

  2. The 3rd party caller to our service method is prepending 00 to an integer value that they are passing in the POST request. Something must have changed with the way these values are parsed in SS, because in the old 4.0.52 the method would still bind properly and the value would be parsed as an int correctly. In 4.5.14 this is no longer the case.

Here is the DTO as defined in our service

public class AddNote : IReturn<Note>
    {
        public int CustomerId { get; set; }
        public string Content { get; set; }
        public string CallType { get; set; }
        public int? DispositionId { get; set; }
        public int? OrderId { get; set; }
        public string Username { get; set; }
        public int? UserId { get; set; }
        public DateTime NoteDate { get; set; }
        public string CallId { get; set; }
    }

Here’s the stack trace

{
    "responseStatus": {
        "errorCode": "SerializationException",
        "message": "Unable to bind to request 'AddNote'",
        "stackTrace": "   at ServiceStack.Serialization.StringMapTypeDeserializer.PopulateFromMap(Object instance, IDictionary`2 keyValuePairs, List`1 ignoredWarningsOnPropertyNames)\r\n   at ServiceStack.Host.RestPath.CreateRequest(String pathInfo, Dictionary`2 queryStringAndFormData, Object fromInstance)\r\n   at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq, IRestPath restPath, Dictionary`2 requestParams, Object requestDto)\r\n   at ServiceStack.Host.RestHandler.CreateRequest(IRequest httpReq, IRestPath restPath)\r\n   at ServiceStack.Host.RestHandler.ProcessRequestAsync(IRequest httpReq, IResponse httpRes, String operationName)",
        "errors": [
            {
                "errorCode": "SerializationException",
                "fieldName": "customerId",
                "message": "'002264643' is an Invalid value for 'customerId'"
            }
        ]
    }
}

here is their post request

We will likely need to change the CustomerId field to string and parse.

Oddly enough if we change the Content-Type to application/json and pass the DTO with the same values as json it binds the request but CustomerId is 0.

{
 "customerId": 0012312,
 "content": "foo",
 "dispositionId": 123,
 "username": "xx",
 "callId":123
}

Why is there a different behavior for the different content types? With the x-www-formurlencoded not binding at all.

Numbers with leading 00 isn’t a valid JSON number, so you would need to change it to a string to read its original value. This change likely occurred when converting ServiceStack.Text deserializers to use custom parsing functions which use the more memory efficient StringSegment.

The JSON Serializer deserializes as much as possible without error which is why it silently ignores the property, in future we’ll use StrictMode to throw an Exception when this occurs.

As ServiceStack.Text has no dependencies it doesn’t log by default, but you can view any warnings by specifying a tracer, e.g:

Tracer.Instance = new Tracer.ConsoleTracer();

Which will log a warning to the console:

WARN: failed to set property customerId with: 0012312

I understand that its not valid JSON. What I’m moreso wondering is why the x-www-form-urlencoded POST didnt bind the request? This is not JSON it is just a urlencoded string in the POST body.

We’re actually considering using a request filter to detect requests from this specific client to parse the invalid integer (string) to a valid int on the DTO. Will a Typed Request Filter trigger for this even if the request wont bind currently?

Thanks again for your help with this @mythz !!

JSON Serializers catches the deserialization Exception and logs to the tracer whereas parsing x-www-form-urlencoded requests is handled in ServiceStack where the Exception is thrown.

The Exception occurs when ServiceStack deserializes the Request DTO so the Exception will have already occurred before any filters that include the Request DTO are fired so the PreRequestFilters is the only filter fired before the Request is deserialized.

You could register a Custom Request Binder where you can take over deserialization of the Request, otherwise changing the property to a string and parsing it in your Service is another option.

If anyone is still encountering this issue, then I have the fix.
I have encountered the same issue recently when deploying into a customer’s AWS EKS cluster.
The issue is the use of content type of “application/x-www-form-urlencoded”.
You should use the following and change your DTO from “form” to “body” and switch from content type of “application/x-www-form-urlencoded” to “application/json”.

Here is some code snippet that I used to get things working:

Dictionary<string, string> payload = new Dictionary<string, string>();
payload.Add(“TenantID”, servicContext.tenantId);
payload.Add(“TenantUserID”, servicContext.userEmail);
payload.Add(“RequestingUserID”, requestingUserId);

/*/

  • This next line will create a json object based on key/value pair very nicely for you!
    /*/
    string body = Newtonsoft.Json.JsonConvert.SerializeObject(payload)

var uri = new Uri(baseUri, $“DownloadData/”);
var message = new HttpRequestMessage(HttpMethod.Post, uri);

/*/

  • This next line will allow you to easily set the content type and add encoding to the json body.
    /*/
    message.Content = new StringContent(body, Encoding.UTF8, “application/json”);
2 Likes