Add root element to response model - c#

I'm writing an ASP.NET Core API, which should follow an existing format.
The response should always start with a data element in the json
{
"data": {
"batch_id": null,
"created_at": "2019-01-29T16:58:04+00:00",
"current_operation": null,
"description": "This watch has a new name",
"model": {
"brand_id": null,
"created_at": null,
...
}
}
}
I created a class Batch which contains all the properties that we see, and my controller is taking care of serialize it in the background.
public class Batch
{
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("serial_number")]
public string SerialNumber { get; set; }
[HttpGet("{id}")]
public ActionResult<Batch> Get(string id)
{
...
return batch;
}
Is there a way to write something so that every payload has to start with a data property?
I would like to avoid writing a class DataWrapper<T> that I have to use for every response.

You could just use an anonymous object to wrap the response from the controller:
[HttpGet("{id}")]
public ActionResult<Batch> Get(string id)
{
...
return Ok(new { data = batch });
}

You can use GenericClass
public class GenericResponseClass<T>{
public T data;
}
then you can pass your batch(or any other) class to GenericResposneClass just like
public class Batch
{
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("serial_number")]
public string SerialNumber { get; set; }
}
GenericResponseClass<Batch> response = new GenericResponseClass<Batch>();
Batch batch = new Batch();
batch.Label = "New Label";
batch.SerialNumber = "Serial Number";
response.data = batch;
then pass/serialize your response

Related

How can I convert url-encoded or url-decoded string to json format and then to object?

