RestSharp POST Object as JSON - c#

Here is my class:
public class PTList
{
private String name;
public PTList() { }
public PTList(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
}
and my RestSharp POST Request:
protected static IRestResponse httpPost(String Uri, Object Data)
{
var client = new RestClient(baseURL);
client.AddDefaultHeader("X-Authentication", AuthenticationManager.getAuthentication());
client.AddDefaultHeader("Content-type", "application/json");
var request = new RestRequest(Uri, Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(Data);
var response = client.Execute(request);
return response;
}
and when I use the httpPost method with the good URI and a PTList object, the front API anwser that "name" is null.
I think that my PTList object is not serialized as a valid JSON in the request for the API, but can't understand what's going wrong.

There are a couple of issues I can see.
The first is that the object you're sending has no public fields, I'd also simplify the definition a little too:
public class PTList
{
public PTList() { get; set; }
}
The second issue is that you're setting the Content-Type header which RestSharp will do by setting request.RequestFormat = DataFormat.Json
I'd also be tempted to use generics rather than an Object
Your httpPost method would then become:
protected static IRestResponse httpPost<TBody>(String Uri, TBody Data)
where TBody : class, new
{
var client = new RestClient(baseURL);
client.AddDefaultHeader("X-Authentication", AuthenticationManager.getAuthentication());
var request = new RestRequest(Uri, Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(Data);
var response = client.Execute(request);
return response;
}

You could try this instead of AddJsonBody:
request.AddParameter("application/json; charset=utf-8", JsonConvert.SerializeObject(Data), ParameterType.RequestBody);
It's one of the solutions here: How to add json to RestSharp POST request

Json serializer used by RestSharp by default does not serialize private fields. So you can change your class like this:
public class PTList
{
public PTList() { }
public PTList(String name) {
this.name = name;
}
public string name { get; set; }
}
And it will work fine.
If capabilities of default serializer will be not enough (as far as I know - you cannot even rename properties with it, to make Name serialize as name for example) - you can use better serializer, like JSON.NET, like described here for example.

Related

WebApi HttpPost not receiving the posted content from HttpClient

Web API:
I tried using [FormBody] and [FromForm] before the string stringcontent as well.
// POST api/<MAUserController>
[HttpPost("AuthenticateUser")]
public async Task<ActionResult<MAUser>> PostAsync(string stringcontent)
{
//stringcontent is null
}
Client Code:
List<KeyValuePair<string, string>> postParameters = new List<KeyValuePair<string, string>>();
postParameters.Add(new KeyValuePair<string, string>("Email", Email));
postParameters.Add(new KeyValuePair<string, string>("Password", Password));
var jsonString = JsonConvert.SerializeObject(postParameters);
var stringContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", tokenString);
//httpClient.DefaultRequestHeaders.Add("Email", Email);
//httpClient.DefaultRequestHeaders.Add("Password", Password);
using (var response = await httpClient.PostAsync(API_URL, stringContent))
{
if (response.IsSuccessStatusCode)
{
//Success code
}
else
{
//Handle unsuccessful here
}
}
You're posting structured data in JSON format from the client. So why is the API just trying to accept a plain string? That doesn't make a lot of sense.
You should make it accept a model object with the correct structure, instead. ASP.NET will take care of binding the JSON properties to the model properties. However, you should also simplify the postParameters in the client as well - you're over-complicating the structure.
e.g.
Client:
var postParameters = new { Email = "abc#example.com", Password = "xyz" };
Server:
public async Task<ActionResult<MAUser>> PostAsync([FromBody] UserCredentials credentials)
{
}
where UserCredentials is a DTO class like this:
public class UserCredentials
{
public string Email { get; set; }
public string Password { get; set; }
}
ok so when using content type you are basically telling the receiving API how to parse the request payload and so by telling it application/json the framework is trying to parse the payload from JSON to an object and assign it to your parameter ( not really since you need to add an attribute [FromBody] ) but it can not do it since you are expecting a string, so either change your content type or change your parameter type ( i would suggest your parameter type ) .

Why do I get "not_authed"-error from Slack when sending a post-request from c#?

I am trying to serialize an object into Json and then send it to Slack. I have done this successfully without serializing but instead using "Dictionary" and "FormUrlEncodedContent" and then send it.
But now, for the purpose of making things easier and more agile, I just wanted to create one JSon-class which I could serialize and then use for every request I want to send.
Here is my code:
My JsonObject:
public class JsonObject
{
private string _token = "xoxp-MyToken";
[JsonProperty("token")]
public string token { get { return _token; } }
[JsonProperty("channel")]
public string channel { get; set; }
[JsonProperty("as_user")]
public bool as_user = true;
[JsonProperty("username")]
public string username { get;set; }
[JsonProperty("text")]
public string text { get; set; }
}
My client:
public class BpsHttpClient
{
private readonly HttpClient _httpClient = new HttpClient { };
public Uri UriMethod { get; set; }
public BpsHttpClient(string webhookUrl)
{
UriMethod = new Uri(webhookUrl);
}
public async Task<HttpResponseMessage> UploadFileAsync(StringContent requestContent)
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, UriMethod);
request.Content = requestContent;
var response = await _httpClient.SendAsync(request);
return response;
}
}
Main:
class MainArea
{
public static void Main( string[] args)
{
try
{
Task.WaitAll(SendMessage());
}
catch(Exception ass)
{
Console.WriteLine(ass);
Console.ReadKey();
}
}
private static async Task SendMessage()
{
var client = new BpsHttpClient("https://slack.com/api/chat.postMessage");
JsonObject JO = new JsonObject();
JO.channel = "DCW21NBHD";
JO.text = "This is so much fun :D !";
var Json = JsonConvert.SerializeObject(JO, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
var StringJson = new StringContent(Json, Encoding.UTF8, "application/json");
var DeSon = JsonConvert.DeserializeObject(Json);
Console.WriteLine(DeSon); //this is for me to see if my JsonObject looks correct - it does ;)
Console.ReadKey();
var Response = await client.UploadFileAsync(StringJson);
string AnswerContent = await Response.Content.ReadAsStringAsync();
Console.WriteLine(AnswerContent);
Console.ReadKey();
}
}
When I run the code I allways get the answer:
Output:
{"ok":false,"error":"not_authed"}
although I think my JsonObject looks right - it has the token in there...
Anybody have an idea why?
So, i figured it out - I SHALL NOT put my token in the JsonObject I want to send.
The solution in this case (using httpclient) is that one has to add a header for authorization to the client, like so:
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "lé token");
and then it works.

Convert object to json using RestSharp only

I've created a small class like this one.
public class Device
{
public Device()
{
}
[DeserializeAs(Name = "u_friendly_name")]
//[SerializeAs(Name = "u_friendly_name")]
public string Name { get; set; }
}
}
In order to map "Name" to "u_friendly_name" (as it should be in json) I've added a DeserializeAs declaration. My first question here is.. do I need both DeserializeAs and SerializeAs if I want to POST/GET json or would DeserializeAs suffice?
Doing a GET like this works perfectly. It automatically manages to get the json and cast it to a device as required. However, doing a POST wasn't as simple...
public Device GetDevice(string guid)
{
var request = new RestRequest("api/now/table/x_device", Method.GET);
request.RootElement = "result";
var devices = client.Execute<List<Device>>(request);
return devices.Data.FirstOrDefault(d => d.Guid == guid);
}
I'm trying to do a POST like this.
public void RegisterDevice()
{
Device device = new Device();
device.Name = Environment.MachineName;
var request = new RestRequest("api/now/table/x_device", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddBody(device); // HERE
Console.WriteLine(request.Parameters[0]);
var response = client.Execute(request);
}
The problem is that the object isn't translated into json. Instead of having "u_friendly_name" in the json output I see "Name". I know this can be solved using Json.Net such as:
string json = JsonConvert.SerializeObject(device);
But that would also require me to add another dependency to my project and add the JsonProperty declaration to my class. I have been able to get POST working with Json.NET, but not GET and vise versa.
Anyone who can point me in the right direction of how to serialize my class using (preferably) only RestSharp?
Edit: After reading a lot of posts on stackoverflow, I get the impression that RestSharp just isn't suitable for deserialization. I found the following link that uses a custom json serializer and while POST works great, I'm not sure what I'm doing wrong with GET: http://bytefish.de/blog/restsharp_custom_json_serializer/
public Device GetDevice(string guid)
{
var request = new RestRequest("api/now/table/x_device", Method.GET);
request.RequestFormat = DataFormat.Json;
request.JsonSerializer = NewtonsoftJsonSerializer.Default;
request.RootElement = "result";
var devices = client.Execute<List<Device>>(request);
return devices.Data.FirstOrDefault(d => d.Guid == guid);
}
The only thing that works is setting both:
[JsonProperty(PropertyName = "u_friendly_name")]
[DeserializeAs(Name = "u_friendly_name")]
But that shouldn't be necessary I hope?
Edit2: I have manged to get POST to work by adding the "AddHandlers" to the RestSharp client as mentioned in the blog post above. I have also changed my class and added a "Devices" definition.
public class Devices
{
[JsonProperty(PropertyName = "result")]
public List<Device> devices { get; set; }
}
public class Device
{
public Device()
{
}
[DeserializeAs(Name = "u_friendly_name")]
//[SerializeAs(Name = "u_friendly_name")]
public string Name { get; set; }
}
}
Now my function looks like this and works as intended:
public Device GetDevice(string guid)
{
var request = new RestRequest("api/now/table/x_uia_sdm_device", Method.GET);
request.RequestFormat = DataFormat.Json;
request.JsonSerializer = NewtonsoftJsonSerializer.Default;
IRestResponse response = client.Execute(request);
var deviceList = JsonConvert.DeserializeObject<Devices>(response.Content);
return deviceList.devices.FirstOrDefault(d => d.Guid == guid);
}
Json:
{
"result": [
{
"u_guid": "12345678",
"u_friendly_name": "DeviceA",
"sys_mod_count": "1",
"sys_updated_on": "2017-03-09 11:58:50",
"sys_tags": "",
"u_config_override": "log_level_local = 5",
"u_running_version": "1.0.0",
"sys_id": "abcdefg",
"sys_created_on": "2017-03-07 12:25:06",
"u_reference_record": "",
"u_status": "Provisioned",
"sys_created_by": "foo#bar.no"
},
{
"u_guid": "34567890",
"u_friendly_name": "DeviceB",
"sys_mod_count": "0",
"sys_updated_on": "2017-03-08 13:23:06",
"sys_tags": "",
"u_config_override": "",
"u_running_version": "",
"sys_id": "abcdefg",
"u_application": "",
"u_reference_record": "",
"u_status": "",
"sys_created_by": "foo#bar.no"
}
]
}
Even though it now works my initial question still stands. If possible I would love to remove Json.Net and only use RestSharp.

