system.net.httpClient automatic JSON handling causing issues

My endpoint is expecting a decimal and for some reason when the httpclient is sending the json it’s turning my numbers to literals. I’m not sure how to get it to not wrap those in quotes.

Previously using the httplib I was dumping the JSON to a string and sending it manually and that was working as it should.

I have tried seeing if I can force it to a decimal when I generate the JSON but that didn’t make a difference. What else might I try for this?

image

Does this work?

data = {
  'key': float(value)
}

Not sure what type “Edm.Decimal” is, though. You may be missing some information.

Unfortunately no that didn't work same issue.

That is the Entity Data Model or EDM (C#/.NET land which is the Epicor base framework I'm sending to) type that our ERP system is expecting:

data = {
   Number01: 12345.00
}

What it is getting:

data = {
   Number01: '12345'
}
val = 3

data = {
  'foo': float(val)
}

print system.util.jsonEncode(data)

Results:

{"foo":3.0}
>>> 

Check the JSON being sent like this. Only way I could see it being a literal is with your use of Decimal or str or if the variable is actually a string and you don’t convert it with float().

edit: Hmm, not sure this is a good sanity check after all, the httpClient uses a different method of converting the data to JSON.

Yeah seems to work fine with httpClient as well. You can see it on the wire too:

Yeah, httpbin gives me what I expect:

I wonder if the single quotes in your logged output aren’t misleading - maybe it is getting a raw number, but the lack of a trailing zero is making it fail to cast?

Possibly but what about the old method works that is different from the httpclient I wonder? Below is the old and new way I'm trying to send the data. This is only a portion of the total function, but everything outside of these sections is the same

This is the way I am doing it today and is working as expected

data = {
					 'Company': "WCI",
					 'Key1': "PLCLoggedData",
					 'Key2': res,
					 'Key3': "",
					 'Key4': "",
					 'Key5': str(int(time.time())),
					 'Date01': datetime.date.today().strftime("%Y-%m-%d"),
					 'Number01': str(seconds_since_midnight),
					 #'Number02': meter,
					 'Number03': bpm,
					 'Number04': bpmtarget,
					 #'Number05': 0.00,
					 'Number06': currmeter,
					 'ShortChar01': jobnum,
					 'CheckBox01': status
				   }

conn = httplib.HTTPSConnection(settings[0].value)
conn.request("POST", "/" + str(settings[1].value).strip() + "/api/v2/odata/WCI/Ice.BO.UD02Svc/UD02s", json.dumps(data), BuildEpicorHeaderInfo(settings))

This is the new way I'm trying to do that is causing the error

payload = {
					 'Company': "WCI",
					 'Key1': "PLCLoggedData",
					 'Key2': res,
					 'Key3': "",
					 'Key4': "",
					 'Key5': str(int(time.time())),
					 'Date01': datetime.date.today().strftime("%Y-%m-%d"),
					 'Number01': seconds_since_midnight,
					 #'Number02': meter,
					 'Number03': bpm,
					 'Number04': bpmtarget,
					 #'Number05': 0.00,
					 'Number06': currmeter,
					 'ShortChar01': jobnum,
					 'CheckBox01': status
				   }

response = httpClient.post(url = BuildEpicorEndpointURL(settings, endpoint), data = payload, params = getvars, headers = BuildEpicorHeaderInfo(settings))

I am going to run fiddler on my Epicor server and watch for the incoming request to see the difference between the two. It will take me a bit to setup, but I'll report back later.

Even stranger is that the new method is working fine on some calls and not others. In the new method case the POST for tag 405 failed and gave us a 400 error

But the old method is working on all calls. All 201 responses the old way.

It’s the same dictionary in both cases just sent through different libraries so weird! gah!

Once you get fiddler or Wireshark or something that lets you watch the request/response I’m sure the problem will reveal itself.

Looks like it’s taking it to an exponent notation using the system.net.httpClient

This is using the old httplib.HTTPConnection method. No to the E power here

Hmm. I don’t know if there’s a way to switch it off. The E notation is valid JSON syntax, your backend application is at fault here.

1 Like

As a workaround, try encoding into a JSON string using system.util.jsonEncode. If that appears to encode it without using scientific notation then you can post this JSON string as your data, and you’ll have to explicitly include a Content-Type header for JSON rather than relying on automatic detection.

1 Like

You don’t get the benefit of the automatic conversion, but you can always json.dumps your dictionary and set the Content-Type header appropriately; you still get the other benefits of httpClient()

1 Like

Unfortunately, I don’t have any control over how Epicor ICE Framework is parsing the incoming data so I do have to figure it out on the sending side. It will hopefully be quicker than getting a billion dollar developer to pivot LOL.

So that was my next question is can I just send it as a raw string like I have been. Right there with you guys, but you beat me to it!

That being said it seems to be ignoring my supplied content type. Is there another way I should be setting content type other than header dictionary?

I set content type along with my other headers

But that is not what is sent through. Is it being overriden?
image

For sanity I created a much smaller isolated script is this a bug I am seeing @Kevin.Herron or @PGriffith? We are on 8.0.10 if we upgraded would I have the ability to control that header?

Yes, looks like it was a bug fixed in 8.0.15. Any version after that should work.

1 Like

Confirmed that on our 8.1.2 instance all is well. Thanks much! Guess I know what we are doing this weekend :slight_smile:

2 Likes

We are live on 8.1.2 and can confirm in production the workaround is working just fine. Thank you both! Until next time :slight_smile:

2 Likes