Can RestSharp send a List<string> in a POST request? - json

I am trying to get RestSharp to work with a restful service that I have. Everything seems to be working fine, except when my object being passed via POST contains a list (in this particular case a list of string).
My object:
public class TestObj
{
public string Name{get;set;}
public List<string> Children{get;set;}
}
When this gets sent to the server the Children property gets sent as a string with the contents System.Collections.Generic.List`1[System.String].
This is how I am sending the object:
var client = new RestClient();
var request = new RestRequest("http://localhost", Method.PUT);
var test = new TestObj {Name = "Fred", Children = new List<string> {"Arthur", "Betty"}};
request.AddObject(test);
client.Execute<TestObj>(request);
Am I doing something wrong, or is this a bug in RestSharp? (If it makes a difference, I am using JSON, not XML.)

It depends on what server you're hitting, but if you're hitting an ASP.NET Web API controller (and probably other server-side technologies), it'll work if you add each item in the collection in a loop:
foreach (var child in test.Children)
request.AddParameter("children", x));

Use AddJsonBody
var client = new RestClient();
var request = new RestRequest("http://localhost", Method.PUT);
request.AddJsonBody(new TestObj {
Name = "Fred",
Children = new List<string> {"Arthur", "Betty"}
});
client.Execute(request);
Api Side
[AcceptVerbs("PUT")]
string Portefeuille(TestObj obj)
{
return String.Format("Sup' {0}, you have {1} nice children",
obj.Name, obj.Children.Count());
}

I had a similar problem with a list of Guids. My post would work but the list would never have the correct data. I hacked it abit and used the json.net to serialize the object
Issue I had on another stackoverflow post
I know this isn't perfect but does the trick

Related

get request.Body param value .net core 2

I'm receiving a json object as request body content, like:
{
"reportID": "C4239"
}
When i try to get the value of "reportID" it doesn't seem to be a method like request.Body.value or something. How could i get the param's value of this json object?.
Unfortunately ASP.NET Core doesn't let you just capture 'raw' data in any meaningful way just by way of method parameters.
One way or another you need to do some custom processing of the Request.Body to get the raw data out and then deserialize it.
You can use below code to process the Request Body:-
public async Task<IActionResult> SomeAction()
{
using (var reader = new StreamReader(Request.Body))
{
var body = reader.ReadToEnd();
YourDataModel reqObj = JsonConvert.DeserializeObject<YourDataModel>(body);
var objId = reqObj.reportId;
}
// Do some work
}
You can get the details on below link:-
https://weblog.west-wind.com/posts/2017/Sep/14/Accepting-Raw-Request-Body-Content-in-ASPNET-Core-API-Controllers
public class desResponse
{
public string reportId;
}
desResponse reqObj = JsonConvert.DeserializeObject<desResponse>(request.Body);
var objId = reqObj.reportId.ToString();

How to send serializable request object with httpClient in .net core?

I'm new in .net and I'm looking for a way (if exists) to be able to pass a request object to a http client without "manually" serialize it to json. I did some java implementations in the past and there it was done under the hood and I thought that it should be possible also in .netCore
This is the request object:
public class Request
{
[JsonProperty("number", NullValueHandling = NullValueHandling.Ignore)]
public int Number { get; set; }
}
and I'm looking for something like:
var request = new Request {Number=2};
client.PostAsync("url", request)
I found a similar implementation, but that does not seems to be .netcore compatible:
https://www.nuget.org/packages/Microsoft.AspNet.WebApi.Client/5.2.4-preview1
Is there anything similar for .netcore?
Thanks
You will still need to serialize the object to a JSON string.
The referenced Microsoft.AspNet.WebApi.Client library in question would have the PostAsJsonAsync extension method along with many others for extending HttpClient.
Which internally may have looked like this.
public static Task<HttpResponseMessage> PostAsJsonAsync<T>(this HttpClient client, string requestUri, T obj) {
var json = JsonConvert.SerializeObject(obj);
var content = new StringContent(json, Encoding.UTF8, "application/json");
return client.PostAsync(requestUri, content);
}
and used like
using System.Net.Http;
//...
var request = new Request { Number = 2 };
var response = await client.PostAsJsonAsync("url", request);

Web Api 2 with OData v4 - Bound function returning complex object

In this simple example I am trying to get an object serialized as JSON from a Web Api 2 + OData v4 service. Controller has bound function Test which is returning an array of annon. objects.
public class ProductsController : ODataController
{
[HttpGet]
public IHttpActionResult Test(int key)
{
var res = new[]
{
new { Name = "a", Value = new[] { 1, 2, 3 } },
new { Name = "b", Value = new[] { 2, 4, 5 } }
// this also produces same result
// new { Name = "a", Value = "c" },
// new { Name = "b", Value = "c" }
};
return this.Ok(res);
}
}
Edm is built with this piece of code:
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Product>("Products");
var productType = builder.EntityType<Product>();
var f = productType.Function("Test").Returns<object>();
when I make a request to the service (eg. http://localhost:9010/odata/Products(33)/Default.Test) I am getting a strange response - an array of two empty objects, like this:
{
"#odata.context": "http://localhost:9010/odata/$metadata#Collection(System.Object)",
"value": [
{},
{}
]
}
In my real app I'm returning object serialized to a JSON string with Newtonsoft's Json converter - that works fine, but this problem is still bothering me. I suspect it is something related to OData's default serializer, but it is unclear to me how to configure it.
So, is it possible to configure edm function's return parameter in such way where I would get correctly serialized complex object?
Thanks!
As lukkea said, OData is not designed to work with anonymous types.
Side note, in you WebApiConfig you should change "Returns" to "ReturnsCollection" if you are returning a collection.
Anyway, let's assume you wrote the following.
return this.Ok(Newtonsoft.Json.JsonConvert.SerializeObject(res));
var f = productType.Function("Test").Returns<string>();
You would get back the following:
{
"#odata.context": "http://localhost/Test/odata/$metadata#Edm.String",
"value":
"[
{\"Name\":\"a\",\"Value\":[1,2,3]},
{\"Name\":\"b\",\"Value\":[2,4,5]}
]"
}
Note that there is still 2 items in the array but this time they are not empty.
Since OData did not know the return type in your previous example, it return 2 objects without values.
You have 2 options.
Return back the anonymous type as a serialized json string and then deserialize that json on the client side.
Create a class and return that type.
Option 1
// ON SERVER
return this.Ok(Newtonsoft.Json.JsonConvert.SerializeObject(res));
var f = productType.Function("Test").Returns<string>();
// ON CLIENT
string jsonString = odataContext.Products.ByKey(33).Test().GetValue();
var objectList = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(jsonString);
string firstObjectName = objectList[0].Name;
Option 2
// ON SERVER
public class TestObject
{
public string Name { get; set; }
public List<int> Integers { get; set; }
}
var res = new List<TestObject>
{
new TestObject { Name = "a", Integers = new List<int> { 1, 2, 3 } },
new TestObject { Name = "b", Integers = new List<int> { 2, 4, 5 } }
};
return this.Ok(res);
var f = productType.Function("Test").ReturnsCollection<TestObject>();
If you want to return a person with an extra property that is not strongly typed then you want ODataOpenType
Whilst it is true that working with dynamic responses is tricky, it's not that hard and you certainly do not need to resort to returning your objects through string encoding.
The key is that a dynamic response means that we can't use the standard EnableQueryAttribute to apply specific projections or filtering on the method response, and we can't return OkNegotiatedContentResult as this response object is designed to enable the runtime to manipulate how the response object is serialized into the HTTP response.
ApiController.Ok(T content);
Creates an System.Web.Http.Results.OkNegotiatedContentResult with the specified values.
content: The content value to negotiate and format in the entity body.
Content Negotiation
Content Negotiation is basically a mechansim to encapsulate the process to determine how your method response should be transmitted over http as well as the heavy lifting to physically encode the response.
By using Content Negotiation, your method only needs to return a query or raw c# object, even if the caller specified in the request that the output should be XML (instead of the standard JSON). The concept of dealing with the physical serialization and the logic to interpret the caller's intent is abstracted away so you do not need to worry about it at all.
There are 2 options that are available to you to customise the output:
ApiController.JsonResult(T content);
This allows you to specify the object graph to serialise, this will not respond to EnableQueryAttribute or Content Negotiation.
return this.JsonResult(res);
This response is not in the usual OData Response wrapper so it does not include the standard #odata attributes like #odata.context.
If your response object does not match the type specified in the Action/Function defintion in the OData Model, calls to this endpoint will result in a But if the response object does not match the type specified in the OData Model this will result in a HTTP 406 Not Acceptable, so make sure you register the response an an object or another type of interface that your response object inherits from or implements.
HttpResponseMessage
Bypass OData response management all together and return HttpResponseMessage directly from your method. In this way you are responsible for serializing the response content as well as the response headers.
This however bypasses all the OData mechanisms including response validation and formatting, meaning you can return whatever you want.
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(res))
};
result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
return result;

Dynamically switch applicable DataContract at runtime?

Can I turn data contract attributes off and on dynamically? Essentially, I'd like two data contracts, one between the 3rd party and my app, and one between my app and my client - without having to manage two DTO classes. For example, consider MyDTO:
[DataContract]
public class MyDTO
{
[DataMember(Name = "Lame/3rdParty/Inbound/Key")]
public string MyCoolOutboundKey { get; set; }
}
I'd like to deserialize the DTO with ServiceStack.Text:
MyDTO dto = "{\"Lame/3rdParty/Inbound/Key\":\"CoolValue\"}".FromJson<MyDTO>();
But, I'd like to serialize it so that this Assertion would be true:
Assert.AreEqual("{\"MyCoolOutboundKey\":\"CoolValue\"}",dto.ToJson());
The actual object in question has over hundred properties, so I'm hoping to avoid having to create a second class just to allow for outbound serialization.
So, there is nothing wrong with your approach, but I think you are underestimating the power of JsonObject, it's kinda like LINQ to JSON.
I used it to get geo data from Google Maps and map it to a nice little DTO:
var jsonObj = jsonFromGoogleMaps.FromJson<JsonObject>();
return (
from x in jsonObject.Get<JsonArrayObjects>("results")
let geo = x.Get("geometry")
let loc = geo.Get("location")
return new Coords
{
Lat = x.Get<decimal>("lat"),
Lng = x.Get<decimal>("lng"),
}
).FirstOrDefault();
OK - it's pretty well established that you cannot change attributes at runtime.
An alternative that would create an end-run around the entire issue, would be to pre-process the incoming json, replacing the keys according to a map, i.e.:
Dictionary<String,String> map = new Dictionary<String,String>();
map.Add("Lame/3rdParty/Inbound/Key","MyCoolOutboundKey");
JsonObject result = new JsonObject();
JsonObject obj = jsonObject.Parse("{\"Lame/3rdParty/Inbound/Key\":\"CoolValue\"}");
foreach (var entry in obj)
{
entry.Key = map[entry.Key];
result[entry.Key] = entry.Value;
}
Assert.AreEqual("{\"MyCoolOutboundKey\":\"CoolValue\"}",result.ToJson());
This way the only data contract I'd require would be the one between my app and my app's clients.

Returning and displaying a JSON Object which is an associate array in a Windows 8 App

I am using a online tutorial to lean how to create a web service, generate a JSON object, send it back to my Win 8 App and display it. The web service is working however I am struggling to return a value to the APP. My code in the app is:
WinJS.xhr({
url: 'http://localhost/filmgloss/web-service.php?termID=1&format=JSON'
})
.done(
function complete(result) {
// terms is the key of the object
for (var terms in result) {
for (var term in terms) {
if (result.hasOwnProperty(term)) {
//here you have to acess to
var termName = result[term].termName;
var def = result[term].definition;
}
//Show Terms
testDef.innerText = definition;
}
}
},
And he code in my web service is:
if($format == 'json') {
header('Content-type: application/json');
echo json_encode(array('terms'=>$terms));
}else...
The JSON output itself looks like:
{"terms":[{"term":{ "termName":"Focus","definition":"A Focus..."}}]}
I am using a for..in but whilst I can look inside terms' I can't work out how to look interm`
I usually build my own data structure that represents the JSON structure.
In your case it would be something like this:
public class TermsList
{
public List<Term> terms { get; set; }
}
public class Term
{
public string termName { get; set }
public definition termName { get; set }
...
}
Then you can just deserialize your string into your object. There are different ways to do this. I would use Json.Net.
Here is one way:
Parse JSON in C#
public static T Deserialise<T>(string json)
{
T obj = Activator.CreateInstance<T>();
using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(obj.GetType());
obj = (T)serializer.ReadObject(ms); // <== Your missing line
return obj;
}
}
If you wanna keep it dynamic, that should work too:
http://www.drowningintechnicaldebt.com/ShawnWeisfeld/archive/2010/08/22/using-c-4.0-and-dynamic-to-parse-json.aspx
I have managed to resolve my issue with the help of a developer friend. My problem was that I had not realised that the result of WinHS.xhr was not already a JSON Array. Although my web-service outputs a JSON Array when it is consumed through WinHS.xhr it appears to be returned as an XMLHttpRequest object.
The solution was therefore to process the result using:
JSON.parse(result.responseText)
I could then use a For...In loop as expected:
for (terms in responseTerms) {
//terms will find key "terms"
var termName = responseTerms.terms[0].term.termName;
var termdefinition = responseTerms.terms[0].term.definition;
testTerm.innerText = termName;
testDef.innerText = termdefinition;
}
Thanks for everyone that commented, hopefully this may help others in the future if they're starting out with Win 8 app development.