Unexpected character encountered while parsing value line 1, position 1 - c#

I'm building .Net Core 3.1 Web API. To send requests to Web API. I'm using System.Net.Http library. I put JSON into POST request body. This is Web API side handler:
using Microsoft.AspNetCore.Mvc;
[ApiController]
public class MyController : ControllerBase
{
[HttpPost]
public int HandleRequest([FromBody] string jsonString)
{
return 1;
}
}
The code below sends empty ArrayList to Web API but it always returns "Unexpected character encountered while parsing value line 1, position 1.".
var serializedData = new JavaScriptSerializer().Serialize(new ArrayList());
var content = new StringContent(serializedData, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content);
return response.Result.Content.ReadAsStringAsync();
I've tried to use JsonConvert and played around the object to serialize but it always returns the same error. But then I've found that if I make serialization twice then it starts working. So code below works - sends the request without any errors and the data on Web API side is correct.
var serializer = new JavaScriptSerializer();
var serializedData = serializer.Serialize(serializer.Serialize(new ArrayList()));
var content = new StringContent(serializedData, Encoding.UTF8, "application/json");
var response = client.PostAsync(url, content);
return response.Result.Content.ReadAsStringAsync();
Why do I need to do double serialization to make it work?

First, when you are using async methods you should add await keyword:
var response = await client.PostAsync(url, content);
return await response.Result.Content.ReadAsStringAsync();
Secondly, you are sending an array, so why not just try to send it and get as object not string:
var updateData = new ArrayList();
var jsonObject = JsonConvert.SerializeObject(updateData);
var content = new StringContent(jsonObject, Encoding.UTF8, "application/json");
var res = await apiClient.PutAsync(url, content);
And then in WebAPI:
[HttpPost]
public int HandleRequest([FromBody] ArrayList list)
{
return 1;
}

