My xamarin app freezes when i try JsonConvert.DeserializeObject <T> - c#

When I get a json response from HttpClient () and try to deselize, my Xamarin application freezes (UI works, but the code after in class ExecuteGetRequest line 15 does not work). What can it be because of?
No errors.
I call the method of obtaining a list of anime user
ShikimoriMain shikimoriMain = new ShikimoriMain();
var UserInformation = await shikimoriMain.GetUserInformation(Convert.ToInt64(UserID));
var UserAnimeList = await shikimoriMain.GetUserAnimeList(Convert.ToInt64(UserID), 1, 5);
string animeName = UserAnimeList.Anime[0].Anime.Name;
ShikimoriMain.GetUserAnimeList
public async Task<ShikimoriUserAnimeList> GetUserAnimeList(long id, int page, int limit)
{
string[] args = new string[] { ShikimoriCategories.UserID + "/" + id + ShikimoriCategories.UserAnimeList + $"?limit={limit}&page={page}" };
return await ExecuteGetRequest<ShikimoriUserAnimeList>(args);
}
ExecuteGetRequest
public async Task<T> ExecuteGetRequest<T>(string[] args) where T : class
{
T returnedObject;
using (var client = new HttpClient())
{
// client.BaseAddress = new Uri($"{httpApiv1}/{args}");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, httpApiv1 + String.Join("/", args));
request.Headers.TryAddWithoutValidation("User-Agent", "Search Anime");
HttpResponseMessage responseMessage = await client.SendAsync(request);
string json = await responseMessage.Content.ReadAsStringAsync(); // successfully get json
returnedObject = JsonConvert.DeserializeObject<T>(json); // after that the code is not executed
return returnedObject;
}
}
ShikimoriUserAnimeList
public class ShikimoriUserAnimeList
{
[JsonProperty()]
public List<GetAnime> Anime { get; set; }
}
public class GetAnime
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("anime")]
public Anime Anime { get; set; }
}
public class Anime
{
[JsonProperty("id")]
public int ID { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("russian")]
public string NameRU { get; set; }
[JsonProperty("image")]
public AnimeImage AnimeImage { get; set; }
[JsonProperty("kind")]
public string King { get; set; }
[JsonProperty("score")]
public string Score { get; set; }
[JsonProperty("status")]
public string Status { get; set; }
[JsonProperty("episodes")]
public int Episodes { get; set; }
}
public class AnimeImage
{
[JsonProperty("original")]
public string Original { get; set; }
[JsonProperty("preview")]
public string Preview { get; set; }
[JsonProperty("x96")]
public string ImageX96 { get; set; }
[JsonProperty("x48")]
public string ImageX48 { get; set; }
}

For the sake of completion:
An error was being thrown but was not visible in the device log. Wrapping the JsonConvert.DeserializeObject<T>(json) in a try catch block helped finding the Exceptionbeing thrown.
try
{
returnedObject = JsonConvert.DeserializeObject<T>(json); // after that the code is not executed
return returnedObject;
}
catch (Exception ex)
{
... (debug and fix the error that occurred)
}

I had same problem, I've realized that using HttpClient async will cause deadlock in winforms or xamarin (however it works well with Asp) and I changed these lines
HttpResponseMessage responseMessage = await client.SendAsync(request);
string json = await responseMessage.Content.ReadAsStringAsync(); // successfully get json
Like these (Make them work synchronous):
HttpResponseMessage responseMessage = client.SendAsync(request).Result;
string json = responseMessage.Content.ReadAsStringAsync().Result; // successfully get json
And change your method as default synchronous
Take a look at Here

Related

Received Model is empty in the controler after post