I'm getting a post request to my api (x-www-form-urlencoded) and the body of the request looks like this:
worker=%7B%22_id%22%3A+%7B%22%24oid%22%3A+%2261asd23e9231241dfd2b4c3bd%22%7D%2C+%22sid%22%3A+%22WKb32df49cas43413585352e8a6e2%cd%22%22%%22%3A+1234154123%7D%7D&task=%7B%22_id%22%3A+%7B%22%24oid%22%3A+%2261caffc34dsf33182b4c789
continues.
There are 2 objects (classes) that I need to receive in this incoming request, and I created the class structure of these 2 objects: For example, my class structure is as follows:
public class Worker
{
[JsonProperty("friendly_name")]
public string FriendlyName { get; set; }
[JsonProperty("date_updated")]
public WorkerDateUpdated DateUpdated { get; set; }
[JsonProperty("activity")]
public string Activity { get; set; }
[JsonProperty("workspace_sid")]
public string WorkspaceSid { get; set; }
[JsonProperty("date_created")]
public WorkerDateCreated DateCreated { get; set; }
[JsonProperty("queues")]
public List<string> queues { get; set; }
}
public class Task
{
[JsonProperty("reason")]
public string Reason { get; set; }
[JsonProperty("date_updated")]
public TaskDateUpdated DateUpdated { get; }
[JsonProperty("assignment_status")]
public string AssignmentStatus { get; set; }
[JsonProperty("total_cost")]
public TaskTotalCost TotalCost { get; set; }
}
In the incoming request, I receive 3 objects (class) as url-encoded, I only need 2 objects and their properties.
using (var reader = new StreamReader(
HttpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false
))
{
var bodyString = await reader.ReadToEndAsync();
_logger.LogInformation("BodyString ---> " + bodyString);
var decodedUrl = HttpUtility.UrlDecode(bodyString);
_logger.LogInformation(" decodedUrl ---> " + decodedUrl);
}
I can read the incoming body and convert it to decoded format. Below is an example:
worker={"_id": {"$oid": "XXXXXXXXXX"}, "sid": "XXXXXXXXXXXXX", "x": true, "account_sid": "XXXXXXXXXXXX", "workspace_sid": "XXXXXXXXXXXX", "queues ": ["XXXXXXXXXXXXXX"], "activity": "idle", "available": true, "friendly_name": "XXXXXXXX", "attributes": {"mail": "XXXXXXXXXXXX", "name": "XXXXXXXXXX" }, "date_created": {"$date": XXXXXXXXX}, "date_updated": {"$date": XXXXXXXXXX}, "date_status_changed": {"$date": XXXXXXXXXXXXX}}&task={"_id": {" $oid": "XXXXXXXXXXXXXX"}, "sid": "XXXXXXXXXXXX", "x": true, "account_sid": "XXXXXXXXXXX", "workspace_sid": "XXXXXXXXXXXXXXXXXX", "workflow_sid": "XXXXXXXXXXXX", "workflow_friendly_name" : "daytime1", "initial_attributes": {"station_name": "XXXXX", "component_type": X, "component_id": XXX, "mail": "XXXXXX", "main_issue": "XXXXXXXXXXXXXX", "predictivi_maintenance_time": "XXXXXXXXXX", "hospital_name": "\u00dcsk\u00fcdar XXXXXXXXXXX"}
I can see it as , but I can't deserialize it. Or I don't know if I'm doing it wrong. I have created a separate class that contains my 2 classes. I keep my Worker and Task class in it, I cannot deserialize to that class, it does not deserialize in any way. Unexpected charachter throws exception. How can I convert these objects to json format or object format?
Edit:
My Other Custom classes:
public class TaskDateUpdated
{
[JsonProperty("$date")]
public long Date { get; set; }
}
public class TaskTotalCost
{
[JsonProperty("$numberDecimal")]
public string NumberDecimal { get; set; }
}
public class TaskDateCreated
{
[JsonProperty("$date")]
public long Date { get; set; }
}
public class TaskLastChargeDate
{
[JsonProperty("$date")]
public long Date { get; set; }
}
public class TaskId
{
[JsonProperty("$oid")]
public string Oid { get; set; }
}
public class WorkerDateUpdated
{
[JsonProperty("$date")]
public long date { get; set; }
}
public class WorkerDateCreated
{
[JsonProperty("$date")]
public long date { get; set; }
}
public class WorkerDateStatusChanged
{
[JsonProperty("$date")]
public long date { get; set; }
}
I also have a single class containing these 2 classes, I get an error when I try to deserialize to this class, I also get an error when I try to deserialize it to other worker and task classes separately. I can't deserialize at all.
public class DataContainer
{
public Task Task { get; set; }
public Worker Worker { get; set; }
}
My post method looks like this:
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<ActionResult<ResponseRequest>> AddWorkerTask()
{
using (var reader = new StreamReader(
HttpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false
))
{
var bodyString = await reader.ReadToEndAsync();
_logger.LogInformation("BodyString ---> " + bodyString);
var decoded = HttpUtility.UrlDecode(bodyString);
//here is where i need to deserialize and convert it to
//a valid json and object
}
}
You can use HttpUtility.ParseQueryString to parse it into a NameValueCollection, then simply use the indexer ["worker"] on that.
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<ActionResult<ResponseRequest>> AddWorkerTask()
{
using (var reader = new StreamReader(
HttpContext.Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false
))
{
var bodyString = await reader.ReadToEndAsync();
var decoded = HttpUtility.ParseQueryString(bodyString);
var worker = JsonSerializer.Deserialize<Worker>(decoded["worker"]);
var task = JsonSerializer.Deserialize<Task>(decoded["task"]);
// or whatever your JSON deserializer is
}
}
In newer versions of ASP.net Core you can use HttpContext.Request.Form
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public async Task<ActionResult<ResponseRequest>> AddWorkerTask()
{
var worker = JsonSerializer.Deserialize<Worker>(HttpContext.Request.Form["worker"]);
var task = JsonSerializer.Deserialize<Task>(HttpContext.Request.Form["task"]); // or whatever your JSON deserializer is
}

Dotnet using graphQL client, Data response not mapped

I'm using the last GraphQL client NuGet package (3.2.1) on .NET Core 3.1 project and calling a GraphQL API.
When I do the "SendQueryAsync()" or "SendMutationAsync()" the response status code is OK but the Data property is always Null.
I think it's related to the serialization but idk where is the problem.
How I use it
var graphQLClient = new GraphQLHttpClient(new GraphQLHttpClientOptions { EndPoint = new Uri(_graphQLEndPoint) }, new NewtonsoftJsonSerializer(), httpclient);
var request = new GraphQLRequest
{
Query = #"query CurrentUserCards {
currentUser {
cardsCount
cards {
name
pictureUrl
position
player {
displayName
}
}
}
}"
};
var data = await graphQLClient.SendQueryAsync<Data>(request);
Even if I put "Rootobject" class it's null.
My model
I generated my model with "Paste JSON as classes" feature on Visual studio, from the JSON result.
public class Rootobject
{
public Data data { get; set; }
}
public class Data
{
public Currentuser currentUser { get; set; }
}
public class Currentuser
{
public int cardsCount { get; set; }
public Card[] cards { get; set; }
}
public class Card
{
public string name { get; set; }
public string pictureUrl { get; set; }
public string position { get; set; }
public Player player { get; set; }
}
public class Player
{
public string displayName { get; set; }
}
Response from Postman
{
"data": {
"currentUser": {
"cardsCount": 12,
"cards": [
{
"name": "Henry",
"pictureUrl": "",
"position": "Coach",
"player": {
"displayName": "Thierry Henry",
}
},
{
"name": "Zidane",
"pictureUrl": "",
"position": "Coach",
"player": {
"displayName": "Zinedine Zidane",
}
}
...
]
}
}
}
I have solved this by removing the Rootobject class and use the Data class as root. I think that the response always has a data property so it skips that in the deserialization.