var serializedData = new JavaScriptSerializer().Serialize(new ArrayList());
Console.WriteLine(serializedData);
// Output: []
var serializer = new JavaScriptSerializer();
var serializedData = serializer.Serialize(serializer.Serialize(new ArrayList()));
Console.WriteLine(serializedData);
// Output: "[]"
You have an error because your endpoint expects string but in first serialization you are sending an array.
Second serialization works, because first you serialize ArrayList to string and then that string to string. In the end you by accident send a serialized string and endpoint can deserialize it.
Error "Unexpected character encountered while parsing value line 1, position 1." means that server receives at first character [ but it expects " because it tries deserialize JSON to string - but it was array.

Related

Send a JSON request to another web site from C# code behind in an ASP.NET MVC project

I'm working with ASP.NET MVC (backend being C#) and I'm trying to send a json that would look like this :
{
"store_id": "store3",
"api_token": "yesguy",
"checkout_id": "UniqueNumber",
"txn_total": "10.00",
"environment": "qa",
"action": "preload"
}
to another web site, suppose it's something like:
https://TestGate.paimon.com/chkt/request/request.php
Through some research I found this :
Send json to another server using asp.net core mvc c#
Looks good but I'm not working in core, my project is just normal ASP.NET MVC. I don't know how to use json functions to send it to a web site.
Here is what I tried (updated after inspired by Liad Dadon answer) :
public ActionResult Index(int idInsc)
{
INSC_Inscription insc = GetMainModelInfos(idinsc);
JsonModel jm = new JsonModel();
jm.store_id = "store2";
jm.api_token = "yesguy";
jm.checkout_id = "uniqueId";
jm.txn_total = "123.00";
jm.environment = "qa";
jm.action = "preload";
var jsonObject = JsonConvert.SerializeObject(jm);
var url = "https://gatewayt.whatever.com/chkt/request/request.php";
HttpClient client = new HttpClient();
var content = new StringContent(jsonObject, System.Text.Encoding.UTF8, "application/json");
System.Threading.Tasks.Task<HttpResponseMessage> res = client.PostAsync(url, content);
insc.response = res.Result; // This cause an exeption
return View(insc);
}
When ths Json is posted correctly, the other web site will answer me with is own Json :
{
"response" :
{
"success": "true",
"ticket": "Another_Long_And_Unique_Id_From_The_Other_Web_Site"
}
}
What I need to do is retreive this Json answer, once I have it, the rest is piece of cake.
Infos :
After the PostAsync function, var res contains this :
It looks like you might not be correctly handling an asynchronous task — the WaitingForActivation message you’re seeing, rather than being a response from our API, is in fact the status of your task.
The task is waiting to be activated and scheduled internally by the .NET Framework infrastructure.
It seems you might need to await⁽²⁾ the task to ensure it completes or access the response with await client.PostAsync(url, content);. for adding await you need to add async to controller⁽¹⁾ action.
public async Task<ActionResult> Index(int idInsc) //Change here [1]
{
INSC_Inscription insc = GetMainModelInfos(idinsc);
JsonModel jm = new JsonModel();
jm.store_id = "store2";
jm.api_token = "yesguy";
jm.checkout_id = "uniqueId";
jm.txn_total = "123.00";
jm.environment = "qa";
jm.action = "preload";
var jsonObject = JsonConvert.SerializeObject(jm);
var url = "https://gatewayt.whatever.com/chkt/request/request.php";
HttpClient client = new HttpClient();
var content = new StringContent(jsonObject, System.Text.Encoding.UTF8, "application/json");
System.Threading.Tasks.Task<HttpResponseMessage> res = await client.PostAsync(url, content); //Change here [2]
insc.response = res.Result; // This cause an exeption
return View(insc);
}
This is how I would post a JSON object to somewhere using Newtonsoft.Json package, HttpClient and StringContent classes:
using Newtonsoft.Json;
var object = new Model
{
//your properties
}
var jsonObject = JsonConvert.SerializeObject(object);
var url = "http://yoururl.com/endpoint"; //<- your url here
try
{
using HttpClient client = new();
var content = new StringContent(jsonObject , Encoding.UTF8,
"application/json");
var res = await client.PostAsync(url, content);
}
Please make sure your function is async and that you await the client.PostAsync fucntion.
If someone is wondering how I finally pulled it off (with other's help) here it is :
var url = "https://gatewayt.whatever.com/chkt/request/request.php";
HttpClient client = new HttpClient();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var content = new StringContent(jsonObject, System.Text.Encoding.UTF8, "application/json");
var res = await client.PostAsync(url, content);
var jsonRes = await res.Content.ReadAsStringAsync();
This line is important var jsonRes = await res.Content.ReadAsStringAsync(); the object jsonRes will be a string value, which is actually the response. The var res will only be the status of the response, not the actual response.

The PostAsync in HttpClient doesn't send data to my webapi

I've created a HttpClient instance to invoke an API with post method.
using (var client = new HttpClient())
{
var person = new Stu();
person.ApplicantId = "48751889-D86E-487B-9508-000EAB65F11F";
var json = JsonConvert.SerializeObject(person);
var data = new StringContent(json, Encoding.UTF8, "application/json");
var url = "http://localhost:52085/api/CollegeService/IsCoolegeStudent";
// var client = new HttpClient();
var response = await client.PostAsync(url, data);
string result = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(result);
}
public class Stu
{
public string ApplicantId { get; set; }
}
When I check my API out , I receive ApplicantId of my object is Null.
I cant not figure out why ApplicantId is Null.
Finally I've changed my [FromForm] to[FromBody] in my API and it worked correctly but it stuck on this line var response = await client.PostAsync(url, data);and doesn't go on.
the await keyboard make my app stuck ,I've changed it this way
var response = await client.PostAsync(url, data).ConfigureAwait(false);
but I didn't figure it out why it cause this problem.
If you using FromForm attribute, you should use FormUrlEncodedContent instead of StringContent as content type when you send POST message. If you still want send json - change FromForm at IsCoolegeStudent method to FromBody.

Error converting JSON response from backend to type with JsonConvert.DeserializeObject

So I am having this weird problem with deserializing a response from my BackEnd, The request works fine and the BackEnd succesfully responds with a result.
This is the error I get:
'Error converting value "{"Succes":true,"AuthKey":"$2a$13..."}" to type 'FrontEnd.LoginUserResponse'. Path '', line 1, position 96.'
The code I am using to make the HTTP call and deserialize the string:
public async Task<bool> loginUser(LoginUserData login)
{
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(login), Encoding.UTF8);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage responseMessage = await httpClient.PostAsync("http://ip/webBackEnd/api/user/login", httpContent);
string response2 = responseMessage.Content.ReadAsStringAsync().Result;
LoginUserResponse response = JsonConvert.DeserializeObject<LoginUserResponse>(response2);
if (response.Succes)
{
return true;
}
else { return false; }
}
I tried making a response2 to check the value and I have noticed it does something weird with 3 backslashes. This might be the reason why this is occuring.
This is response2 that visual studio shows when I click the magnifying glass:
"{\"Succes\":true,\"AuthKey\":\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\"}"
When I hover on visual studio:
https://imgur.com/a/jUyLz6d
This is the Class that it is converting to
public class LoginUserResponse
{
[JsonProperty("succes")]
public bool succes { get; set; }
[JsonProperty("authkey")]
public string authkey { get; set; }
}
The Backend code:
[HttpPost]
[Route("login")]
public string Login([FromBody]LogInData logInData)
{
IReadUser.LogInRequest request = new IReadUser.LogInRequest(logInData);
IReadUser.LogInResponse backResponse = readUser.logIn(request);
LogInResponse response = new LogInResponse();
response.succes = backResponse.Succes;
response.authkey = backResponse.AuthKey;
return JsonConvert.SerializeObject(response);
}
EDIT // SOLUTION
Ok so, the front-end was fine, it was my backend code sending a double serialised string. I used
return JsonConvert.SerializeObject(response);
When I also could have used
return response;
So if you every get an error like this, it's probably the backend doubling up on the serialization.
Thanks for all the help!
Couple of things:
1. you should await responseMessage.Content.ReadAsStringAsync():
public async Task<bool> loginUser(LoginUserData login)
{
var httpContent = new StringContent(JsonConvert.SerializeObject(login), Encoding.UTF8);
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var responseMessage = await httpClient.PostAsync("http://ip/webBackEnd/api/user/login", httpContent);
var response2 = await responseMessage.Content.ReadAsStringAsync();
var response = JsonConvert.DeserializeObject<LoginUserResponse>(response2);
return response.Succes
}
And 2. Based on your image it looks like the response from your backing service is being serialized twice.
1:
"{\"Succes\":true,\"AuthKey\":\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\"}"
2:
"\"{\\\"Succes\\\":true,\\\"AuthKey\\\":\\\"$2a$11$tQCw4zGGd2J2fXAxAN68Ruu3xheTuMKq4EHbeLtc9DAa2rgzJe8bS\\\"}\""
now to deserialize you have to do it twice
var s = JsonConvert.DeserializeObject<string>(response2);
var response = JsonConvert.DeserializeObject<LoginUserResponse>(s);
Probably best to fix the service if that's actually what is happening

Passing a custom object to a REST endpoint with C#

I have a rest endpoint that accepts a single custom object parameter containing two properties.
Let's call the param InfoParam
public class InfoParam
{
public long LongVar { get; set; }
public string StringVar { get; set; }
}
My code I have is as follows:
infoParam.LongVar = 12345678;
infoParam.StringVar = "abc"
var myRequest = (HttpWebRequest)WebRequest.Create(url);
myRequest.Method = "POST";
var content = string.Empty;
using (var theResponse = (HttpWebResponse)MyRequest.GetResponse())
{
using (var stream = theResponse.GetResponseStream())
{
using (var sr = new StreamReader(stream))
{
content = sr.ReadToEnd();
}
}
}
So I have the InfoParam variable, with the two values, but I can't figure out where to pass it in to the REST endpoint.
You need to turn the object into a stream of bytes that can be added to the Request stream - which will in turn be sent as the HTTP POST body. The format of these bytes needs to match what the server expects. REST endpoints usually expect these bytes to resemble JSON.
// assuming you have added Newtonsoft.JSON package and added the correct using statements
using (StreamWriter writer = new StreamWriter(myRequest.GetRequestStream()) {
string json = JsonConvert.SerializeObject(infoParam);
writer.WriteLine(json);
writer.Flush();
}
You'll probably want to set various other request parameters, like the Content-Type header.
You have to write it int the `Content (and set content-type). Check out How to: Send data by using the WebRequest class
The recommendation is to use System.Net.Http.HttpClient instead.
Please note that you should know what content the server expects ('application/x-www-form-urlencoded`, json, etc.)
The following snippet is from POST JSON data over HTTP
// Construct the HttpClient and Uri. This endpoint is for test purposes only.
HttpClient httpClient = new HttpClient();
Uri uri = new Uri("https://www.contoso.com/post");
// Construct the JSON to post.
HttpStringContent content = new HttpStringContent(
"{ \"firstName\": \"Eliot\" }",
UnicodeEncoding.Utf8,
"application/json");
// Post the JSON and wait for a response.
HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(
uri,
content);
// Make sure the post succeeded, and write out the response.
httpResponseMessage.EnsureSuccessStatusCode();
var httpResponseBody = await httpResponseMessage.Content.ReadAsStringAsync();
Debug.WriteLine(httpResponseBody);
In your case the content would be something like this
HttpStringContent content = new HttpStringContent(
JsonConvert.SerializeObject(infoParam), // using Json.Net;
UnicodeEncoding.Utf8,
"application/json");

Web API json responds faulty json [duplicate]

I am trying to fix an ASP.NET WebAPI method where a Json response is required. However it's returning a string instead.
Initially it was returing XML format, but I've added this line to the mvc code in App_Start\WebApiConfig.cs in order to return Json by default.
config.Formatters.Remove(config.Formatters.XmlFormatter);
We've updated the c# method as follows to use NewtonSoft:
public string Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
string resp = DynAggrClientAPI.openSession(userid, pwd);
JsonSerializer ser = new JsonSerializer();
string jsonresp = JsonConvert.SerializeObject(resp);
return resp;
}
The resp var is coming back as a string type:
"{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}"
and jsonresp var looks like this :
"\"{status:\\\"SUCCESS\\\",data:[\\\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\\\"]}\""
and in Chrome's F12 dev tools, the data object is :
""{status:\"SUCCESS\",data:[\"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d\"]}""
and in Console tools, the result of angular.fromJson(data) :
"{status:"SUCCESS",data:["4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"]}"
I would appreciate some advice on how to properly return the Json object, and NOT in any string type.
UPDATE
By intercepting the resp var, and using Mr. Chu's suggestion below, I can successfully achieve a nice clean Json object on the client.
The key is that resp needs to contains double quotes around both key:value pairs:
public HttpResponseMessage Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
string resp = DynAggrClientAPI.openSession(userid, pwd);
resp = "{\"status\":\"SUCCESS\",\"data\":[\"194f66366a6dee8738428bf1d730691a9babb77920ec9dfa06cf\"]}"; // TEST !!!!!
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(resp, System.Text.Encoding.UTF8, "application/json");
return response;
}
in Chrome console, the response is :
Object {status: "SUCCESS", data: Array[1]}
data: Array[1]
status: "SUCCESS"
__proto__: Object
resp is already a JSON string, but it is not valid JSON (the keys are not wrapped in quotes ("). If it is returned to angular, the JavaScript JSON.parse() method is unable to deserialize it. However, you can use JSON.NET in deserialize it to a JObject and serialize it again into valid JSON and create your own HttpResponseMessage...
public HttpResponseMessage Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
var jObject = JObject.Parse(resp);
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(jObject.ToString(), Encoding.UTF8, "application/json");
return response;
}
Or you can just return the JObject and have Web API serialize it for you...
public JObject Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
var jObject = JObject.Parse(resp);
return jObject;
}
In either case, the Web API call should return this JSON, which is now valid...
{
"status": "SUCCESS",
"data": [
"4eb97d2c6729df98206cf214874ac1757649839fe4e24c51d21d"
]
}
In the angular code, you'd have to dig out the session id which is stored in an array called data...
userService.openUserSession(rzEnvJson).then(function (response) {
var sessionResponse = response.data; // or simply response, depending if this is a promise returned from $http
$rootScope.rgSessionVars.sessionID = sessionResponse.data[0];
});
The key to what is going on here is in the comment made by Mike Cheel; serialization is happening twice, once in the OP's code and once by Asp.Net WebAPI. That is why a string is returned instead of a Json object.
I was encountering the exact same thing. Here is a hello world example showing the problem. I first did something like this:
[Route("getall")]
public string GetAllItems()
{
var result = new
{
x = "hello",
y = "world"
};
return JsonConvert.SerializeObject(result);
}
I then tried to so something like this, thinking that I needed to return IHttpActionResult to resolve this:
[Route("getall")]
public IHttpActionResult GetAllItems()
{
var result = new
{
x = "hello",
y = "world"
};
return Ok(JsonConvert.SerializeObject(result));
}
Both these controller actions gave me a string rather than the Json object that I was wanting; so I go this:
"{\"x\":\"hello\",\"y\":\"world\"}"
Finally I saw the comment by Mike and realized that I needed to return the .Net object directly and just let WebAPI handle the serialization. So instead of returning this:
return Ok(JsonConvert.SerializeObject(result));
return this:
return Ok(result);
Then I got the result that I was expecting:
{"x":"hello","y":"world"}
I don't see what this has to do with AngularJS, but your problem is simple. Your data object is JSON encoded. So you could almost certainly access data.JsonRequestBehavior and it would be 1. But your Data field inside it is AGAIN JSON-encoded. You need to decode it before trying to use it - it's just a string when you get to this callback:
var myData = angular.fromJson(data.Data);
console.log(myData.data);
Note that your data.Data object is itself another wrapper - an array. You almost certainly want myData.data[0] to go into that sessionID field...
These other solutions weren't working for me, but I was able to get something like this to work:
[HttpGet]
public async Task Get(CancellationToken cancellationToken)
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "");
await using (Stream contentStream = await DynAggrClientAPI.openSessionStreamAsync(userid, pwd, cancellationToken))
{
Response.StatusCode = (int)HttpStatusCode.OK;
Response.ContentType = "application/json";
await contentStream.CopyToAsync(Response.Body, cancellationToken);
}
}
I had a similar problem (raw json in string, like resp) and this worked fine for me in .Net 6. I haven't checked previous versions.
[HttpGet]
public IActionResult Get()
{
string userid = UrlUtil.getParam(this, "userid", "");
string pwd = UrlUtil.getParam(this, "pwd", "" );
string resp = DynAggrClientAPI.openSession(userid, pwd);
return Content(resp, "application/json"):
}

Categories

Resources