from my rest call, I am receiving this JSON:
{
"livemode": true,
"error": {
"type": "unauthorized",
"message": "You did not provide a valid API key."
}
}
I need to fetch type and message into my type:
public class TestObject
{
string type { get; set; }
string message { get; set; }
}
But this returns null objects:
HttpClient client = new HttpClient();
Uri uri = new Uri("https://api.onlinebetaalplatform.nl/v1");
HttpResponseMessage response = await client.GetAsync(uri);
string content = await response.Content.ReadAsStringAsync();
JObject json = JObject.Parse(content);
TestObject album = json.ToObject<TestObject>();
1.) I understand that the type and message attributes are "nested". How do I access them?
2.) Even if I call my type livemode and error, the objects still return null.
Can you help me out a little?
Thank you :)
There seems to be one set of curly brackets to many. I am pretty sure that the api you are querying is not returning the first and the last curly bracket. Continue on after that has been taken care of.
In order to fetch the data, add these class definitions
public class Error
{
public string type { get; set; }
public string message { get; set; }
}
public class Root
{
public bool livemode { get; set; }
public Error error { get; set; }
}
and change
TestObject album = json.ToObject<TestObject>();
To
Root album = json.ToObject<Root>();
As some of the comments to your question mentioned, you are currently trying to convert the JSON string to the nested Error object instead of the root object, where the Error object is located.
In the future, there are tools that can generate C# classes from JSON. I used https://json2csharp.com/ this time around to do so.
EDIT:
I just found out that Visual Studio actually has an in-built JSON to Class feature!
I have an API request that goes off and the response structure back looks like this:
{
"MessageBody": {
"foo" : ""
}
}
The properties under MessageBody can be anything, not only foo, but its value is always a string.
eg. {"MessageBody": { "Token": "abc" }} or {"MessageBody": { "Name": "abc" }}
How can I capture this response from the API as a generic object for the property under MessageBody?
I can represent the first example above as:
public class MessageBody
{
public string Token { get; set; }
}
How would I represent both Token or Name properties under the same MessageBody object? There's a bunch of different values that MessageBody can have, but again they would all be of type string.
I have acheived something similar using Newtonsoft
Your route should take the body in as a generic object and it can then be deserialized into any object you'd like:
/*Using this method, the controller will automatically handle
validating proper Json format*/
[HttpPost]
public async Task<IActionResult> Post([FromBody] object Body)
{
/*here you will send the generic object to a service which will deserialize.
the object into an expected model.*/
customService.HandlePost(Body);
}
Now create an object with any expected fields you would get from the body. (Json2csharp.com is extremely useful!)
public class MessageBody
{
public string Token { get; set; }
public string Name { get; set; }
}
Inside your service you can handle the object like this:
using Newtonsoft.Json
using Models.MessageBody
public class customService()
{
public void HandlePost(object body)
{
var DeserializedBody = JsonConvert.DeserializeObject<MessageBody>(body);
//Any Values that were not assigned will be null in the deserialized object
if(DeserializedBody.Name !== null)
{
//do something
}
}
}
This is obviously a very bare bones implementation, error handling will be important to catch any invalid data. Instead of using one object and null fields to get the data you need, I would recommend adding a "subject" route variable (string) that you can use to determine which object to deserialize the body into.
post *api/MessageBody/{Subject}
I currently have a Web API that implements a RESTFul API. The model for my API looks like this:
public class Member
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Created { get; set; }
public DateTime BirthDate { get; set; }
public bool IsDeleted { get; set; }
}
I've implemented a PUT method for updating a row similar to this (for brevity, I've omitted some non-relevant stuff):
[Route("{id}")]
[HttpPut]
public async System.Threading.Tasks.Task<HttpResponseMessage> UpdateRow(int id,
[FromBody]Models.Member model)
{
// Do some error checking
// ...
// ...
var myDatabaseEntity = new BusinessLayer.Member(id);
myDatabaseEntity.FirstName = model.FirstName;
myDatabaseEntity.LastName = model.LastName;
myDatabaseEntity.Created = model.Created;
myDatabaseEntity.BirthDate = model.BirthDate;
myDatabaseEntity.IsDeleted = model.IsDeleted;
await myDatabaseEntity.SaveAsync();
}
Using PostMan, I can send the following JSON and everything works fine:
{
firstName: "Sara",
lastName: "Smith",
created: "2018/05/10",
birthDate: "1977/09/12",
isDeleted: false
}
If I send this as my body to http://localhost:8311/api/v1/Member/12 as a PUT request, the record in my data with ID of 12 gets updated to what you see in the JSON.
What I would like to do though is implement a PATCH verb where I can do partial updates. If Sara gets married, I would like to be able to send this JSON:
{
lastName: "Jones"
}
I would like to be able to send just that JSON and update JUST the LastName field and leave all the other fields alone.
I tried this:
[Route("{id}")]
[HttpPatch]
public async System.Threading.Tasks.Task<HttpResponseMessage> UpdateRow(int id,
[FromBody]Models.Member model)
{
}
My problem is that this returns all the fields in the model object (all of them are nulls except the LastName field), which makes sense since I am saying I want a Models.Member object. What I would like to know is if there is a way to detect which properties have actually been sent in the JSON request so I can update just those fields?
I hope this helps using Microsoft JsonPatchDocument:
.Net Core 2.1 Patch Action into a Controller:
[HttpPatch("{id}")]
public IActionResult Patch(int id, [FromBody]JsonPatchDocument<Node> value)
{
try
{
//nodes collection is an in memory list of nodes for this example
var result = nodes.FirstOrDefault(n => n.Id == id);
if (result == null)
{
return BadRequest();
}
value.ApplyTo(result, ModelState);//result gets the values from the patch request
return NoContent();
}
catch (Exception ex)
{
return StatusCode(StatusCodes.Status500InternalServerError, ex);
}
}
Node Model class:
[DataContract(Name ="Node")]
public class Node
{
[DataMember(Name = "id")]
public int Id { get; set; }
[DataMember(Name = "node_id")]
public int Node_id { get; set; }
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "full_name")]
public string Full_name { get; set; }
}
A valid Patch JSon to update just the "full_name" and the "node_id" properties will be an array of operations like:
[
{ "op": "replace", "path": "full_name", "value": "NewNameWithPatch"},
{ "op": "replace", "path": "node_id", "value": 10}
]
As you can see "op" is the operation you would like to perform, the most common one is "replace" which will just set the existing value of that property for the new one, but there are others:
[
{ "op": "test", "path": "property_name", "value": "value" },
{ "op": "remove", "path": "property_name" },
{ "op": "add", "path": "property_name", "value": [ "value1", "value2" ] },
{ "op": "replace", "path": "property_name", "value": 12 },
{ "op": "move", "from": "property_name", "path": "other_property_name" },
{ "op": "copy", "from": "property_name", "path": "other_property_name" }
]
Here is an extensions method I built based on the Patch ("replace") specification in C# using reflection that you can use to serialize any object to perform a Patch ("replace") operation, you can also pass the desired Encoding and it will return the HttpContent (StringContent) ready to be sent to httpClient.PatchAsync(endPoint, httpContent):
public static StringContent ToPatchJsonContent(this object node, Encoding enc = null)
{
List<PatchObject> patchObjectsCollection = new List<PatchObject>();
foreach (var prop in node.GetType().GetProperties())
{
var patch = new PatchObject{ Op = "replace", Path = prop.Name , Value = prop.GetValue(node) };
patchObjectsCollection.Add(patch);
}
MemoryStream payloadStream = new MemoryStream();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(patchObjectsCollection.GetType());
serializer.WriteObject(payloadStream, patchObjectsCollection);
Encoding encoding = enc ?? Encoding.UTF8;
var content = new StringContent(Encoding.UTF8.GetString(payloadStream.ToArray()), encoding, "application/json");
return content;
}
}
Noticed that tt also uses this class I created to serialize the PatchObject using DataContractJsonSerializer:
[DataContract(Name = "PatchObject")]
class PatchObject
{
[DataMember(Name = "op")]
public string Op { get; set; }
[DataMember(Name = "path")]
public string Path { get; set; }
[DataMember(Name = "value")]
public object Value { get; set; }
}
A C# example of how to use the extension method and invoking the Patch request using HttpClient:
var nodeToPatch = new { Name = "TestPatch", Private = true };//You can use anonymous type
HttpContent content = nodeToPatch.ToPatchJsonContent();//Invoke the extension method to serialize the object
HttpClient httpClient = new HttpClient();
string endPoint = "https://localhost:44320/api/nodes/1";
var response = httpClient.PatchAsync(endPoint, content).Result;
Thanks
PATCH operations aren't usually defined using the same model as the POST or PUT operations exactly for that reason: How do you differentiate between a null, and a don't change. From the IETF:
With PATCH, however, the enclosed entity contains a set of
instructions describing how a resource currently residing on the
origin server should be modified to produce a new version.
You can look here for their PATCH suggestion, but sumarilly is:
[
{ "op": "test", "path": "/a/b/c", "value": "foo" },
{ "op": "remove", "path": "/a/b/c" },
{ "op": "add", "path": "/a/b/c", "value": [ "foo", "bar" ] },
{ "op": "replace", "path": "/a/b/c", "value": 42 },
{ "op": "move", "from": "/a/b/c", "path": "/a/b/d" },
{ "op": "copy", "from": "/a/b/d", "path": "/a/b/e" }
]
#Tipx's answer re using PATCH is spot on, but as you've probably already found, actually achieving that in a statically typed language like C# is a non-trivial exercise.
In the case where you're using a PATCH to represent a set of partial updates for a single domain entity (e.g. to update the first name and last name only for a contact with many more properties) you need to do something along the lines of looping each instruction in the 'PATCH' request and then applying that instruction to an instance of your class.
Applying an individual instruction will then comprise of
Finding the property of the instance that matches the name in the
instruction, or handling property names you weren't expecting
For an update: Trying to parse the value submitted in the patch into the instance property and handling the error if e.g. the instance property is a bool but the patch instruction contains a date
Deciding what to do with Add instructions as you can't add new properties to a statically typed C# class. One approach is to say that Add means "set the value of the instance's property only if property's existing value is null"
For Web API 2 on the full .NET Framework the JSONPatch github project looks to make a stab at providing this code, although it doesn't look like there's been a lot of development on that repo recently and the readme does state:
This is still very much an early project, don't use it in production
yet unless you understand the source and don't mind fixing a few bugs
;)
Things are simpler on .NET Core as that has a set of functionality to support this in the Microsoft.AspNetCore.JsonPatch namespace.
The rather useful jsonpatch.com site also lists out a few more options for Patch in .NET:
Asp.Net Core JsonPatch (Microsoft official implementation)
Ramone (a framework for consuming REST services, includes a JSON Patch implementation)
JsonPatch (Adds JSON Patch support to ASP.NET Web API)
Starcounter (In-memory Application Engine, uses JSON Patch with OT for client-server sync)
Nancy.JsonPatch (Adds JSON Patch support to NancyFX)
Manatee.Json (JSON-everything, including JSON Patch)
I need to add this functionality to an existing Web API 2 project of ours, so I'll update this answer if I find anything else that's useful while doing that.
I wanted to achieve exactly the same thing, but used a different method to others described here. I've created a working repo using this if you want to check it out:
https://github.com/emab/patch-example
If you have the following two models:
Database model
public class WeatherDBModel
{
[Key]
public int Id { get; set; }
public string City { get; set; }
public string Country { get; set; }
public double Temperature { get; set; }
public double WindSpeed { get; set; }
public double Rain { get; set; }
public Weather(int id, string city, string country, double temperature, double windSpeed, double rain)
{
Id = id;
City = city;
Country = country;
Temperature = temperature;
WindSpeed = windSpeed;
Rain = rain;
}
}
Update model
Containing exact names of database model properties. Includes properties which can be updated
public class WeatherUpdateModel
{
public string? City { get; set; }
public string? Country { get; set; }
public double Temperature { get; set; }
public double WindSpeed { get; set; }
public double Rain { get; set; }
}
This update model is sent to the service layer along with the id of the object you'd like to update.
You can then implement the following method in your repository layer which maps any non-null values from the updateModel into an existing entity if it has been found:
public Weather Update(int id, WeatherUpdate updateObject)
{
// find existing entity
var existingEntity = _context.Weather.Find(id);
// handle not found
if (existingEntity == null)
{
throw new EntityNotFoundException(id);
}
// iterate through all of the properties of the update object
// in this example it includes all properties apart from `id`
foreach (PropertyInfo prop in updateObject.GetType().GetProperties())
{
// check if the property has been set in the updateObject
// if it is null we ignore it. If you want to allow null values to be set, you could add a flag to the update object to allow specific nulls
if (prop.GetValue(updateObject) != null)
{
// if it has been set update the existing entity value
existingEntity.GetType().GetProperty(prop.Name)?.SetValue(existingEntity, prop.GetValue(updateObject));
}
}
_context.SaveChanges();
return existingEntity;
}
Using this method you can change your models without worrying about the update logic, as long as you ensure that the UpdateModel is kept up-to-date with the database model.
If a property of your object was omitted in your JSON, ASP.NET won't "set" that property on the object, the property will have its default value. In order to know which properties were sent with the JSON object you need to have a way to detect which properties of the object were set.
In order to detect which properties have "actually been sent" with the JSON object, you can modify your Member class to contain a collection of property names that were "set". Then, for all properties that you want to be able to know if they were sent in the JSON object make that when the property is set the name of the property should be added to the collection of set properties.
public class Member
{
private string _firstName;
private string _lastName;
...
private bool _isDeleted;
public string FirstName
{
get => _firstName;
set
{
_firstName = value;
_setProperties.Add(nameof(FirstName));
}
}
public string LastName
{
get => _lastName;
set
{
_lastName = value;
_setProperties.Add(nameof(LastName));
}
}
...
public bool IsDeleted
{
get => _isDeleted;
set
{
_isDeleted= value;
_setProperties.Add(nameof(IsDeleted));
}
}
private readonly HashSet<string> _setProperties = new HashSet<string>();
public HashSet<string> GetTheSetProperties()
{
return new HashSet<string>(_setProperties);
}
}
In the UpdateRow method you can now check whether a property was sent in the JSON by checking if it is in the _setProperties collection. So if you want to see if the LastName was sent in the JSON just do
bool lastNameWasInJson = model.Contains(nameof(model.LastName));
Following up to Avid Learners approach. I found this easy to add to an existing PUT method.
Alternatively to avoid loading twice you could apply update operations and then before saving apply the patch, but I'd rather load twice and have simple code.
public ResultModel Patch(UpdateModel model)
{
var record = LoadAsUpdateModel(model.Id);
if (record == null) return null;
foreach(var propertyName in model.SetProperties())
{
var property = model.GetType().GetProperty(propertyName);
property.SetValue(record, property.GetValue(model));
}
return Update(record);
}
I am trying to call a rest api method from c#. Problem is for all content types it passes null to body parameter.I shared my code below.Apart from this code I have tried to write body parameter to request as stream.It didn't work either. I have also tried 'application/x-www-form-urlencoded' as content type.
Calling rest api method from c# sample:
string token = Server.UrlEncode("v0WE/49uN1/voNwVA1Mb0MiMrMHjFunE2KgH3keKlIqei3b77BzTmsk9OIREken1hO9guP3qd4ipCBQeBO4jiQ==");
string url = "http://localhost:2323/api/Applications/StartProcess?token=" + token;
string data = #"{""ProcessParameters"": [{ ""Name"":""flowStarter"",""Value"": ""Waffles"" }],
""Process"": ""RESTAPISUB""}";
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new System.Uri(url);
byte[] cred = UTF8Encoding.UTF8.GetBytes("username:password");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
System.Net.Http.HttpContent content = new StringContent(data, UTF8Encoding.UTF8, "application/json");
HttpResponseMessage messge = client.PostAsync(url, content).Result;
string description = string.Empty;
if (messge.IsSuccessStatusCode)
{
string result = messge.Content.ReadAsStringAsync().Result;
description = result;
}
Rest api Method:
[HttpPost]
[ActionName("StartProcess")]
public int StartProcess([FromUri]string token,[FromBody]WorkflowStartParameters parameters)
{
try
{
LoginInformation info = CasheProcesses.ReadCashe(token);
eBAWSAPI api = Service.GetWSService();
WorkflowProcess proc = api.StartProcess(info.Id, info.Password, info.ImpersonateUserId, info.Language, parameters);
return proc.ProcessId;
}
catch (Exception ex)
{
throw new Exception("An error occured when starting process,exception detail:" + ex);
}
}
WorkflowStartParameters class structure:
public class WorkflowStartParameters
{
public WorkflowParameter[] ProcessParameters;
public string Process { get; set; }
}
public class WorkflowParameter
{
public string Name { get; set; }
public string Value { get; set; }
}
I have searched this problem a lot. It seems as a very common problem. I just found this solution working properly, passing request parameter to rest api method and reading body parameter from there. But it is not a valid solution for me.
If you have any idea,feel free to share.
Thanks,
Zehra
I don´t know if it can solve your problem, but let me try.
I guess you don´t have to utilize Server.UrlEncode in your call, but:
Dim myUri As New Uri(Token)
And I guess you must not encode also your username and password - try pass them as string.
Your problem appear to be here:
public class WorkflowStartParameters
{
public WorkflowParameter[] ProcessParameters; <---- needs get/set
public string Process { get; set; }
}
This needs to be a public property to serialize properly. Currently you have it set up as a public field. Just add { get; set; } and give that a try. I would also look into serializing with Newtonsoft.Json to ensure your object is properly serialized. Trying to do it with escape strings will be messing the more data you are sending.
By the way there can be issues sometimes serializing arrays, I would change that to :
public List<WorkflowParameter> ProcessParameters{get;set;}
Finally I have achieved to send filled out data to server. It was about serialization problem. But it didn't work with json serialization before send data. I have added DataContract attribute to my class and it works properly.
Unfortunately still I couldn't figure out this when I make ajax calls from java script it works without DataContract attribute but if I call it in c# it needs DataContract attribute. If someone share the information about this I would appreciate!
I am sharing new class structure, everything else but this still same:
[Serializable]
[DataContract]
public class WorkflowParameter
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Value { get; set; }
}
[Serializable]
[DataContract]
public class WorkflowStartParameters
{
[DataMember]
public WorkflowParameter[] ProcessParameters { get; set; }
[DataMember]
public string Process { get; set; }
}
I'm using Restsharp to deserialize some webservice responses, however, the problem is that sometimes this webservices sends back a json response with a few more fields. I've manage to come around this so far by adding all possible field to my matching model, but this web service will keep adding/removing fields from its response.
Eg:
Json response that works:
{
"name": "Daniel",
"age": 25
}
Matching model:
public class Person
{
public string name { get; set; }
public int age { get; set; }
}
This works fine: Person person = deserializer.Deserialize<Person>(response);
Now suppose the json response was:
{
"name": "Daniel",
"age": 25,
"birthdate": "11/10/1988"
}
See the new field bithdate? Now everything goes wrong. Is there a way to tell to restsharp to ignore those fields that are not in the model?
If there's that much variation in the fields you're getting back, perhaps the best approach is to skip the static DTOs and deserialize to a dynamic. This gist provides an example of how to do this with RestSharp by creating a custom deserializer:
// ReSharper disable CheckNamespace
namespace RestSharp.Deserializers
// ReSharper restore CheckNamespace
{
public class DynamicJsonDeserializer : IDeserializer
{
public string RootElement { get; set; }
public string Namespace { get; set; }
public string DateFormat { get; set; }
public T Deserialize<T>(RestResponse response) where T : new()
{
return JsonConvert.DeserializeObject<dynamic>(response.Content);
}
}
}
Usage:
// Override default RestSharp JSON deserializer
client = new RestClient();
client.AddHandler("application/json", new DynamicJsonDeserializer());
var response = client.Execute<dynamic>(new RestRequest("http://dummy/users/42"));
// Data returned as dynamic object!
dynamic user = response.Data.User;
A simpler alternative is to use Flurl.Http (disclaimer: I'm the author), an HTTP client lib that deserializes to dynamic by default when generic arguments are not provided:
dynamic d = await "http://api.foo.com".GetJsonAsync();
In both cases, the actual deserialization is performed by Json.NET. With RestSharp you'll need to add the package to your project (though there's a good chance you have it already); Flurl.Http has a dependency on it.