I am struggeling to consume an API endpoint (http://ogre.adc4gis.com/convertJson) that takes JSON data and returns a zip file. Visiting http://ogre.adc4gis.com shows the parameters the api expects.
It absolutely works using Postman and using Javascript, so I am wondering what I am doing wrong with in my c# code.
This an example JSON string, which can be posted to the API:
{ "displayFieldName": "NUM_GES2_1", "fieldAliases": { "NUM_GES2_1": "NUM_GES2_1" }, "geometryType": "esriGeometryPoint", "spatialReference": { "wkid": 102362, "latestWkid": 4647 }, "fields": [{ "name": "NUM_GES2_1", "type": "esriFieldTypeString", "alias": "NUM_GES2_1", "length": 254 }], "features": [{ "attributes": { "NUM_GES2_1": "001-08" }, "geometry": { "x": 32674408.2009, "y": 5790291.4659000002 } }] } For completenes sake, this is the action method, that invokes the call to the bespoke api:
[HttpGet] [Route("{id:int}/Attributive")] public async Task<IActionResult> GetFeatureClass(int id) { var client = new HttpClient(); client.DefaultRequestHeaders.Accept.Clear(); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //get token from internal api var token = await _tokenService.RefreshToken(); //dummy address that returns a single object for development var tokenObjString = await client.GetStringAsync( $"http://url.to/MapServer/{id}/query?where=1%3D1&objectIds=4&f=pjson&token={token}" ); var data = await PostDataToOgrService(tokenObjString); var response = File(data, "application/octet-stream", "FeatureClass.Zip"); return response; } Here comes the part where the actual call to the api is made. Payload is the escaped json string. The get rid of all the escapes, I've just converted it to an object and then back again.
public async Task<byte[]> PostDataToOgrService(string payload) { var client = new HttpClient(); var newJson = JsonConvert.DeserializeObject(payload); var pairs = new Dictionary<string, object> { { "json", newJson } }; var json = JsonConvert.SerializeObject(pairs); var content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await client.PostAsync("http://ogre.adc4gis.com/convertJson", content); if (response.IsSuccessStatusCode) { return await response.Content.ReadAsByteArrayAsync(); } else { throw new Exception("Something went wrong"); } } Every call returns an Error 400 Bad Request:
{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers: { Date: Fri, 08 Sep 2017 06:15:01 GMT ETag: W/"27-Ag3Jnk3T/v6dECAccJTzg4aO/wA" X-Powered-By: Express Access-Control-Allow-Origin: * Access-Control-Allow-Methods: POST Access-Control-Allow-Headers: X-Requested-With Access-Control-Expose-Headers: Content-Disposition Content-Length: 39 Content-Type: application/json; charset=utf-8 }} Things I've tried:
Do not convert the payload to an object and just use it as it is:
var pairs = new Dictionary<string, string> { { "json", payload } }; var json = JsonConvert.SerializeObject(pairs); var content = new StringContent(json, Encoding.UTF8, "application/json"); Build the string content raw:
payload = "{ \"json\": " + payload + "}"; Use "application/x-www-url-formencoded" as Content-Type
I am a total loss here. What am I doing wrong?
EDIT As requested, here are the request headers from a successfull postman request:
POST /convertJson HTTP/1.1 cache-control: no-cache Postman-Token: 2976abca-6725-43ce-873e-907c12a9fdee Content-Type: multipart/form-data; boundary=--------------------------829328978588990941765750 User-Agent: PostmanRuntime/6.1.6 Accept: */* Host: ogre.adc4gis.com accept-encoding: gzip, deflate content-length: 629 Connection: keep-alive
Bad Requesterror when I send the above-mentioned JSON to the endpoint via Postman. and what isvar token = await _tokenService.RefreshToken();. Is it mandatory? and what is your intent byFile(data, "application/octet-stream", "FeatureClass.Zip");