Serialization Exception: unexpected character '<' - c#

I have this simple method which suppose to get weather data, when I call it this error occur:
System.Runtime.Serialization.SerializationException was unhandled by user code
HResult=-2146233076
Message=There was an error deserializing the object of type UWpWeather.RootObject. Encountered unexpected character '<'.
public async static Task <RootObject> GetWeather(double lat, double lng) {
var http = new HttpClient();
var response = await http.GetAsync("http://api.openweathermap.org/data/2.5/forecast/daily?q=leeds&type=accurate&mode=xml&units=metric&cnt=3&appid= MY AIP-KEY");
string result = await response.Content.ReadAsStringAsync();
var serializer = new DataContractJsonSerializer(typeof (RootObject));
var ms = new MemoryStream(Encoding.UTF8.GetBytes(result));
var data = (RootObject) serializer.ReadObject(ms);
return data;
}

The API does not honour any of the HTTP content or Accept headers you pass through on the request, but rather it sets the content-type of the response based on the query string parameter.
Your initial URL:
http://api.openweathermap.org/data/2.5/forecast/daily?q=leeds&type=accurate&mode=xml&units=metric&cnt=3&appid=
MY AIP-KEY"
What it should be:
http://api.openweathermap.org/data/2.5/forecast/daily?q=leeds&type=accurate&mode=json&units=metric&cnt=3&appid=
MY AIP-KEY"
That should allow you to deserialize it into your RootObject correctly.
Caveat: I don't have your root object implementation, so I could only verify up until getting a JSON-formatted response back.

I found the answer, my first mistake was using Xml instead of Json when calling my data. second, when I used this website (json2csharp) to convert Json to series of classes that represent my Json it created it fine except one which created as a list public List<List> list { get; set; }
I simply removed that one and my code now is working just fine. thanks all for your support.

Related

Get the copy task id in SpringCM

I'm following this link to copy a document from one folder to another in springCM:
https://developers.docusign.com/clm-api/guides/task-api
at this section of the page: Copy Document Tasks - Initiate Copy - Sample Request
The copy is successful and I can verify that there is a new document in the destination folder, but I'm also trying to get back the object that contains the status and the Href.
But I'm getting an exception when try to desalinize the object to my custom one that matches the response.
"Unexpected character encountered while parsing value: \u001f. Path '', line 0, position 0."
This is my code along with my custom object:
// my custom object
public class SCMDocumentCopyResponse
{
public string Status { get; set; }
public string Href { get; set; }
}
// when in initiating the request
var content = JsonConvert.SerializeObject("{\"DocumentsToCopy\":[{\"Href\":\"https://myapi/documents/785252f4ABC\"}],\"DestinationFolder\":{\"Href\":\"https://myapi/folders/f77e277a-\XYZ"}}");
var buffer = Encoding.UTF8.GetBytes(content);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await client.PostAsync(url, byteContent).ConfigureAwait(false);
string result = await response.Content.ReadAsStringAsync();
var final = JsonConvert.DeserializeObject<SCMDocumentCopyResponse>(result);
What am I doing wrong? Can you give me a working code?
Looks like you have html response from your server.
And when you try to deserialize response - you got this exception.
Try to check you response. Is json really there, as you expect.
Also, you should check response status. And try to deserialize only success response.

API Controller unable to read Json from POST body