How to send individual variables from collected API data to another location

I'm trying to collect data from a client through an API. Eventually sending individual parts of the data that I collected to another project.
So for example I'm collecting an entire data object with id,Name,Status, etc. And I only want the id variable with it's value to be send to another project.
Everything works fine except from the sending part. I still had to paste all related classes to make it easier to understand.
I'm trying to send a list of objects. The problem is that I don't know how to send it the right way. You can see what I tried below. I'm creating my own object named WatchdogDTO which contains only the values that I want to send. Eventually I serialize it to send it to http://localhost:53661/api/Values. Which is another project I use to test if it works. Now it just literally sends the name of the list instead of the actual WatchdogDTO.
This is the data I'm collecting:
[
{
"id": "200",
"name": "Kerno (Camera)",
"hostName": "Amsterdam",
"status": false,
"hasCamera": true,
"cameraStatus": "0",
"lastSeen": "34324"
},
{
"id": "202",
"name": "Bassy (Location)",
"hostName": "Limburg",
"status": true,
"hasCamera": false,
"cameraStatus": "-1",
"lastSeen": "2344"
}
]
I created a corresponding model:
public class ServerStateDto
{
public string id { get; set; }
public string Name { get; set; }
public string HostName { get; set; }
public bool Status { get; set; }
public bool hasCamera { get; set; }
public string CameraStatus { get; set; }
public DateTime LastSeen { get; set; }
}
In the class ApiManager I collect the data above and deserialize it:
class ApiManager
{
HttpClient client = new HttpClient();
public List<ServerStateDto> CollectWatchdogData()
{
client.BaseAddress = new Uri("https://classified.Data.net:4802");
HttpResponseMessage response = client.GetAsync("/api/pdf/process/getalldata").Result;
if (response.IsSuccessStatusCode)
{
string dto = response.Content.ReadAsStringAsync().Result;
List<ServerStateDto> model = Newtonsoft.Json.JsonConvert.DeserializeObject<List<ServerStateDto>>(dto);
return model;
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
return null;
}
}
}
This is just a general class that calls the functions CollectWatchdogData(); and PostWatchdogData();
{
public bool Start(HostControl hostControl)
{
ApiManager x = new ApiManager();
List<ServerStateDto> returnedData = x.CollectWatchdogData();
if (returnedData == null)
{
return false;
}
WatchdogApiClient cli = new WatchdogApiClient();
cli.PostWatchdogData(returnedData);
return true;
}
}
This is a model for the object that I'm sending. I only want to send Id from the model above:
public class WatchdogDTO
{
public string id { get; set; }
}
This class actually sends the WatchdogDTO from above to localhost:53661 which is another visual studio project of my which I use to test if the sending works.
public class WatchdogApiClient
{
private static readonly HttpClient client = new HttpClient();
//public async void PostWatchdogData(ServerStateDto toSend)
public async void PostWatchdogData(List<ServerStateDto> toSend)
{
//to actually send the data
WatchdogDTO toActuallySend = new WatchdogDTO()
{
id = toSend.ToString()
};
//Serialize data to bytestream so it can be sent
string serializedWatchDogData = JsonConvert.SerializeObject(toActuallySend);
if (string.IsNullOrEmpty(serializedWatchDogData))
{
return;
try
{
var response = await client.PostAsync("http://localhost:53661/api/Values", new StringContent(serializedWatchDogData, Encoding.UTF8, "application/json"));
}
catch (Exception ex)
{
Console.WriteLine($"Encountered an exception during PostAsync in method PostWatchDogData: {ex.Message}");
throw ex;
}
}
}
Eventually the destination of the data has a class and a model aswell to receive the data sent
model:
public class WatchdogDTO
{
public string id { get; set; }
}
This is the sending part, the sending works but the problem is that the value of WatchdogDTO data is the name of the list instead of the actual list with its values.
Class to receive the data send:
public class ValuesController : ApiController
{
[HttpPost]
public void PostWatchdogData([FromBody] WatchdogDTO data)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
hubContext.Clients.All.BroadcastMessage("Server", "b");
}
}
How can I send individual parts like for example only the id, or the host name, or the id AND the hostname.
Thanks in advance and sorry for the bunch of code.