I have one API in my webservice App that receives an empty model after the post.
This is the code in my testclient that calls the API
private async void AddDriverPayment()
{
ModelPalmDriverPaymentRequest modelPalmDriverPaymentRequest = new ModelPalmDriverPaymentRequest()
{
SCS_ID = int.Parse(gttDXTextEditAddDriverPaymentSCS_ID.Text),
DriverID = int.Parse(gttDXTextEditAddDriverPaymentDriverID.Text),
Amount = decimal.Parse(gttDXTextEditAddDriverPaymentAmount.Text),
Remark = gttDXTextEditAddDriverPaymentRemark.Text,
PaymentType = gttDXTextEditAddDriverPaymentPaymentType.Text,
PaymentYear = int.Parse(gttDXTextEditAddDriverPaymentPaymentYear.Text),
PaymentWeek = int.Parse(gttDXTextEditAddDriverPaymentPaymentWeek.Text),
DocumentPath = gttDXTextEditAddDriverPaymentDocumentPath.Text,
DatePayment = dateTimePickerAddDriverPayment.Value
};
string JsonData = JsonConvert.SerializeObject(modelPalmDriverPaymentRequest);
System.Net.Http.StringContent restContent = new StringContent(JsonData, Encoding.UTF8, "application/json");
HttpClient client = new HttpClient();
try
{
var response = await client.PostAsync(comboBoxEditPalmAddDriverPayment.Text, restContent);
if (response.IsSuccessStatusCode)
{
var stream = await response.Content.ReadAsStringAsync();
ModelPalmDriverPaymentResponse Result = JsonConvert.DeserializeObject<ModelPalmDriverPaymentResponse>(stream);
textBoxAddDriverPaymentResult.Text = Result.SCS_ID.ToString() + " " + Result.PaymentID.ToString();
}
else
{
textBoxAddDriverPaymentResult.Text = response.StatusCode + " " + response.ReasonPhrase;
}
}
catch (Exception ex)
{
textBoxAddDriverPaymentResult.Text = ex.Message;
}
}
And this is the controller code in the webservice
[Route("palm/AddDriverPayment")]
[ApiController]
public class ControllerPalmDriverPayment : ControllerBase
{
private readonly RepositoryPalmDriverPayment _repositoryPalmDriverPayment = new();
[HttpPost]
public IActionResult AddDriverPayment(ModelPalmDriverPaymentRequest modelPalmDriverPaymentRequest)
{
try
{
return base.Ok(_repositoryPalmDriverPayment.AddDriverPaymemnt(modelPalmDriverPaymentRequest));
}
catch (System.Exception)
{
return base.BadRequest("Nope not working...");
}
}
}
The model looks like this (I copied the model class from the service into the client, so I am sure they are exact the same)
public class ModelPalmDriverPaymentRequest
{
public int SCS_ID;
public int DriverID;
public decimal Amount;
public string? Remark;
public string? PaymentType;
public int PaymentYear;
public int PaymentWeek;
public string? DocumentPath;
public DateTime DatePayment;
}
When I try the code, I can see in debug of the testclient that when I post the data, the model is correct filled,
but then I can see in debug on the webservice that the received model is empty
I have other API's in this webservice that I test with the same client, they all do not have this problem.
I found this question but the answers don't help me
Anybody has any idea what the problem here is ?
EDIT
I found the problem, and wrote it in an answer so anybody with the same problem can find it.
Specify Content-Type: application/json on the client side or use the [FromBody] attribute on your ModelPalmDriverPayemntRequest parameter on the controller method.
More details about FromBody attribute here
I have it working now, the problem was I forgot to provide getters and setters in the model
So once I changed this
public class ModelPalmDriverPaymentRequest
{
public int SCS_ID;
public int DriverID;
public decimal Amount;
public string? Remark;
public string? PaymentType;
public int PaymentYear;
public int PaymentWeek;
public string? DocumentPath;
public DateTime DatePayment;
}
into this
public class ModelPalmDriverPaymentRequest
{
public int SCS_ID { get; set; }
public int DriverID { get; set; }
public decimal Amount { get; set; }
public string Remark { get; set; }
public string PaymentType { get; set; }
public int PaymentYear { get; set; }
public int PaymentWeek { get; set; }
public string DocumentPath { get; set; }
public DateTime DatePayment { get; set; }
}
It worked again

Posting in blazor returns exception stating that "The JSON value could not be converted to System.Int32."