Background
I'm sending JSON in my body to my API controller but keep getting the following error.
{"":["Unexpected character encountered while parsing value: {. Path
'', line 1, position 1."]}
My HTTP request
HttpClient client = new HttpClient();
HttpRequest httpRequest;
HttpResponseMessage httpResponse = null;
httpRequest = new HttpRequest("", HostnameTb.Text, null);
var values = new Dictionary<string, string>
{
{ "APIKey", APIKeyTb.Text }
};
string json = JsonConvert.SerializeObject(values);
StringContent content = new StringContent(json.ToString(), Encoding.UTF8, "application/json");
httpResponse = client.PostAsync(HostnameTb.Text, content).Result;
var responseString = await httpResponse.Content.ReadAsStringAsync();
My Controller looks like this.
[HttpPost]
public void Post([FromBody] string value)
{
//Never gets here.
}
The Json in the body.
{"APIKey":"1283f0f8..."}
Question
I would prefer to use the .Net Core [From Body] functionality, rather than getting the content manually.
I would expect the JSON string to be available in the string Value parameter.
What am I missing?
ASP.NET Core tries to deserialize {"APIKey":"1283f0f8..."} from JSON into a string value, and fails, because it expects the input to be a valid JSON string.
In other words, if your body was "{\"APIKey\":\"1283f0f8...\"}" you would have the JSON string in the input variable as you expect.
In order to get the APIKey value without changing the HTTP request, create an input type:
public class Input
{
public string ApiKey { get; set; }
}
and use that as the input of your controller action:
[HttpPost]
public void Post([FromBody] Input input)
{
var apiKey = input.ApiKey;
// etc
}
Alternatively, change your HTTP request to send a string:
// ...
var content = new StringContent(JsonConvert.SerializeObject(json), Encoding.UTF8, "application/json");
// ...
Note the use of JsonConvert.SerializeObject() instead of ToString(); "foo".ToString() is still just "foo", while you want "\"foo\"".
That's not how this works. [FromBody] invokes a serializer to deserialize the request body. Then, the modelbinder attempts to bind that to the param. Here, it cannot do that because you're binding to a string, and the request body is a dictionary. Essentially what's happening under the hood (pseudo-code) is:
value = JsonConvert.DeserializeObject<string>(dictionaryAsJson);
You're getting a deserialization error from JSON.NET because it can't parse the JSON into a string.
If you want the value as a string, then you should post is as something like text/plain instead of application/json. Otherwise, you'll need to bind to a type that actually represents the JSON object coming in, which would be a Dictionary<string, string> here.
I had the same issue with ASP.NET Core 3.1. I was POSTing a JSON to my API controller that looked like:
public JsonResult Save([FromBody]MainDetails obj){ ... }
The problem in my case was that a property ChildDetails.StartDate of my MainDetails object was of type DateTime, and I was sending a null value in JSON. This was causing the deserialization to fail at the controller. I changed the property type to DateTime? from DateTime to make it work.
Basically, one needs to check and ensure that the JSON that you POST is valid for the target object to which you are deserializing it. If you have non-nullable properties for which the value sent in JSON is null, then your deserialization will fail (without telling you why).
Hope this helps.

Unable to Parse JSON Response

I have a service that sends JSON response. The controller method looks as follows:
string varStr = "{proper JSON here}";
public string GetListofResourcesInSubscription(string subscriptionId)
{
// Uncomment any option below to test. The error persists either way.
//return varStr; --- Option 1
return JsonConvert.SerializeObject(JObject.Parse(varStr)); // Option 2
}
The method that gets the response is like the following:
response = outgoingRequest.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK)
{
responseStream = response.GetResponseStream();
using (var reader = new StreamReader(responseStream))
{
string strResp = reader.ReadToEnd();
JObject joResponse = JObject.Parse(strResp); // throws error
JArray objArray = (JArray)joResponse["value"];
// other processing
}
}
Irrespective of the return statement selected in the controller method above, the response parser is always throwing an error while it is trying to parse the response.
Changing the parsing line to the following resolves the issue but it is not clear to me why it is so.
JObject joResponse = JObject.Parse(JsonConvert.DeserializeObject<string>(strResp));
Also, I want to know what is the correct way of sending a JSON response from an ASP.NET web api2 controller. I don't want to use models for creating the response because I have JSON strings that I want to return directly instead of creating models out of them.
Update 1:
The error is the following:
"Error reading JObject from JsonReader. Current JsonReader item is not an object: String. Path '', line 1, position 6546."} System.Exception {Newtonsoft.Json.JsonReaderException}
You can't deserialize a complex JSON object back to a string. Your example won't work, because you are assuming the JSON evaluates to a string:
JObject joResponse = JObject.Parse(JsonConvert.DeserializeObject<string>(strResp))
You might have more success either using a JObject, or the alternative is to deserialize into a Dictionary, or into a known type.
var dictionary = JsonConvert.DeserializeObject<<Dictionary<string,object>>(strResp);
The problem here was the return type of the controller function. As it was returning string, the serialization to string was required to get correct result. The correct way of returning JSON is to return a JToken as explained here. So the controller needs to be changed to the following:
public JToken GetListofResourcesInSubscription(string subscriptionId)
{
return JObject.Parse(varStr);
}