RestSharp - GET request with "$" response attribute name

I need to get GET response from REST API. I use RestSharp. The problem is, that one name of the response attribute is "$". This is the response:
[
{
"CodeId": {
"$": "00000000"
},
"Entity": {
"LegalName": {
"#xml:lang": "cs",
"$": "xxxxx"
}
}
}
]
How should I use the RestSharp to get the value of Entity.LegalName.$ ?
I found the answer thanks by #fredrik.
var client = new RestClient(url);
var request = new RestRequest(urlRequest, DataFormat.Json);
var response = client.Get(request);
Console.WriteLine(JsonSerializer.Deserialize<List<TestRestResponseTemplate>>(response.Content)[0].Entity.LegalName.Value);
TestRestResponseTemplate:
public class TestRestResponseTemplate
{
public Entity Entity { get; set; }
}
public class LegalName
{
[JsonPropertyName("#xml:lang")]
public string Language { get; set; }
[JsonPropertyName("$")]
public string Value { get; set; }
}
public class Entity
{
public LegalName LegalName { get; set; }
}

JSON to derived types deserialization difficulties

i have a solution where i consume a WebService using RestSharp providing JSON data. I have a class model like this, matching the received data:
public class PBase
{
public string Name { get; set; }
public virtual string GetValue()
{
return string.Empty;
}
}
public class PDouble : PBase
{
public double DoubleValue { get; set; }
public string Scale { get; set; }
public override string GetValue()
{
return DoubleValue.ToString(CultureInfo.InvariantCulture);
}
}
public class PBool : PBase
{
public bool? BoolValue { get; set; }
public override string GetValue()
{
if (!BoolValue.HasValue)
return null;
return BoolValue.Value ? "1" : "0";
}
}
Meerely deep within the data, such blocks as the following appear multiple times, holding the parameters of a parent object, which is not of much interest here (as everything else except the parameter thingy works fine):
"Parameters":
[
{
"__type": "PDouble:http://name.space.de/Parameter",
"Name": "DEPTH",
"DoubleValue": 5,
"Scale": "MM"
},
{
"__type": "PDouble:http://name.space.de/Parameter",
"Name": "HEIGHT",
"DoubleValue": 10,
"Scale": "MM"
},
{
"__type": "PBool:http://name.space.de/Parameter",
"Name": "ESSENTIAL",
"BoolValue": true
},
]
Now, the problem is, the deserialized data contains only PBase instances. So everything except Name is gone. How can i achieve correct deserialization?
EDIT:
For deserialization i have nothing special implemented, just like this:
var client = new RestClient()
{
BaseUrl = new Uri("MyURL")
};
var request = new RestRequest()
{
Resource = "MyResource",
Method = Method.GET
};
request.AddHeader("Accept", "application/json");
request.RequestFormat = DataFormat.Json;
var response = client.Execute<MyType>(request);
return response.Data;

Categories

Resources