I have a Product class, which looks like this:
Public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Code { get; set; }
public string Barcode { get; set; }
public string InnerCode { get; set; }
public virtual ProductUnit ProductUnit { get; set; }
public int? ProductUnitID { get; set; }
public virtual ProductType ProductType { get; set; }
public int? ProductTypeID { get; set; }
}
In ASP.NET Core Web API Service I have a put method which returns OK(product).
The response in postman looks like this:
{
"result": {
"id": 22,
"name": "Bread",
"productType": {
"id": 4,
"name": "Food",
"remarks": null,
"products": []
},
"productTypeID": 4,
"code": "566",
"barcode": "855",
"innerCode": "145522",
"productUnit": {
"id": 4,
"name": "Box",
"remarks": null,
"products": []
},
"productUnitID": 4
},
"id": 592, ---> //probably this
"exception": null,
"status": 5,
"isCanceled": false,
"isCompleted": true,
"isCompletedSuccessfully": true,
"creationOptions": 0,
"asyncState": null,
"isFaulted": false
}
I am trying to get Product object as shown below:
var data = await httpResponseMessage.Content.ReadAsAsync<Product>();
But As a result, I get the product object with null properties, except the ID, which is random number and which as I think is the id above the exception in the json response.
What mistake do I have?
So, I believe you are trying to parse result which is the inner object in your case.
In order to parse the whole result you have to create a type for mentioned json, which you can create using https://app.quicktype.io/#l=cs&r=json2csharp.
Classes will be as follows :
public partial class ProductResult
{
[JsonProperty("result")]
public Result Result { get; set; }
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("exception")]
public object Exception { get; set; }
[JsonProperty("status")]
public long Status { get; set; }
[JsonProperty("isCanceled")]
public bool IsCanceled { get; set; }
[JsonProperty("isCompleted")]
public bool IsCompleted { get; set; }
[JsonProperty("isCompletedSuccessfully")]
public bool IsCompletedSuccessfully { get; set; }
[JsonProperty("creationOptions")]
public long CreationOptions { get; set; }
[JsonProperty("asyncState")]
public object AsyncState { get; set; }
[JsonProperty("isFaulted")]
public bool IsFaulted { get; set; }
}
public partial class Result
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("productType")]
public Product ProductType { get; set; }
[JsonProperty("productTypeID")]
public long ProductTypeId { get; set; }
[JsonProperty("code")]
[JsonConverter(typeof(ParseStringConverter))]
public long Code { get; set; }
[JsonProperty("barcode")]
[JsonConverter(typeof(ParseStringConverter))]
public long Barcode { get; set; }
[JsonProperty("innerCode")]
[JsonConverter(typeof(ParseStringConverter))]
public long InnerCode { get; set; }
[JsonProperty("productUnit")]
public Product ProductUnit { get; set; }
[JsonProperty("productUnitID")]
public long ProductUnitId { get; set; }
}
public partial class Product
{
[JsonProperty("id")]
public long Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("remarks")]
public object Remarks { get; set; }
[JsonProperty("products")]
public List<object> Products { get; set; }
}
now you can use ProductResult as
var data = await httpResponseMessage.Content.ReadAsAsync<ProductResult>();
Update
Another solution is, instead of creating type (class) for full JSON data you can use JObject class and using jsonpath you can select any property or object as follows :
string result = await httpResponseMessage.Content.ReadAsStringAsync();
Product product = JObject.Parse(result).SelectToken("$.result").ToObject<Product>()
Related
I'm working on an web API, where it needs to receive the multi-part form data with in a model. As of now it's not receiving the request and showing the Bad request When I tried from the Postman.
My model :
public class InvoiceDetails
{
public int? po_id { get; set; }
public DateTime created_date { get; set; }
public string grn_status { get; set; }
public int utilization_amount { get; set; }
public int currency_id { get; set; }
public string currency_code { get; set; }
public string currency_symbol { get; set; }
[FromForm(Name = "invoice_file")]
public List<IFormCollection> invoice_file { get;set;}
[FromForm(Name = "other_files")]
public List<IFormCollection> other_files { get; set; }
}
In the above class/model "invoice_file" and "other_files" can have multiple file uploads so I made it List.
My Action Method :
[HttpPost]
[Route("CreateInvoice")]
public IActionResult CreateInvoice([FromForm]InvoiceDetails idobj )
{
//var modelData = Request.Form["invoice_file"];
Response resobj = new Response();
try
{
if (idobj.invoice_file.Count > 0)
{
resobj = _dataContext.AddInvoice(idobj);
if (resobj.flag == true)
{
Upload(idobj);
}
}
else
{
resobj.flag = false;
resobj.message = "please upload atleast one invioce file";
}
}
catch (Exception ex)
{
}
return Ok(resobj);
}
How can I make the action method or model, in such a way that user can upload the model with multiple files to the properties other_files & invoice_file.
Reference of postman Image
As CodeCaster says,add Content-Type:multipart/form-data; and change List<IFormCollection> to List<IFormFile>.It is not changing the whole model to List.So you can also retrieve other information which exists in your model with idobj.xxx.Change
public class InvoiceDetails
{
public int? po_id { get; set; }
public DateTime created_date { get; set; }
public string grn_status { get; set; }
public int utilization_amount { get; set; }
public int currency_id { get; set; }
public string currency_code { get; set; }
public string currency_symbol { get; set; }
[FromForm(Name = "invoice_file")]
public List<IFormCollection> invoice_file { get;set;}
[FromForm(Name = "other_files")]
public List<IFormCollection> other_files { get; set; }
}
to
public class InvoiceDetails
{
public int? po_id { get; set; }
public DateTime created_date { get; set; }
public string grn_status { get; set; }
public int utilization_amount { get; set; }
public int currency_id { get; set; }
public string currency_code { get; set; }
public string currency_symbol { get; set; }
[FromForm(Name = "invoice_file")]
public List<IFormFile> invoice_file { get; set; }
[FromForm(Name = "other_files")]
public List<IFormFile> other_files { get; set; }
}
result:
IFormCollection is used to retrieve all the values from posted form data.refer to the official document.
If you want to use c,you can try to use it,you can do like this
public IActionResult CreateInvoice([FromForm]IFormCollection idobj)
and you need to get the data you want to foreach keys of IFormCollection,so public List<IFormCollection> invoice_file { get;set;} is better than use IFormCollection.
How do work with a model with a model property inside of it?
I am pulling info from an api successfully but it does not work after I try to change my model from int to model like below:
public class TypeModel
{
[PrimaryKey]
public int pType { get; set; }
public DepartmentModel fDepartment { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string Version { get; set; }
}
Here is the department model
public class DepartmentModel
{
public int pDepartment { get; set; }
public string Name { get; set; }
}
My ViewModel had this code and was working. Been trying to make changes as I think I need to change it in here somehow.
Types.Clear();
IEnumerable<TypesModel> types = await DataSource.GetTypesAsync(typeinfo.pType, true);
foreach (var column in types)
{
Types.Add(column);
}
Here is the deserialization from the api.
IEnumerable<TypeModel> TypeEnumerator;
public async Task<IEnumerable<TypeModel>> GetTypesAsync(bool r = false)
{
if (r)
{
var j = await HttpConstructor.GetStringAsync($"api/gettypes");
return await Task.Run(() => JsonConvert.DeserializeObject<IEnumerable<TypeModel>>(j));
}
return TypeEnumerator; ;
}
Here is the json information being produced from the api for types
{
"pType": 10,
"fDepartment": 1,
"title": "Bigwig",
"description": "For the bigwigs",
"comments": "high priority",
"version": "1.2.3"
},
{
"pType": 11,
"fDepartment": 1,
"title": "Frontdesk",
"description": "front end people",
"comments": "none",
"version": "1.2.4"
}
this is what I would do. There are undoubtedly other ways to approach it
public class TypeModel
{
[PrimaryKey]
public int pType { get; set; }
public int fDepartment { get; set; }
public DepartmentModel Department { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string Version { get; set; }
}
List<TypesModel> types = await DataSource.GetTypesAsync(typeinfo.pType, true);
foreach (var type in types)
{
type.Department = new DepartmentModel
{
pDepartment = type.fDeparment,
Name = "???"
};
}
Got a solution going by using a Dictionary collection and avoided adjusting the model and mess up the business logic throughout the app.
I kept the original model and created a new one called TypesModel to use for list views.
public class TypesModel
{
[PrimaryKey]
public int pType { get; set; }
public Dictionary<int, string> fDepartment { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Comments { get; set; }
public string Version { get; set; }
}
Then I used Linq join to combine the information and also fill in the dictionary values.
var query = from t in types
join d in departments
on t.fDeparment equals d.pDepartment
select new TypesModel
{
pType = t.pType,
fDepartment = new Dictionary<int, string>()
{
{ d.pDepartment, d.Name }
},
Title = t.Title,
Description = t.Description
};
I have created an web api using the below code.
[HttpPost]
[Route("api/Agents/SetAgentSettings")]
public HttpResponseMessage SetAgentSetting(string agentIp, string agentMac, Guid orgId,SettingModel settingData)
{
}
From postman I am trying to call this api using the following request.
http://localhost:50194/api/Agents/SetAgentSettings?agentIp=10.0.1.33&agentMac=E442A6273481&orgId=C1F62D47-FBDF-468E-A4E6-418BFD8EB525
And in body I am sending the following body:
{
"agentIp":"10.0.2.10",
"agentMac":"Computer1",
"orgId":"c1f62d47-fbdf-468e-a4e6-418bfd8eb525",
"settingData":"{\"IsAutoSyncActive\":false,\"AutoSyncInterval\":0,\"AutosyncTime\":\"00:00\",\"IsRealtimeSyncActive\":false,\"RealTimeSyncUrl\":null,\"LogTargets\":6,\"LogSeveritys\":15,\"Exports\":0,\"LogInDetail\":true,\"LogInDatabase\":true,\"NotifyEmailId\":null,\"DiagonisticsMode\":false,\"ResyncRule\":null,\"ResyncBatchCount\":\"10\",\"IsResyncScheduled\":false,\"ExecuteFor\":1,\"Batch\":0,\"SaveSyncInfoToDb\":false,\"RealTimePort\":null,\"NotificationRule\":null,\"IsNotificationMailEnabled\":false,\"FileDeleteTime\":null,\"AgentType\":null,\"Frequency\":\"DAILY\",\"PartitionKey\":\"c1f62d47-fbdf-468e-a4e6-418bfd8eb525\",\"RowKey\":\"fbc6b368-9251-4165-a36b-fc1bd3912925\",\"Timestamp\":\"0001-01-01T00:00:00+00:00\",\"ETag\":null}"
}
In controller I am getting every data but setting model is not serializing. How to send the setting model data.
You're passing settingData in JSON string and another side expecting to be bind it with the model, which wouldn't work anyway. You have to pass the model in JSON format. Additionally, as you're passing agentIp, agentMac, orgId in URL, don't need to pass in the body again.
Here I assume your SettingModel as follows,
public class SettingModel
{
public bool IsAutoSyncActive { get; set; }
public int AutoSyncInterval { get; set; }
public string AutosyncTime { get; set; }
public bool IsRealtimeSyncActive { get; set; }
public object RealTimeSyncUrl { get; set; }
public int LogTargets { get; set; }
public int LogSeveritys { get; set; }
public int Exports { get; set; }
public bool LogInDetail { get; set; }
public bool LogInDatabase { get; set; }
public object NotifyEmailId { get; set; }
public bool DiagonisticsMode { get; set; }
public object ResyncRule { get; set; }
public string ResyncBatchCount { get; set; }
public bool IsResyncScheduled { get; set; }
public int ExecuteFor { get; set; }
public int Batch { get; set; }
public bool SaveSyncInfoToDb { get; set; }
public object RealTimePort { get; set; }
public object NotificationRule { get; set; }
public bool IsNotificationMailEnabled { get; set; }
public object FileDeleteTime { get; set; }
public object AgentType { get; set; }
public string Frequency { get; set; }
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public string Timestamp { get; set; }
public object ETag { get; set; }
}
Your request should be:
URL: http://localhost:50194/api/Agents/SetAgentSettings?agentIp=10.0.1.33&agentMac=E442A6273481&orgId=C1F62D47-FBDF-468E-A4E6-418BFD8EB525
Body:
{
"IsAutoSyncActive": false,
"AutoSyncInterval": 0,
"AutosyncTime": "00:00",
"IsRealtimeSyncActive": false,
"RealTimeSyncUrl": null,
"LogTargets": 6,
"LogSeveritys": 15,
"Exports": 0,
"LogInDetail": true,
"LogInDatabase": true,
"NotifyEmailId": null,
"DiagonisticsMode": false,
"ResyncRule": null,
"ResyncBatchCount": "10 ",
"IsResyncScheduled": false,
"ExecuteFor": 1,
"Batch": 0,
"SaveSyncInfoToDb": false,
"RealTimePort": null,
"NotificationRule": null,
"IsNotificationMailEnabled": false,
"FileDeleteTime": null,
"AgentType": null,
"Frequency": "DAILY ",
"PartitionKey": "c1f62d47-fbdf-468e-a4e6-418bfd8eb525",
"RowKey": "fbc6b368-9251-4165-a36b-fc1bd3912925",
"Timestamp": "0001-01-01T00:00:00+00:00",
"ETag": null
}
Method:
[HttpPost]
[Route("api/Agents/SetAgentSettings")]
public void SetAgentSetting(string agentIp, string agentMac, Guid orgId, [FromBody]SettingModel settingData)
{
}
I am trying to insert JSON data into my models via EF 6. I am getting this error;
Inner Exception is {0}System.ArgumentException: Could not cast or convert from System.String to EPINMiddleWareAPI.Models.Serial.
konum: Newtonsoft.Json.Utilities.ConvertUtils.EnsureTypeAssignable(Object value, Type initialType, Type targetType)
konum: Newtonsoft.Json.Utilities.ConvertUtils.ConvertOrCast(Object initialValue, CultureInfo culture, Type targetType)
konum: Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EnsureType(JsonReader reader, Object value, CultureInfo culture, JsonContract contract, Type targetType)
Message ---
{0}Error converting value "c57a55b5-b2d4-46e7-86e0-cc13726ca8a7" to type 'EPINMiddleWareAPI.Models.Serial'. Path 'coupons[0].serials[0]', line 1, position 310.
Here is my model structure:
public class ConfirmResponse
{
public int Id { get; set; }
public string referenceId { get; set; }
public string version { get; set; }
public string signature { get; set; }
public string paymentID { get; set; }
public string productCode { get; set; }
public string currency { get; set; }
public string ApplicationCode { get; set; }
public double unitPrice { get; set; }
public double totalPrice { get; set; }
public string purchaseStatusCode { get; set; }
public DateTime? purchaseStatusDate { get; set; }
public DateTime? requestDateTime { get; set; } = DateTime.Now;
public string merchantProductCode { get; set; }
public List<Coupon> coupons { get; set; }
}
public class Coupon
{
public int Id { get; set; }
public int ConfirmResponseID { get; set; }
public List<Serial> serials { get; set; }
public List<Pin> pins { get; set; }
public virtual ConfirmResponse confirmResponse { get; set; }
}
public class Serial
{
public int Id { get; set; }
public string serials { get; set; }
public int CouponID { get; set; }
public virtual Coupon coupons { get; set; }
}
My sample JSON:
"{\"referenceId\":\"0000000046\",\"paymentId\":\"MDO1037624\",\"productCode\":\"001002461285\",\"quantity\":\"1\",\"currency\":\"TL\",\"unitPrice\":\"46,47\",\"totalPrice\":\"46,47\",\"merchantProductCode\":\"\",\"purchaseStatusCode\":\"00\",\"purchaseStatusDate\":\"2019-03-17T20:58:48Z\",\"coupons\":[{\"serials\":[\"c57a55b5-b2d4-46e7-86e0-cc13726ca8a7\"],\"pins\":[\"T6VC-XC6X-3H6JS-NVWL-93PCa\"]}],\"version\":\"V1\",\"signature\":\"2f961c7dbc32c3bc128b6e69d19e8e1a\",\"applicationCode\":\"52e7cf966b724749a7c4efadc3727ed7\"}"
How can I fix this problem? I would like to insert this JSON into my database tables. I am using EF 6.
edit:
This model structure solved my problem. Now I can insert serials and pins into database.
public class ConfirmResponse
{
public int Id { get; set; }
public string referenceId { get; set; }
public string version { get; set; }
public string signature { get; set; }
public string paymentID { get; set; }
public string productCode { get; set; }
public string currency { get; set; }
public string ApplicationCode { get; set; }
public double unitPrice { get; set; }
public double totalPrice { get; set; }
public string purchaseStatusCode { get; set; }
public DateTime? purchaseStatusDate { get; set; }
public DateTime? requestDateTime { get; set; } = DateTime.Now;
public string merchantProductCode { get; set; }
public List<Coupon> coupons { get; set; }
}
public class Coupon
{
public int Id { get; set; }
public int ConfirmResponseID { get; set; }
public List<string> serials { get; set; }
public List<string> pins { get; set; }
public virtual ConfirmResponse confirmResponse { get; set; }
public List<string> StringsSerial
{
get { return serials; }
set { serials = value; }
}
public List<string> StringsPin
{
get { return pins; }
set { pins = value; }
}
[Required]
public string Serial
{
get { return String.Join(",", serials); }
set { serials = value.Split(',').ToList(); }
}
[Required]
public string Pin
{
get { return String.Join(",", pins); }
set { pins = value.Split(',').ToList(); }
}
}
Thanks in advance.
you're json is wrong
take a look into the coupons array, you initialize the serials array with an string/guid and not with a model of serial
it should be
"coupons": [{
{
"serials": [{
"serials": "c57a55b5-b2d4-46e7-86e0-cc13726ca8a7"
}
],
}
}
]...
I guess for Pins the same
Im using xamarin.forms to create an app that uses the MusixMatch api. It's throwing the following exception : Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.List. To my knowledge, Ive done everything correctly, not sure why this exception is being thrown. Any help will be appreciated.
TrackList.cs
public class TrackList
{
public class Track
{
public int track_id { get; set; }
public string track_mbid { get; set; }
public string track_isrc { get; set; }
public string track_spotify_id { get; set; }
public string track_soundcloud_id { get; set; }
public string track_xboxmusic_id { get; set; }
public string track_name { get; set; }
public int track_rating { get; set; }
public int track_length { get; set; }
public int commontrack_id { get; set; }
public int instrumental { get; set; }
}
public class Body
{
public IList<Track> track_list { get; set; }
}
}
Api Request
public async void SearchBtn(object sender, EventArgs e)
{
List<TrackList.Track> trans = new List<TrackList.Track>();
string search = SearchField.Text;
try
{
var content = "";
HttpClient client = new HttpClient();
var RestUrl = "http://api.musixmatch.com/ws/1.1/track.search?q_track=" + search + "&page_size=3&page=1&s_track_rating=desc";
client.BaseAddress = new Uri(RestUrl);
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(RestUrl);
content = await response.Content.ReadAsStringAsync();
var items = JsonConvert.DeserializeObject<List<TrackList.Body>>(content);
listTracks.ItemsSource = items;
}
catch (Exception ex)
{
string exception = ex.Message;
}
}
The json from PostMan
{
"message": {
"header": {
"status_code": 200,
"execute_time": 0.013219118118286,
"available": 10000
},
"body": {
"track_list": [
{
"track": {
"track_id": 143296606,
"track_mbid": "",
"track_isrc": "",
"track_spotify_id": "",
"track_soundcloud_id": "",
"track_xboxmusic_id": "",
"track_name": "&Burn",
"track_name_translation_list": [],
"track_rating": 61,
"track_length": 179,
"commontrack_id": 79313332,
"instrumental": 0,
"explicit": 0,
"has_lyrics": 1,
"has_lyrics_crowd": 0,
"has_subtitles": 1,
"has_richsync": 1,
"num_favourite": 19,
"lyrics_id": 17324950,
"subtitle_id": 19405016,
"album_id": 27788309,
"album_name": "Dont Smile At Me",
"artist_id": 34955086,
"artist_mbid": "",
"artist_name": "Billie Eilish feat. Vince Staples",
"album_coverart_100x100": "http://s.mxmcdn.net/images-storage/albums/nocover.png",
"album_coverart_350x350": "",
"album_coverart_500x500": "",
"album_coverart_800x800": "",
"track_share_url": "https://www.musixmatch.com/lyrics/Billie-Eilish-feat-Vince-Staples/burn-with-Vince-Staples?utm_source=application&utm_campaign=api&utm_medium=IT+Related%3A1409617652911",
"track_edit_url": "https://www.musixmatch.com/lyrics/Billie-Eilish-feat-Vince-Staples/burn-with-Vince-Staples/edit?utm_source=application&utm_campaign=api&utm_medium=IT+Related%3A1409617652911",
"commontrack_vanity_id": "Billie-Eilish-feat-Vince-Staples/burn-with-Vince-Staples",
"restricted": 0,
"first_release_date": "2017-12-15T00:00:00Z",
"updated_time": "2017-12-17T22:53:56Z",
"primary_genres": {
"music_genre_list": []
},
"secondary_genres": {
"music_genre_list": []
}
}
}
]
}
}
}
You're telling it to deserialize the result to a list, when actually the result is object with 1 property (message) which has 2 properties (header and body), so make sure your object structure matches. I find json2csharp extremely handy for complex structures like this.
public class TrackListResponse
{
public Message message { get; set; }
public class Header
{
public int status_code { get; set; }
public double execute_time { get; set; }
public int available { get; set; }
}
public class PrimaryGenres
{
public List<object> music_genre_list { get; set; }
}
public class SecondaryGenres
{
public List<object> music_genre_list { get; set; }
}
public class Track
{
public int track_id { get; set; }
public string track_mbid { get; set; }
public string track_isrc { get; set; }
public string track_spotify_id { get; set; }
public string track_soundcloud_id { get; set; }
public string track_xboxmusic_id { get; set; }
public string track_name { get; set; }
public List<object> track_name_translation_list { get; set; }
public int track_rating { get; set; }
public int track_length { get; set; }
public int commontrack_id { get; set; }
public int instrumental { get; set; }
public int #explicit { get; set; }
public int has_lyrics { get; set; }
public int has_lyrics_crowd { get; set; }
public int has_subtitles { get; set; }
public int has_richsync { get; set; }
public int num_favourite { get; set; }
public int lyrics_id { get; set; }
public int subtitle_id { get; set; }
public int album_id { get; set; }
public string album_name { get; set; }
public int artist_id { get; set; }
public string artist_mbid { get; set; }
public string artist_name { get; set; }
public string album_coverart_100x100 { get; set; }
public string album_coverart_350x350 { get; set; }
public string album_coverart_500x500 { get; set; }
public string album_coverart_800x800 { get; set; }
public string track_share_url { get; set; }
public string track_edit_url { get; set; }
public string commontrack_vanity_id { get; set; }
public int restricted { get; set; }
public DateTime first_release_date { get; set; }
public DateTime updated_time { get; set; }
public PrimaryGenres primary_genres { get; set; }
public SecondaryGenres secondary_genres { get; set; }
}
public class TrackList
{
public Track track { get; set; }
}
public class Body
{
public List<TrackList> track_list { get; set; }
}
public class Message
{
public Header header { get; set; }
public Body body { get; set; }
}
}
Then just deserialize to the outer object:
JsonConvert.DeserializeObject<TrackListResponse>(content);
I think you can't deserialize a single object into a collection. So you should use TrackList.Body instead of List<TrackList.Body>
So you maybe have to change this line:
var items = JsonConvert.DeserializeObject<List<TrackList.Body>>(content);
to
var items = JsonConvert.DeserializeObject<TrackList.Body>(content);
then iterate each item in items to add them to a List<TrackList.Body>