RestSharp get serialized output

I am looking for a way to access the serialized result of the AddBody call.
I am using the built in RestSharp Serializer.
Example:
class Foo
{
public string FooField;
}
void SendRecord()
{
var f = new Foo();
f.FooField = "My Value";
request.AddBody(f);
// How do I get the serialized json result of the add body call without
// data? I would like to log the serialized output of the add body call to
// the database.
//Expected {"FooField":"My Value"}
var response = client.Execute(request);
}
I figured it out by finding this post.
request.Parameters.Where(p => p.Type == ParameterType.RequestBody).FirstOrDefault();
I also struggled with this (using v107 preview) and couldn't find any examples of logging the actual string sent to the server. The issue I was trying to debug was getting the right serialisation settings so the object was no use to me.
The only way I could find to get the serialized body as a string was to hook into the OnBeforeRequest event on the RestRequest:
var request = new RestRequest("/", Method.Post)
.AddHeader(KnownHeaders.ContentType, "application/json", false)
.AddJsonBody(myObj);
request.OnBeforeRequest = async (httpRequest) =>
{
var requestBodyStr = await httpRequest.Content.ReadAsStringAsync();
Trace.WriteLine($"Request body: {requestBodyStr}");
};
RestSharp itself doesn't expose the serialized request body when you pass an object to it.
There is a way to get at it though, I just posted over here:
https://stackoverflow.com/a/75537611/2509281
Right off the RestSharp homepage (http://restsharp.org/):
// execute the request
RestResponse response = client.Execute(request);
var content = response.Content; // raw content as string <~~~~~~~~~~

What is the best way of reading/parsing WEB API 2 IHttpActionResult responses?

I have following web api method:
public IHttpActionResult Get(int id)
{
var person = _personRepository.GetPersonByID(id);
if (person == null)
return NotFound();
return Ok<Person>(person);
}
And following client calling method:
var data = default(IEnumerable<T>);
var response = _client.GetAsync(relativeUri).Result;
response.EnsureSuccessStatusCode(); // Throw on error code.
if (response.IsSuccessStatusCode)
{
//string dataString = response.Content.ReadAsStringAsync().Result;
data = response.Content.ReadAsAsync<IEnumerable<T>>().Result;
}
else
{
//return response status code/reason phrase
}
after ReadAsAsync call is finished, data variable indicates a collection of type T with count matching returned rows but all objects (elements) are having null valued properties or empty.
Actual values are not being populated in properties.
Fiddler shows the JSON string. Even, ReadAsStringAsAsync() method returns JSON string.
Is there a better way to parse JSON into T type using one of ReadAsXXXX() methods?
Thanks,
-Jignesh
I just wanted to update that I have found the root cause of the issue that I was facing.
The code sample that I mentioned is actually the correct way of calling web api methods.
In my case, JSON string was formatted in Camel Casing at server side and at client side, default formtting was used.
this is server side code which was causing the issue:
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
As soon as this was removed, it started working.
Clearly, ReadAsAsync method could not find the matching properties and therefore all values were being dropped.
Thanks,
-Jignesh

Categories