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);
Related
First, I am not sure if my question reflects my needs, please let me know if that needs to be changed.
What I am doing here is creating functions in DLL application to be called from DotNET outside c#. The issue with my function now is the Model class. Where I am going to use this DLL, I cannot see/use my model class from the outside, therefore how do I change my code to use a string instead of Product model? I still need to send my request as JSON though.
I am working with JSON
I have the following 2 classes:
In Class 1 (SetupWebAPIAsync): Function that puts a product (Model)
public static async Task<ApiResponse> PutProductAsync(string endpoint, Product p)
{
StringContent httpContent = new StringContent(JsonConvert.SerializeObject(p), Encoding.UTF8, "application/json");
string result = "";
HttpResponseMessage response = await client.PutAsync(endpoint, httpContent);
response.EnsureSuccessStatusCode();
result = await response.Content.ReadAsStringAsync();
return new ApiResponse(response.StatusCode, result);
}
In Class 2:
public static ApiResponse PutIn(string user, string password, string endpoint , Product Httpcontent)
{
User = user;
Password = password;
Endpoint = endpoint;
Content = Httpcontent;
ExecutePUTRequest().Wait();
return apiResponse;
}
private static async Task ExecutePUTRequest()
{
SetupWebAPIAsync.SetAPIAuthentication(User, Password);
apiResponse = await SetupWebAPIAsync.PutProductAsync(Endpoint,Content);
}
My Model Class:
public class Product
{
public string id { get; set; }
public string name { get; set; }
public bool inactive { get; set; }
}
ex:
{
"id" : "12",
"name" : "test",
"inactive": false,
}
Now this is how I call my function and it works this way BUT I need to replace product by a string I pass in from my test outside Dll.
Product product = new Product { name = "API_Testing" };
PutIn("user", "pass", "https://localhost/api/product", product);
Well you can't cause your PutIn() method expects an Product Httpcontent as method parameter. instead take a stringified product as JSON and convert that to product and call the main method like
public static ApiResponse PutIn(string user, string password,
string endpoint , string Httpcontent)
{
User = user;
Password = password;
Endpoint = endpoint;
Content = NewtonSoft.Json.JsonConvert.DeserializeObject<Product>(Httpcontent);
ExecutePUTRequest().Wait();
return apiResponse;
}
You can then call it like
string product = "{id : 12,name : API_Testing,inactive: false,}"
PutIn("user", "pass", "https://localhost/api/product", product);
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.
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.
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;
}
I have this API url: https://faucetbox.com/api/v1/send
With this API data: amount=1&to=xxx&api_key=yyy
And I got this C# code:
string JSON_WRITER(string url,string JSON)
{
string result="";
using (var client = new WebClient())
{
result = client.UploadString(url, "POST", JSON);
}
return result;
}
Which is called like this:
JSON_WRITER("https://faucetbox.com/api/v1/send", "amount=1& to=DSfPc8GkRGF3Xrp99gHQFFJ7hcFJCqkwYH&api_key=4VdBEIAQKPpZ4SWOhQLUMn7mMNVql")
However it doesn't work, and it gives the following error:
{"status":414,"message":"Missing or invalid parameters."}
Can somebody correct the syntax error, if there is any, i`m not that experienced with JSON, or please help me resolve the problem, thanks!
(Don't worry about the API key though, it doesn't reveal private information)
EDIT: Adding JSON serialization for constructing JSON.
public class Data
{
public decimal Amount { get; set; }
public string Api_Key { get; set; }
public string To { get; set; }
}
Serialization code:
string json = JsonConvert.SerializeObject(new Data { Amount = 1M, Api_Key = "Some key", To = "some destination" });
Add a content type header as below.
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
JSON Payload:
{"amount":1,"to":"DSfPc8GkRGF3Xrp99gHQFFJ7hcFJCqkwYH","api_key":"4VdBEIAQKPpZ4SWOhQLUMn7mMNVql"}
JSON Specification can be found below.
http://json.org/