I am new to Blazor and I am encountering the following issue when trying to post for data with an authentication token : at the time of the API call, an exception is lifted with the message "The JSON value could not be converted to System.Int32. Path: $ | LineNumber: 0 | BytePositionInLine: 1."
Here's the code in my blazor page's code-behind :
public partial class ContactCreate : AuthenticatedPageBase
{
[Inject]
public IContactDataService ContactDataService { get; set; }
[Inject]
public ICountryDataService CountryDataService { get; set; }
public Contact.Post Model { get; set; } = new Contact.Post();
protected string CountryIdString { get; set; } = string.Empty;
protected string TokenString { get; set; } = string.Empty;
public string ErrorMessage { get; set; } = string.Empty;
protected List<Country.ListItem> Countries { get; set; } = new List<Country.ListItem>();
protected async override Task OnInitializedAsync()
{
await base.OnInitializedAsync();
Countries = (await CountryDataService.GetCountryListAsync(Token.Token)).ToList();
TokenString = Token.Token;
}
protected async Task HandleValidSubmit()
{
try
{
Model.CountryId = int.Parse(CountryIdString);
var response = await ContactDataService.PostContactAsync(TokenString, Model);
NavManager.NavigateTo("/contacts");
}
catch(Exception ex)
{
ErrorMessage = ex.Message;
}
}
protected void HandleInvalidSubmit()
{
ErrorMessage = "Le formulaire n'est pas valide. Veuillez réessayer.";
}
}
and here's the relevant code in the data service :
public async Task<int> PostContactAsync(string token, Contact.Post model)
{
var response = await PostAuthenticatedAsync<int>(token, Url, model);
return response;
}
public async Task<T> PostAuthenticatedAsync<T>(string token, string url, object model)
{
var jsonBody = model.ToJson();
var request = new HttpRequestMessage()
{
RequestUri = new Uri(HttpClient.BaseAddress.ToString() + url),
Method = HttpMethod.Post,
Content = jsonBody
};
request.Headers.Authorization = new AuthenticationHeaderValue("bearer", token);
var response = await HttpClient.SendAsync(request);
return await response.FromJson<T>(Options);
}
...and the extension method that serializes the object into json :
public static StringContent ToJson(this object o)
{
return new StringContent(JsonSerializer.Serialize(o), Encoding.UTF8, "application/json");
}
Here's the object model that I'm passing through :
public class Contact
{
public class Post
{
[MaxLength(50)]
public string FirstName { get; set; }
[MaxLength(50)]
public string LastName { get; set; }
[MaxLength(50)]
public string CompanyName { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
[MaxLength(20)]
public string PostCode { get; set; }
[MaxLength(60)]
public string Locality { get; set; }
public int CountryId { get; set; }
}
}
And, finally, here's the API method that I'm trying to reach :
[HttpPost]
public async Task<ActionResult> PostContact(Contact.Post model)
{
try
{
var createdId = await _contactRepository.CreateAsync(model);
return Ok(new { Id = createdId });
}
catch (Exception ex)
{
return BadRequest(new { ex.Message });
}
}
Any idea what is happening or what actual exception lies behind this cryptic error message ?
P.S. : I know that there is a question with that exact exception message but it concerns .NET Core while I'm targeting .NET Standard 2.1. I've read it and it visibly doesn't apply to this case.
You are not returning an int (the Id). You're returning an anonymous object with an int property named Id.
Try
return Ok(createdId);

StatusCode: 401, ReasonPhrase: 'Unauthorized' gets displayed when calling a Post Method through HTTPClient using C#

I am trying to access an API's Post method through HTTP Client and passing the AuthToken. When I tried to access in post man I am able to get the response, but when I ran in C#, I got StatusCode: 401, ReasonPhrase: 'Unauthorized' error. I am sharing the request and Response screens of Postman along with my code. can anyone let me know the mistake which i did in the code and how to solve the issue.
Postman Request Header and Response Body
Postman Request Body
below is my C# code.
public class PostEmpData
{
public string cExternalGUID = "10134",
cEmployeeID = "10134", cLastName = "Anderson", cFirstName = "Derek", cAccessGroup = "", cActive = "A";
public int nCardNumber = 10134, nPayMethod = 2;
public string[] cGroupsList = new string[0] { };
public DateTime dHireDate = DateTime.Parse("1999 / 11 / 03"), dTermDate = DateTime.Parse("01 / 01 / 0001"), dRateEffectiveDate = DateTime.Parse("2017 - 07 - 15");
public decimal nPayRate = 1500;
}
public class PostEmployeeClass
{
public int _interfaceID { get; set; }
public int _errorCode { get; set; }
public string _errorDescription { get; set; }
public List<EmpPostResponse> respList;
}
public class EmpPostResponse
{
public string RetKey { get; set; }
public int ErrorCode { get; set; }
public string Description { get; set; }
public string Success { get; set; }
public string SecondaryList { get; set; }
}
static async Task<List<EmpPostResponse>> CallPostEmployeeAsync(object postdata)
{
Console.WriteLine("Post Employee Process Started");
PostEmployeeClass authclass = null;
List<EmpPostResponse> data = null;
HttpResponseMessage response = await client.PostAsJsonAsync("xxxxxxV2/api/ED907F98-9132-4C7D-B4D4-7648A2577F6D/Integration/employees", postdata);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
Console.WriteLine("success");
authclass = await response.Content.ReadAsAsync<PostEmployeeClass>();
data = authclass.respList;
}
else
Console.WriteLine("fail:" + response.StatusCode.ToString());
return data;
}
static void Main(string[] args)
{
Console.WriteLine("Starting the Process");
RunAsync().Wait();
}
static async Task RunAsync()
{
PostEmpData objPost = new PostEmpData();
client.BaseAddress = new Uri("https://xxxx.xxxxx.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
string AuthToken="XXXXXXXXXXXXX";
client.DefaultRequestHeaders.Add("AuthToken", AuthToken);
Console.WriteLine(AuthToken);
var postdata = CallPostEmployeeAsync(objPost);
}catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
I've reviewed your code and there are a few things that I noticed.
One thing that is not going to work: PostEmpData will serialize into an empty object as it contains no properties. So the body will be something like: {}. You will need to add properties to the class:
public class PostEmpData
{
public string cExternalGUID { get; set; } = "10134";
public string cEmployeeID { get; set; } = "10134";
public string cLastName { get; set; } = "Anderson";
public string cFirstName { get; set; } = "Derek";
public string cAccessGroup { get; set; } = "";
public string cActive { get; set; } = "A";
public int nCardNumber { get; set; } = 10134;
public int nPayMethod { get; set; } = 2;
public string[] cGroupsList { get; set; }= new string[0] { };
public DateTime dHireDate { get; set; }= DateTime.Parse("1999 / 11 / 03");
public DateTime dTermDate { get; set; }= DateTime.Parse("01 / 01 / 0001");
public DateTime dRateEffectiveDate { get; set; }= DateTime.Parse("2017 - 07 - 15");
public decimal nPayRate { get; set; }= 1500;
}
There is a good chance that this causes the unauthorized response. And that it may have nothing to do with the token.
And there is also another difference compared to the Postman request. With Postman you send an array of object [{}], but with code you send one object. So you may have to post a list of PostEmpData.

C# loading grid with json

I'm trying to load a grid with json that I receive. This is my code in Home.cs:
private void getTickets()
{
try
{
string urlName = "tickets";
string method = "GET";
string json = null;
HttpStatusCode statusCode = HttpStatusCode.Forbidden;
Tickets data = null;
RestClient client = RequestClient.makeClient();
MakeRequest request = new MakeRequest(null, null, urlName, method);
IRestResponse response = client.Execute(request.exec());
statusCode = response.StatusCode;
json = response.Content;
var ticketWrapper = JsonConvert.DeserializeObject<TicketWrapper>(json);
if ((int)statusCode == 200)
{
gridTicket.DataSource = ticketWrapper.tickets;
}
else
{
MessageBox.Show("error");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Ticket wrapper class
class TicketWrapper
{
public IEnumerable<Tickets> tickets { get; set; }
}
Tickets class
class Tickets
{
public int id;
public string title;
public string description;
public int user_id;
public int subject_id;
}
If I debug I can see that I receive the json but ticketWrapper is null what could be wrong here?
Debug image:
Try to change public fields in Ticket class to properties:
class Tickets
{
public int id { get; set; }
public string title { get; set; }
public string description { get; set; }
public int user_id { get; set; }
public int subject_id { get; set; }
}
Also I think that IEnumerable is not the best option for serialization. Try to use List in TicketWrapper.
Additionally move your break point down, because in current position ticketWrapper will be always null (expression has not yet been executed).

Deserialize XML into Object

Im trying to deserialize an xml response from from Amazons simple db service.
The xml is like this.
<ListDomainsResponse xmlns="http://sdb.amazonaws.com/doc/2009-04-15/">
<ListDomainsResult>
<DomainName>Logging</DomainName>
<DomainName>teets</DomainName>
</ListDomainsResult>
<ResponseMetadata>
<RequestId>9d48122e-1ddf-8771-b771-b36599838ea0</RequestId>
<BoxUsage>0.0000071759</BoxUsage>
</ResponseMetadata>
</ListDomainsResponse>
And the object i'm trying to serialize into is this.
public class ListDomainsResponse : Response
{
public ListDomainsResult ListDomainsResult { get; set; }
}
public class ListDomainsResult
{
public List<String> DomainNames { get; set; }
public string NextToken { get; set; }
}
public class Response
{
public static string NameSpace = "http://sdb.amazonaws.com/doc/2009-04-15/";
public ResponseMetadata ResponseMetadata{ get; set; }
}
public class ResponseMetadata
{
public string RequestId { get ; set; }
public string BoxUsage { get; set; }
}
My problem is that the response metadata is getting deserialized correctly but the List of strings called DomainName is not being deserialized, it is empty each time.
Can someone see what i'm doing wrong.
Updated with more code
public async Task<Response> ListDomains (ListDomainsRequest request)
{
using (Client = new HttpClient ()) {
ListDomainsRequestMarshaller marshaller = new ListDomainsRequestMarshaller ();
marshaller.Configure (request);
HttpResponseMessage responseMessage = Client.GetAsync (marshaller.Marshal ()).Result;
ListDomainsResponseUnMarshaller unmarshaler = new ListDomainsResponseUnMarshaller (responseMessage);
return unmarshaler.Response;
}
}
public ListDomainsResponseUnMarshaller (HttpResponseMessage message)
{
XDocument doc = XDocument.Load (message.Content.ReadAsStreamAsync ().Result);
if (message.StatusCode.Equals (HttpStatusCode.OK)) {
Serializer = new XmlSerializer (typeof(ListDomainsResponse), Response.NameSpace);
Response = (ListDomainsResponse)Serializer.Deserialize (doc.CreateReader ());
Response.HttpStatusCode = message.StatusCode;
Response.ContentLength = (long)message.Content.Headers.ContentLength;
} else {
Serializer = new XmlSerializer (typeof(Response));
Response = (Response)Serializer.Deserialize (doc.CreateReader ());
Response.HttpStatusCode = message.StatusCode;
Response.ContentLength = (long)message.Content.Headers.ContentLength;
}
Serializer = null;
}
Adding Attributes helped
[System.Xml.Serialization.XmlTypeAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
[System.Xml.Serialization.XmlRootAttribute ("ListDomainsResponse", Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
public class ListDomainsResponse : Response
{
public ListDomainsResult ListDomainsResult { get; set; }
}
[System.Xml.Serialization.XmlTypeAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
[System.Xml.Serialization.XmlRootAttribute (Namespace = "http://sdb.amazonaws.com/doc/2009-04-15/")]
public class ListDomainsResult
{
[System.Xml.Serialization.XmlElementAttribute ("DomainName")]
public string[] DomainName { get; set; }
public string NextToken { get; set; }
}

Categories

Resources