Consume WCF Restful service with datacontract

I have created the following restfull web service:
Interface
[ServiceContract]
public interface ISIGService
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "GetTicket/")]
Ticket GetTicket(string user, string pwd);
}
Implementation
public class SIGService : ISIGService
{
public Ticket GetTicket(string user, string pwd)
{
return new Ticket()
{
Usuario = "xx",
UsuarioNombre = "xxx",
UsuarioId = "xxx"
};
}
Contract
[DataContract]
public class Ticket
{
[DataMember]
public int UsuarioId { get; set; }
[DataMember]
public string UsuarioNombre { get; set; }
[DataMember]
public string Usuario { get; set; }
}
I need to consume this service, from a web application, and get the typed object Ticket, I have included a service reference for this.
Server side code:
string urlService =
String.Format("http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'",
usuario, password);
var request = (HttpWebRequest)WebRequest.Create(urlService);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
I put a text variable just to get something, sort of lost here.
I don't seem to get this object, could you give some pointers on this?
Most likely, you just need to change your URL from
http://localhost:22343/SIGService.svc/GetTicket/?user='{0}'&pwd='{1}'
to using the proper REST syntax (since you're using a REST service):
http://localhost:22343/SIGService.svc/GetTicket/{user}/{pwd}
Sample:
http://localhost:22343/SIGService.svc/GetTicket/daniel/topsecret
No ? or user= or single quotes necessary ....
With this, the value from {0} will be passed into the user parameter, and the value from {1} to the pwd parameter.
For consuming the service, I would recommend you check out the excellent RestSharp library which makes using your REST service a breeze.
Your code would look something like this:
// set up the REST Client
string baseServiceUrl = "http://localhost:22343/SIGService.svc";
RestClient client = new RestClient(baseServiceUrl);
// define the request
RestRequest request = new RestRequest();
request.Method = Method.GET;
request.RequestFormat = DataFormat.Xml;
request.Resource = "GetTicket/{user}/{pwd}";
request.AddParameter("user", "daniel", ParameterType.UrlSegment);
request.AddParameter("pwd", "top$ecret", ParameterType.UrlSegment);
// make the call and have it deserialize the XML result into a Ticket object
var result = client.Execute<Ticket>(request);
if (result.StatusCode == HttpStatusCode.OK)
{
Ticket ticket = result.Data;
}

RestSharp Post a JSON Object

I am trying to post the following JSON with RestSharp:
{"UserName":"UAT1206252627",
"SecurityQuestion":{
"Id":"Q03",
"Answer":"Business",
"Hint":"The answer is Business"
},
}
I think that I am close, but I seem to be struggling with the SecurityQuestion (the API is throwing an error saying a parameter is missing, but it doesn't say which one)
This is the code I have so far:
var request = new RestRequest("api/register", Method.POST);
request.RequestFormat = DataFormat.Json;
request.AddParameter("UserName", "UAT1206252627");
SecurityQuestion securityQuestion = new SecurityQuestion("Q03");
request.AddParameter("SecurityQuestion", request.JsonSerializer.Serialize(securityQuestion));
IRestResponse response = client.Execute(request);
And my Security Question class looks like this:
public class SecurityQuestion
{
public string id {get; set;}
public string answer {get; set;}
public string hint {get; set;}
public SecurityQuestion(string id)
{
this.id = id;
answer = "Business";
hint = "The answer is Business";
}
}
Can anyone tell me what I am doing wrong? Is there any other way to post the Security Question object ?
Many thanks.
You need to specify the content-type in the header:
request.AddHeader("Content-type", "application/json");
Also AddParameter adds to POST or URL querystring based on Method
I think you need to add it to the body like this:
request.AddJsonBody(
new
{
UserName = "UAT1206252627",
SecurityQuestion = securityQuestion
}); // AddJsonBody serializes the object automatically
Thanks again for your help. To get this working I had to submit everything as a single parameter. This is the code I used in the end.
First I made a couple of classes called Request Object and Security Question:
public class SecurityQuestion
{
public string Id { get; set; }
public string Answer { get; set; }
public string Hint { get; set; }
}
public class RequestObject
{
public string UserName { get; set; }
public SecurityQuestion SecurityQuestion { get; set; }
}
Then I just added it as a single parameter, and serialized it to JSON before posting it, like so:
var yourobject = new RequestObject
{
UserName = "UAT1206252627",
SecurityQuestion = new SecurityQuestion
{
Id = "Q03",
Answer = "Business",
Hint = "The answer is Business"
},
};
var json = request.JsonSerializer.Serialize(yourobject);
request.AddParameter("application/json; charset=utf-8", json, ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
and it worked !
To post raw json body string, AddBody(), or AddJsonBody() methods will not work. Use the following instead
request.AddParameter(
"application/json",
"{ \"username\": \"johndoe\", \"password\": \"secretpassword\" }", // <- your JSON string
ParameterType.RequestBody);
It looks like the easiest way to do this is to let RestSharp handle all of the serialization. You just need to specify the RequestFormat like so. Here's what I came up with for what I'm working on. .
public List<YourReturnType> Get(RestRequest request)
{
var request = new RestRequest
{
Resource = "YourResource",
RequestFormat = DataFormat.Json,
Method = Method.POST
};
request.AddBody(new YourRequestType());
var response = Execute<List<YourReturnType>>(request);
return response.Data;
}
public T Execute<T>(RestRequest request) where T : new()
{
var client = new RestClient(_baseUrl);
var response = client.Execute<T>(request);
return response.Data;
}
RestSharp supported from object by AddObject method
request.AddObject(securityQuestion);

Categories

Resources