I am trying to send data from winform datagridview to webapi, so i convert datagridview to json. While sending json it failed to POST data and send this error:
'Failed to POST data: (BadRequest): {"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title": "One or more validation errors occurred.","status":400,"traceId":"00-fb84f3c1c1802a481cbe7aba7ef73193-80be6fe9c57344d2-00","errors":{"$":["The JSON value could not be converted to LabDataApi.Models.LabData. Path: $ | LineNumber: 0 | BytePositionInLine: 421."]}}'
Codes:
public class LabData
{
public int SerialNumber { get; set; }
public string LabParameterName { get; set; }
public decimal LabValue { get; set; }
public DateTime LabDate { get; set; }
}
private void button2_Click(object sender, EventArgs e)
{
var url = "https://localhost:7248/api/Lab";
dataGridView1.DataSource = LabResult.GetLabData();
var table = JsonConvert.SerializeObject(dataGridView1.DataSource);
ApiSender apiSender = new ApiSender();
apiSender.POSTData(table, url);
}
public class ApiSender
{
private static HttpClient _httpClient = new HttpClient();
public bool POSTData(object json, string url)
{
using (var content = new StringContent(JsonConvert.SerializeObject(json), System.Text.Encoding.UTF8, "application/json"))
{
HttpResponseMessage result = _httpClient.PostAsync(url, content).Result;
if (result.StatusCode == System.Net.HttpStatusCode.Created)
return true;
string returnValue = result.Content.ReadAsStringAsync().Result;
throw new Exception($"Failed to POST data: ({result.StatusCode}): {returnValue}");
}
}
}
Receiving Json data format
[{"SerialNumber":1,"LabParameterName":"abc","LabValue":7.80,"LabDate":"2001-11-16T10:10:00"},{"SerialNumber":2,"LabParameterName":"xyz","LabValue":10.00,"LabDate":"2001-11-16T10:10:00"},{"SerialNumber":3,"LabParameterName":"qq","LabValue":5.00,"LabDate":"2001-03-16T10:10:00"},{"SerialNumber":18,"LabParameterName":"cbc","LabValue":200.0,"LabDate":"2001-11-16T10:10:00"}]
The JSON value could not be converted to LabDataApi.Models.LabData
Well, you are trying to convert an array of LabData into the LabData model. Update the API to receive IEnumerable<LabData>, or update the client to send multiple POST requests (for each LabData entry (not recommended)).
At least that's the answer to the question you've asked - it looks like you have cut off the end of the exception, perhaps you omitted some essential details by mistake?
There is an issue with your objects definitions when converting to json. Also, you'll want to get it as a List or an Array.
Your serialization/deserialization will work better with these objects.
public class LabDatas
{
public LabData[] Value { get; set; }
}
//or if you want list
public class LabDatas
{
public List<LabData> Value { get; set; }
}
public class LabData
{
public int SerialNumber { get; set; }
public string LabParameterName { get; set; }
public float LabValue { get; set; }
public DateTime LabDate { get; set; }
}
Related
I'm just new to API and I wanted to consume third party API that was provided to me(which I don't have any control on how they structure the datas). I have asked on S.O before this post but I can't understand what or how should I do their suggestions 'Structure your classes to match your JSON Object'
My Json looks like this :
{
"status": 1,
"message": "",
"data": {
"VacationLeave": 11,
"SickLeave": 10,
"EmergencyLeave": 2,
"HolidaySwap": 1,
"OldLeave": 1
}
}
And on my controllers I have this
public IActionResult APICall()
{
// Fetch the JSON string from URL.
List<APIResponse> leaves = new List<APIResponse>();
string apiUrl = "http://xxxxx.xxx.xxx/GetLeaveBalance/2170";
HttpClient client = new HttpClient();
HttpResponseMessage response = client.GetAsync(apiUrl).Result;
if (response.IsSuccessStatusCode)
{
leaves = JsonConvert.DeserializeObject<List<APIResponse>>(response.Content.ReadAsStringAsync().Result);
}
// Return the Deserialized JSON object.
return Json(leaves);
}
My model classes :
public class APIResponse : LeaveModel
{
public int Status { get; set; }
public string Message { get; set; }
public List<LeaveModel> Leaves;
}
public class LeaveModel
{
public int VacationLeave { get; set; }
public int SickLeave { get; set; }
public int EmergencyLeave { get; set; }
public int HolidaySwap { get; set; }
public int OldSwap { get; set; }
}
My problem is: I get this error :
Newtonsoft.Json.JsonSerializationException: 'Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[APITest.Models.APIResponse]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.
Can anyone help me what I'm missing here?
Thank you
Your APIResponse should support generic.
public class APIResponse<T>
{
public int Status { get; set; }
public string Message { get; set; }
public T Data { get; set; }
}
As the data is a LeaveModel object but not a LeaveModel array.
And deserialize as APIResponse<LeaveModel> type.
APIResponse<LeaveModel> apiResponse = JsonConvert.DeserializeObject<APIResponse<LeaveModel>>(response.Content.ReadAsStringAsync().Result);
LeaveModel leave = apiResponse.Data;
And would suggest changing the method to asynchronous.
public async Task<IActionResult> APICallAsync()
{
//Fetch the JSON string from URL.
LeaveModel leave = new LeaveModel();
string apiUrl = "http://xxxxx.xxx.xxx/GetLeaveBalance/2170";
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(apiUrl);
if (response.IsSuccessStatusCode)
{
APIResponse<LeaveModel> apiResponse = JsonConvert.DeserializeObject<APIResponse<LeaveModel>>(await response.Content.ReadAsStringAsync());
leave = apiResponse.Data;
}
//Return the Deserialized JSON object.
return Json(leave);
}
As per json ApiResponse class must look like this
public class APIResponse : LeaveModel
{
public int Status { get; set; }
public string Message { get; set; }
public LeaveModel data;
}
I am making a simple WinForm Application in Windows and I want to get some data about foreign exchange rates. So I decided to call an API from Oanda. I tried several things around but nothing worked. It gives the response in CSV as well as JSON format. I don't know which will be easier to handle.
Also for this type of response, I am unable to create its model class.
Response:
JSON:
{
"meta": {
"effective_params": {
"data_set": "OANDA",
"base_currencies": [
"EUR"
],
"quote_currencies": [
"USD"
]
},
"endpoint": "spot",
"request_time": "2019-06-08T12:05:23+00:00",
"skipped_currency_pairs": []
},
"quotes": [
{
"base_currency": "EUR",
"quote_currency": "USD",
"bid": "1.13287",
"ask": "1.13384",
"midpoint": "1.13336"
}
]
}
CSV:
base_currency,quote_currency,bid,ask,midpoint
EUR,USD,1.13287,1.13384,1.13336
I just need those three numbers so, which method will be helpful and how.
This code I already tried:
var client = new HttpClient();
client.BaseAddress = new Uri("https://www1.oanda.com/rates/api/v2/rates/");
HttpResponseMessage response = await client.GetAsync("spot.csv?api_key=<myapikey>&base=EUR"e=USD");
string result = await response.Content.ReadAsStringAsync();
textBox1.Text = result;
Edit: I need the result of this call for my further processing so I must need this method to complete its execution before proceeding further
First creating model from Json:
use a online model generator like Json2C#, for the Json that you have posted, following is the model generated:
public class EffectiveParams
{
public string data_set { get; set; }
public List<string> base_currencies { get; set; }
public List<string> quote_currencies { get; set; }
}
public class Meta
{
public EffectiveParams effective_params { get; set; }
public string endpoint { get; set; }
public DateTime request_time { get; set; }
public List<object> skipped_currency_pairs { get; set; }
}
public class Quote
{
public string base_currency { get; set; }
public string quote_currency { get; set; }
public string bid { get; set; }
public string ask { get; set; }
public string midpoint { get; set; }
}
public class RootObject
{
public Meta meta { get; set; }
public List<Quote> quotes { get; set; }
}
Now connecting to the WebAPI using HttpClient, which has the option to return both Json and CSV, I would prefer JSON being standard, which can also be consumed easily by variety of clients, use the following simple generic methods:
Assuming it is GET only call, just supply the Host and API details to the generic Process method underneath:
public async Task<TResponse> Process<TResponse>(string host,string api)
{
// Execute Api call Async
var httpResponseMessage = await MakeApiCall(host,api);
// Process Json string result to fetch final deserialized model
return await FetchResult<TResponse>(httpResponseMessage);
}
public async Task<HttpResponseMessage> MakeApiCall(string host,string api)
{
// Create HttpClient
var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }) { BaseAddress = new Uri(host) };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Make an API call and receive HttpResponseMessage
HttpResponseMessage responseMessage = await client.GetAsync(api, HttpCompletionOption.ResponseContentRead);
return responseMessage;
}
public async Task<T> FetchResult<T>(HttpResponseMessage result)
{
if (result.IsSuccessStatusCode)
{
// Convert the HttpResponseMessage to string
var resultArray = await result.Content.ReadAsStringAsync();
// Json.Net Deserialization
var final = JsonConvert.DeserializeObject<T>(resultArray);
return final;
}
return default(T);
}
How to use:
Simply call:
var rootObj = await Process<RootObject>("https://www1.oanda.com/rates/", "api/v2/rates/");
You receive the deserialized RootObject as shown in the model above
For anything further complex processing like sending input to the call with http body, above generic code needs further modification, it is currently only specific to your requirement
Edit 1: (Making the entry call Synchronous)
To make the overall call synchronous, use the GetAwaiter().GetResult() at the topmost level, Main method will be converted to, rest all will remain same as in the sample (async methods)
void Main()
{
var rootObj = Process<RootObject>("https://www1.oanda.com/rates/", "api/v2/rates/").GetAwaiter().GetResult();
}
Edit 2: (Making complete code Synchronous)
void Main()
{
var rootObj = Process<RootObject>("https://www1.oanda.com/rates/", "api/v2/rates/");
}
public TResponse Process<TResponse>(string host, string api)
{
// Execute Api call
var httpResponseMessage = MakeApiCall(host, api);
// Process Json string result to fetch final deserialized model
return FetchResult<TResponse>(httpResponseMessage);
}
public HttpResponseMessage MakeApiCall(string host, string api)
{
// Create HttpClient
var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }) { BaseAddress = new Uri(host) };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Make an API call and receive HttpResponseMessage
HttpResponseMessage responseMessage = client.GetAsync(api, HttpCompletionOption.ResponseContentRead).GetAwaiter().GetResult();
return responseMessage;
}
public T FetchResult<T>(HttpResponseMessage result)
{
if (result.IsSuccessStatusCode)
{
// Convert the HttpResponseMessage to string
var resultArray = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
// Json.Net Deserialization
var final = JsonConvert.DeserializeObject<T>(resultArray);
return final;
}
return default(T);
}
You can use an online service such as json2csharp to get your json model and Json.Net to serialise and deserialise the json string. The following models your json.
public class EffectiveParams
{
public string data_set { get; set; }
public List<string> base_currencies { get; set; }
public List<string> quote_currencies { get; set; }
}
public class Meta
{
public EffectiveParams effective_params { get; set; }
public string endpoint { get; set; }
public DateTime request_time { get; set; }
public List<object> skipped_currency_pairs { get; set; }
}
public class Quote
{
public string base_currency { get; set; }
public string quote_currency { get; set; }
public string bid { get; set; }
public string ask { get; set; }
public string midpoint { get; set; }
}
public class RootObject
{
public Meta meta { get; set; }
public List<Quote> quotes { get; set; }
}
Note that you can change RootOject to a more descriptive name.
So, for example, to get the bid, ask and midpoint value for each quotes, you can simply do this:
RootObject rootObj=JsonConvert.DeserializeObject(jsonString);
//Get the required values.
foreach(var quote in rootObj.quotes)
{
Console.WriteLine($"Bid : {quote.bid} Ask: {quote.ask} MidPoint: {quote.midpoint}");
}
I have 2 applications, one which posts data to another. When I run the first application the post method in the controller executes but the model or ObjavaDto (objaveList) can't be found so it's null. When I copy-paste the json from var json into Postman everything works. What am I missing?
var json = new JavaScriptSerializer().Serialize(objaveList[2]);
I used [2] just for simplicity reasons because there are a lot of them
string url = "http://localhost:61837/api/Objave";
string result;
using (var client = new WebClient())
{
client.Headers.Add("Content-Type", "application/json");
result = client.UploadString(url, "POST", json);
}
2nd application Controller
namespace StecajeviInfo.Controllers.Api
{
[Route("api/[controller]")]
public class ObjaveController : Controller
{
[HttpPost]
public void Post([FromBody]ObjavaDto objaveList)
{
}
}
}
public class ObjavaDto
{
public string OznakaSpisa { get; set; }
public string NazivOtpravka { get; set; }
public string NazivStecajnogDuznika { get; set; }
public string PrebivalisteStecajnogDuznika { get; set; }
public string SjedisteStecajnogDuznika { get; set; }
public string OIBStecajnogDuznika { get; set; }
public string OglasSeOdnosiNa { get; set; }
public DateTime DatumObjave { get; set; }
public string OibPrimatelja { get; set; }
public string Dokument { get; set; }
}
Sent data looks like this
{
"OznakaSpisa":"St-6721/2015",
"NazivOtpravka":"Rješenje - otvaranje stečajnog postupka St-6721/2015-7",
"NazivStecajnogDuznika":"RAIN AIR d.o.o.",
"PrebivalisteStecajnogDuznika":"Savska 144/A, 10000, Zagreb",
"SjedisteStecajnogDuznika":"",
"OIBStecajnogDuznika":"37144498637",
"OglasSeOdnosiNa":"Missing Oib",
"DatumObjave":"\/Date(1501106400000)\/",
"OibPrimatelja":"37144498637",
"Dokument":"e-oglasna.pravosudje.hr/sites/default/files/ts-zg-st/…;"
}
Thank you all for your replies, you have been very helpful and gave me an idea how to test. I tested with commenting out properties and I found out it's because of the special characters in Naziv otpravka ("Rješenje" and "stečajnog") which are luckily present only in that property.
I found that this solved the problem https://stackoverflow.com/a/12081747/6231007
client.Headers["Content-Type"] = "application/json; charset=utf-8";
client.UploadDataAsync(new Uri(url), "POST",
Encoding.UTF8.GetBytes(json));
Datetime is problematic. Make it nullable (DateTime?) and test with that. You'll probably get all other properties filled and datetime will stay null. If that's the problem, make sure your client sends datetime format that your model binder understands.
When I create a new record in my table I would like generate an json response with only the primary ID of my new record, somethink like : {"PrimaryID":123}
I actually use this handmade function:
// Inserts a new row into the PatientSession table
public string AddPatientSession(PatientSession p)
{
int id = (int)_dbConnection.Insert<PatientSession>(p, selectIdentity: true);
string Idconvert = id.ToString();
string IdInsert = "{\"PatientSessionId\":" + Idconvert + "}";
return IdInsert;
}
But I assume it's not the best way to do it, have you a suggestion please?
Thanks in advance
If you just want to return a small JSON payload with just an Id you can use a type with only the fields you want to return, e.g:
public class AddPatientSession : IReturn<PatientId> { ... }
public class PatientId {
public int PatientSessionId { get; set; }
}
Then use in your service like:
public class MyServices : Service
{
public object Any(AddPatientSession request)
{
var model = request.ConvertTo<PatientSession>();
return new PatientId {
PatientSessionId = Db.Insert(model, selectIdentity: true);
}
}
}
Returning an object takes advantage of ServiceStack's built-in Content Negotiation to return the object serialized in the preferred Content-Type, e.g. JSON for JSON/ajax clients.
You can also return an anonymous type containing just the Id:
public object Any(AddPatientSession request)
{
var model = request.ConvertTo<PatientSession>();
return new {
PatientSessionId = Db.Insert(model, selectIdentity: true);
}
}
Which will also serialize to JSON when requested, but the lack of a type does prevent this from being called with ServiceStack's generic typed Service Clients.
Thanks you so much #mythz it's working well I just use a convert function to int because "Db.Insert" return a long type.
// Add PatientSession via POST
public class PatientSessionADD : IReturn<PatientSessionResponseId>
{
public int PatientSessionId { get; set; }
public int ByPatientId { get; set; }
public DateTime PatientStartSessionTime { get; set; }
public int PatientStartSessionByUserId { get; set; }
public DateTime PatientEndSessionTime { get; set; }
public int PatientEndSessionByUserId { get; set; }
}
public class PatientSessionResponseId
{
public int PatientSessionId { get; set; }
}
public object Post(PatientSessionADD request)
{
var p =new PatientSession()
{
ByPatientId = request.ByPatientId,
PatientStartSessionTime = request.PatientStartSessionTime,
PatientStartSessionByUserId = request.PatientStartSessionByUserId
};
return new PatientSessionResponseId
{
PatientSessionID = Convert.ToInt16( Db.Insert<PatientSession>(p, selectIdentity: true) )
};
}
To resume this function get a HTTP POST message, store it in database and return a JSON response with only the Primary ID generated.
Have fun and thanks again mythz
I have a php webservice which gets the data from database and returns it as json data.
Json data
{"faqs":
[
{"faq":{"id":"123"}},
{"faq":{"id":"124"}}
]
}
Object classes
public class FaqList
{
public List<Faq> faqs { get; set; }
}
public class Faq
{
public string id { get; set; }
}
Test class
var client = new HttpClient();
HttpResponseMessage response = await client.GetAsync(new Uri("http://www.mydomain.com/webservice/7/server.php"));
var jsonString = await response.Content.ReadAsStringAsync();
FaqList list = JsonConvert.DeserializeObject<FaqList>(jsonString);
list.faqs.Count() => 2
list.faqs[0].id => NULL !!
I fill all the objects to the 'list'. With count test I see that it's filled. But if I try to get an objects from it, I get null error.
So, how can I correctly fill my list so that I can get the objects from it?
http://json2csharp.com/ suggests these definitions. (One more class Faq2)
public class Faq2
{
public string id { get; set; }
}
public class Faq
{
public Faq2 faq { get; set; }
}
public class RootObject
{
public List<Faq> faqs { get; set; }
}