I am trying to obtain values for Customer attributes via the Rest API. Currently, I can retrieve customer attributes, but am unable to determine which specific attribute is associated. For example, given this code (based on https://github.com/Acumatica/AcumaticaRESTAPIClientForCSharp, Endpoint = "Default", EndpointVersion = "18.200.001", Endpoint Library = Acumatica.Default_20.200.001, Acumatica version = Cloud ERP 2020 R1, Build 20.110.0017):
var customerApi = new CustomerApi(configuration);
var customers = customerApi.GetList(top: 5, expand: "Attributes", select: "Attributes/Attribute,Attributes/Value");
foreach (var cust in customers)
{
Console.WriteLine(cust.ToString());
}
Yields this output:
{
"AccountRef": {},
"Attributes": [
{
"Value": {
"value": "True"
},
"id": "8de7a85d-6d60-4235-9d35-74a9d08d1cc6",
"rowNumber": 1,
"custom": {}
},
{
"Value": {
"value": "Sample Email Body"
},
"id": "8da2a21c-2ba3-45ba-9e12-02122c626e11",
"rowNumber": 2,
"custom": {}
}, ...
What am I missing to be able to get the attribute name returned as well? Or how I am supposed to correlate the given values back to a given attribute?
The default configuration of the Customers API is returning the Attributes array as below for the customerApi.GetList(top: 5, expand: "Attributes", select: "Attributes/Attribute,Attributes/Value"); request
"Attributes": [
{
"Attribute": {
"value": "Company Revenue"
},
"Value": {
"value": "1,000,000 to 5,000,000"
},
"id": "6df69428-7157-438f-8b61-99b2d7d1a3ad",
"rowNumber": 1,
"custom": {}
},
{
"Attribute": {
"value": "Number of Employees"
},
"Value": {
"value": "1-100"
},
"id": "15c3f47f-36eb-481b-92c0-f6b2f738732f",
"rowNumber": 2,
"custom": {}
}
]
Attributes->Attribute->Value is the identifier for the Attribute which is corresponding to the Description of the Attribute record.
Your result is returned for customerApi.GetList(top: 5, expand: "Attributes", select: "Attributes/Value"); request. Please make sure that you have included the Attributes/Attribute in the select part if you are specifying it.
UPDATE
There is a small difference in naming between 18.200 and 20.200.
In 18.200 the Attribute ID is actually named Attribute
In 20.200 the Attribute ID is renamed to Attribute ID
That is why this request is working correctly for 18.200
namespace Acumatica.Default_18_200_001.Model
{
[DataContract]
public class AttributeDetail : Entity_v3
{
[DataMember(Name="Attribute", EmitDefaultValue=false)]
public StringValue Attribute { get; set; }
[DataMember(Name="RefNoteID", EmitDefaultValue=false)]
public GuidValue RefNoteID { get; set; }
[DataMember(Name="Required", EmitDefaultValue=false)]
public BooleanValue Required { get; set; }
[DataMember(Name="Value", EmitDefaultValue=false)]
public StringValue Value { get; set; }
}
}
namespace Acumatica.Default_20_200_001.Model
{
[DataContract]
public class AttributeValue : Entity_v4
{
[DataMember(Name="AttributeID", EmitDefaultValue=false)]
public StringValue AttributeID { get; set; }
[DataMember(Name="AttributeDescription", EmitDefaultValue=false)]
public StringValue AttributeDescription { get; set; }
[DataMember(Name="RefNoteID", EmitDefaultValue=false)]
public GuidValue RefNoteID { get; set; }
[DataMember(Name="Required", EmitDefaultValue=false)]
public BooleanValue Required { get; set; }
[DataMember(Name="Value", EmitDefaultValue=false)]
public StringValue Value { get; set; }
[DataMember(Name="ValueDescription", EmitDefaultValue=false)]
public StringValue ValueDescription { get; set; }
}
}
Related
here Is my Models ,here in my model PK is decorated with Key becoz in EF it must be . But as it is aslo available in base class. if I removed PK from Person it gives error as model has not assign a Key IN EF which is strange to me .
public class Person:TBase
{
[Key]
public long PK { get; set; }
public string NAME { get; set; }
public string ADDRESS { get; set; }
}
public class TBase: Base
{
public virtual long? FKTenant { get; set; }
public virtual bool IsDefault { get; set; }
}
public class Base
{
[Key]
public long PK { get; set; }
public virtual string GlobalID { get; set; }
}
and Controller
[EnableQuery]
public IHttpActionResult Get()
{
try
{
IQueryable<Person> result;
var result = DbContext.Persons.Where(x => x.FKTenant == context.FKTenant).ToList();
return Ok(result);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
i am getting response in postman is
"value": [
{
"#odata.etag": "W/\"bnVsbA==\"",
"PK": 1001,
"NAME": "VIVEK",
"ADDRESS": "DELHI",
"FKTenant":null,
"IsDefault ":null,
"GlobalID ":null
}]
But my Intention to get ouput response as below which should contain onlly name and address
"value": [
{
"#odata.etag": "W/\"bnVsbA==\"",
"NAME": "VIVEK",
"ADDRESS": "DELHI"
}]
Any guide will be appreciable.
You should use a ViewModel
write another class as ViewModel and when you want return object first map to new ViewModel then return it.
my query
/API/Json/GetJson?Desc=test1
I get all records not just the test1 records
[Route("/API/Json/GetJson", "GET")]
public class GetJson : QueryDb<JsonModel>
{
public int? Id { get; set; }
public int? RefId { get; set; }
public int? SecondRefId { get; set; }
public int? ThirdRefId { get; set; }
public int? FourthRefId { get; set; }
public string Name { get; set; }
public string JSON { get; set; }
public string JsonType { get; set; }
public string Desc { get; set; }
public int? AuditId { get; set; }
}
public class JsonModel
{
[AutoIncrement]
[PrimaryKey]
[IgnoreOnUpdate]
public int Id { get; set; }
/// <summary>
/// Other tables the this data is relevant to
/// </summary>
public int? RefId { get; set; }
public int? SecondRefId { get; set; }
public int? ThirdRefId { get; set; }
public int? FourthRefId { get; set; }
/// <summary>
/// name that is displayed to users
/// </summary>
[Required]
public string Name { get; set; }
public string JSON { get; set; }
/// <summary>
/// Tells what data type the JSON is storing
/// </summary>
[Required]
public string JsonType { get; set; }
public string Desc { get; set; }
public int AuditId { get; set; }
public DateTime AuditStamp { get; set; } = DateTime.UtcNow;
}
also my return data has extra fields. Starting at Skip
{
"id": 4,
"refId": 9,
"secondRefId": 3,
"thirdRefId": 100,
"fourthRefId": null,
"name": "test",
"json": "JSON STRING DATA",
"jsonType": "test",
"desc": "test3",
"auditId": 0,
**"skip": null,
"take": null,
"orderBy": null,
"orderByDesc": null,
"include": null,
"fields": null,
"meta": null**
},
I updated my model to nullables and its is till returing all records. My seed data and I am using SS 5.6.0
WireUpService<IntegrationService>();
using (var db = HostContext.Resolve<IDbConnectionFactory>().Open())
{
string JSON = " \"Columns\": [\r\n {\r\n \"CompanyName\": [\r\n {\r\n \"name\": \"Company Name\",\r\n \"Visible\": \"True\",\r\n \"Sort\": \"U,A,Z[Unsorted, A-Z, Z-A]\",\r\n \"Filter\": \"Test Company\"\r\n }\r\n ],\r\n \"ParentCompnay\": [\r\n {\r\n \"name\": \"Company Name\",\r\n \"Visible\": \"True\",\r\n \"Sort\": \"U,A,Z[Unsorted, A-Z, Z-A]\",\r\n \"Filter\": \"Test Company\"\r\n }\r\n ]\r\n }";
db.DropAndCreateTable<JsonModel>();
db.Insert(new JsonModel { Desc = "test",Name = "test",JsonType = "test", JSON = JSON,RefId = 10,SecondRefId = 3, AuditId = 0, AuditStamp = DateTime.Now });
db.Insert(new JsonModel { Desc = "test1", Name = "test", JsonType = "test", JSON = JSON, RefId = 10, SecondRefId = 3, AuditId = 0, AuditStamp = DateTime.Now });
db.Insert(new JsonModel { Desc = "test2", Name = "test", JsonType = "test", JSON = JSON, RefId = 5, SecondRefId = 3, AuditId = 0, AuditStamp = DateTime.Now });
db.Insert(new JsonModel { Desc = "test3", Name = "test", JsonType = "test", JSON = JSON, RefId = 9, SecondRefId = 3,ThirdRefId = 100, AuditId = 0, AuditStamp = DateTime.Now });
}
I wasn't able to reproduce this issue using the classes provided, which I've seeded with test data that matches the query and non-matching test data that you've included in your JSON response:
db.CreateTable<JsonModel>();
db.Insert(new JsonModel { RefId = 1, SecondRefId = 1, ThirdRefId = 111, Name = "test1", Desc = "test1", JsonType = "test", JSON = "TEST1"});
db.Insert(new JsonModel { RefId = 9, SecondRefId = 3, ThirdRefId = 100, Name = "test1", Desc = "test3", JsonType = "test", JSON = "JSON STRING DATA"});
There is an issue with your GetJson model where you've specified Id and AuditId as non-nullable int properties which if not specified are populated in your GetJson Request DTO as 0 (default int).
If you're going to include required value types on your GetJson AutoQuery Service you should always be providing values for them otherwise change them into int? so they're not added to the query filter when they're not specified, e.g:
public class GetJson : QueryDb<JsonModel>
{
public int? Id { get; set; }
public int? AuditId { get; set; }
}
After doing this, it works as expected where I can query the Auto Query Service using your specified query, i.e:
var url = baseUrl.CombineWith("/API/Json/GetJson").AddQueryParam("Desc", "test1");
var json = url.GetJsonFromUrl();
json.Print();
Which works as expected returning the matching result in a QueryResponse<T> DTO, i.e:
{"Offset":0,"Total":0,"Results":[{"Id":1,"RefId":1,"SecondRefId":1,"ThirdRefId":111,"Name":"test1","JSON":"TEST1","JsonType":"test","Desc":"test1","AuditId":0,"AuditStamp":"\/Date(1577190306230-0000)\/"}],"Meta":{}}
I have the following structure in my json file
"missionName": "missionname",
"thumb_image": "pics/mission-info.png",
"uplinkPage": [
{
"RPC": {
"name": "RPC",
"rpc": "",
"args": ""
},
"EXE": {
"name": "app1",
"prog": "",
"args": ""
},
"VM": {
"name": "VM",
"name": "",
"args": ""
},
"JAR": {
"name": "JAR",
"prog": "",
"args": ""
},
"link": {
"name": "somelink",
"url": ""
}
}
],
for this I have the following class
public class EXE
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class RPC
{
public string name { get; set; }
public string rpc { get; set; }
public string args { get; set; }
}
public class VM
{
public string name { get; set; }
public string args { get; set; }
}
public class JAR
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class Link
{
public string name { get; set; }
public string url { get; set; }
}
public class UplinkPage
{
public VM[] vmList { get; set; }
public EXE[] exeList { get; set; }
public RPC[] rpcList { get; set; }
public JAR[] jarList { get; set; }
public Link[] linkList { get; set; }
}
public class Rootobject
{
public string missionName { get; set; }
public string thumb_image { get; set; }
public Uplinkpage[] uplinkPage { get; set; }
}
the uplinkPage section can have one or many of each of the EXE, RPC, VM .. sections. I have tried to add multiply sections like this
"EXE": {
"1": {
"name": "app1",
"data-prog": "",
"data-args": ""
},
"2": {
"name": "app2",
"data-prog": "",
"data-args": ""
}
}
when I do the deserialization as so
Rootobject page = JsonConvert.DeserializeObject<Rootobject>(File.ReadAllText("mission1.json"));
I get an object and I can read everything except if I have multiply values of the same type, I will only get one of them. If I declare sections as array
public EXE[] exeList { get; set; }
I will get the last one and if as
Dictionary<string,EXE> exeList {get; set;}
I will get the first one. I have noticed that when I use the dictionary the type of the EXE changes to EXE1.
So I was wondering what am I doing wrong? am I mission some thing here?
cheers,
es
Whenever you have a JSON property that might be duplicated, it will be easiest to represent the value of that property as JSON array, rather than multiple properties with duplicated names. I.e. instead of
{
"EXE" : {"id":1},
"RPC" : {"name":"a"},
"EXE" : {"id":2},
}
You want to do:
{
"EXE" : [{"id":1}, {"id":2}],
"RPC" : [{"name":"a"}]
}
Similarly, in the VM class, name appears multiple times, so name should be an array as well:
public class VM
{
public string [] name { get; set; }
public string args { get; set; }
}
(It's not impossible to deserialize duplicated property names, just difficult, and requires a custom converter. See How to deserialize JSON with duplicate property names in the same object. Since you control your JSON format, I'd recommend avoiding this. Using a nested object with indexed properties as you propose in your question is also an option; it is less difficult but still requires custom conversion. See How to parse this JSON using Newton Soft for nested object. But using a JSON array is easiest.)
Next, you need to tell Json.NET how to map c# property names to JSON property names when they are inconsistent. For instance, in your JSON you have a property "EXE" but in c# the property name is public EXE[] exeList { get; set; }. You can either rename the JSON properties, rename the c# properties, or make the mapping using [JsonProperty]:
public class UplinkPage
{
[JsonProperty("VM")]
public VM[] vmList { get; set; }
[JsonProperty("EXE")]
public EXE[] exeList { get; set; }
[JsonProperty("RPC")]
public RPC[] rpcList { get; set; }
[JsonProperty("JAR")]
public JAR[] jarList { get; set; }
[JsonProperty("link")]
public Link[] linkList { get; set; }
}
I notice also that your EXE object sometimes has a "data-prog" property, and sometimes just a "prog". You should standardize on one.
Thus your JSON should look like:
{
"missionName": "missionname",
"thumb_image": "pics/mission-info.png",
"uplinkPage": [
{
"RPC": [
{
"name": "RPC",
"rpc": "",
"args": ""
}
],
"EXE": [
{
"name": "app1",
"prog": "prog1",
"args": "args1"
},
{
"name": "app2",
"prog": "prog2",
"args": "args2"
}
],
"VM": [
{
"name": [
"VM",
""
],
"args": ""
}
],
"JAR": [
{
"name": "JAR",
"prog": "",
"args": ""
}
],
"link": [
{
"name": "somelink",
"url": ""
}
]
}
]
}
And your classes should look like:
public class EXE
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class RPC
{
public string name { get; set; }
public string rpc { get; set; }
public string args { get; set; }
}
public class VM
{
public string [] name { get; set; }
public string args { get; set; }
}
public class JAR
{
public string name { get; set; }
public string prog { get; set; }
public string args { get; set; }
}
public class Link
{
public string name { get; set; }
public string url { get; set; }
}
public class UplinkPage
{
[JsonProperty("VM")]
public VM[] vmList { get; set; }
[JsonProperty("EXE")]
public EXE[] exeList { get; set; }
[JsonProperty("RPC")]
public RPC[] rpcList { get; set; }
[JsonProperty("JAR")]
public JAR[] jarList { get; set; }
[JsonProperty("link")]
public Link[] linkList { get; set; }
}
public class Rootobject
{
public string missionName { get; set; }
public string thumb_image { get; set; }
public UplinkPage[] uplinkPage { get; set; }
}
prototype fiddle.
Basically I would like to conditionally ignore a property based on the mapped parent.
An example:
Here are my DTOs:
public class PersonDTO
{
public int Id { get; set; }
public string Name { get; set; }
public List<EmploymentDTO> Employments { get; set; }
public List<HobbyDTO> Hobbies { get; set; }
}
public class EmploymentDTO
{
public int Id { get; set; }
public string Name { get; set; }
public PersonDTO Person { get; set; }
}
public class HobbyDTO
{
public int Id { get; set; }
public string Name { get; set; }
public PersonDTO Person { get; set; }
}
If I request a person then I would like to see its employments and hobbies returned but not an employment or hobby's persons. So I'd don't want to see the person objects in the following JSON:
{
Id : 123,
Name : "Person1",
Employments [
{
Id : 1,
Name : "Employment1",
Person : { ... }
},
{
Id : 2,
Name : "Employment2",
Person : { ... }
}],
Hobbies [
{
Id : 1,
Name : "Hobby1",
Person : { ... }
},
{
Id : 2,
Name : "Hobby2",
Person : { ... }
}]
}
Similarly, if employments was requested, I'd like the following JSON to be returned without the Employments and Hobbies properties on the person object:
{
Id : 1,
Name : "Employment1"
Person : {
Id : 123,
Name : "Person1",
Employments : [ ... ],
Hobbies : [ ... ]
}
}
Is there a way of doing this with Automapper? I've played around with Ignore and Condition but not been able to achieve what I need. I suppose I need to ignore properties depending on what the parents parent object is.
Have you looked at explicit expansion? https://github.com/AutoMapper/AutoMapper/wiki/Queryable-Extensions#explicit-expansion
You can direct AutoMapper to only expand certain properties at runtime. It's available in the LINQ mode of AutoMapper.
I have a class which contains some items. I want to serialize an instance of this class to json using the DataContractJsonSerializer :
[DataContract]
public class Policy
{
private string expiration { get; set; }
private List<List<string>> conditions { get; set; }
public Policy(){}
public Policy(string expiration, List<List<string>> conditions){
this.expiration = expiration;
this.conditions = conditions;
}
[DataMember]
public string DateExpiration
{
get{ return expiration;}
set{expiration = value;}
}
[DataMember]
public List<List<string>> Conditions
{
get{return conditions;}
set{conditions = value;}
}
}
When serialized to json it should be like this :
{
"expiration": "2011-04-20T11:54:21.032Z",
"conditions": [
["eq", "acl", "private"],
["eq", "bucket": "myas3bucket"],
["eq", "$key", "myfilename.jpg"],
["content-length-range", 0, 20971520],
["eq", "$redirect", "myredirecturl"],
]
}
I tried like this but nothing :
string expiration = "2012-12-01T12:00:00.000Z";
List<List<string>> conditions = new List<List<string>>()
{
new List<string>(){ "[ eq", "acl", "private ]" },
new List<string>(){ "[ eq", "bucket", "myas3bucket]" },
new List<string>(){ "[ eq", "$key", "myfilename.jpg ]" },
new List<string>(){ "[ content-length-range", "0", "20971520]" },
new List<string>(){ "[ eq", "$redirect", "myredirecturl]" }
};
Policy myPolicy = new Policy(expiration,conditions);
string policy = JSONHelper.Serialize<Policy>(myPolicy);
thanks
First off... your class needs a little help:
[DataContract]
public class Policy
{
public Policy(){}
public Policy(string expiration, List<List<string>> conditions){
this.DateExpiration = expiration;
this.Conditions = conditions;
}
[DataMember]
public string DateExpiration { get; set; }
[DataMember]
public List<List<string>> Conditions { get; set; }
}
Try removing the brackets in your lists:
string expiration = "2012-12-01T12:00:00.000Z";
List<List<string>> conditions = new List<List<string>>()
{
new List<string>(){ "eq", "acl", "private" },
new List<string>(){ "eq", "bucket", "myas3bucket" },
new List<string>(){ "eq", "$key", "myfilename.jpg" },
new List<string>(){ "content-length-range", "0", "20971520" },
new List<string>(){ "eq", "$redirect", "myredirecturl" }
};
Policy myPolicy = new Policy(expiration,conditions);
string policy = JSONHelper.Serialize<Policy>(myPolicy);