Sunday 2 December 2018

Post and No DTO class

Working on an Asp.Net project I've come across a problem that reminded me of an old post. I have one action in one controller that just expects a simple value (a string) as parameter. The action is not for querying data, and though we are not doing a real REST API, at least I wanted to use a POST and not a GET, and pass the value in the post body (not as a querystring).

When passing multiple values the normal thing is just creating a sort of "DTO" object with those values as fields, send it as JSON and let the ModelBinder do its work. But for a single value (or a couple of them) it felt bad to me to create a class with just a single field. This seemed a perfect case for using dynamic. I mean:

//Client side code
  addItem(item: string): Observable {
    return this._remoteService.post(this.url,
      {
        item: item
      });
}


//server side code
        [HttpPost]
        public HttpResponseMessage AddItem(dynamic dto)
        {
            //wrong, myService receives a "null" value
   return Request.CreateResponse(HttpStatusCode.OK, this.myService.AddItem((dto.item as string)));
        }

The thing is that the myService.AddItem was receiving a null value. Checking with the debugger I could see that the dto object with its "item" field was reaching fine the controller. The model binder was using Json.Net and deserializing it to a JObject. JObjec and "dynamic" are designed to work together, so why was I receiving null when passing over the dto.item???

Here is where that old post of mine comes into play. In my code I'm using the as operator to tell the compiler that dto.item is a string, dto.item as string. The problem is that such statement is false, dto.item is a JValue (containing a string we can say), so when the runtime finds that we don't have a string but a JValue (you can read more here), as fails and returns null. So in this case we have to use the cast operator, (string)dto.item, that here does not behave as just a "hint", but performs a explicit conversion from JValue to String. If you are confused, read my old post, where this thing of cast vs as and the 2 different behaviours of the cast operator (hinting vs converting) are well explained.

//server side code
        [HttpPost]
        public HttpResponseMessage AddItem(dynamic dto)
        {
            //works fine
   return Request.CreateResponse(HttpStatusCode.OK, this._virtualDocument.AddFavoriteToCurrentUser((string)dto.item));
        }

Of course I could be using Content-Type: application/x-www-form-urlencoded as explained hereand the ModelBinder should work fine, but there are some differences depending on the ASP.Net version, and I prefered to just follow the json route.

No comments:

Post a Comment