I have an issue that I've been trying to solve. I'm trying to send data from a java application to a web server, but I can't figure out how to actually send it. The java code is as follows:
String hStr = "{\"id\":2,\"name\":\"John\",\"height\":36.72342538,\"width\":2.99999998,\"frequency\":871.07,\\"idList\":[],\"level\":0.0}";
House ap = toJsonMap.readValue(hStr, House.class);
when: "ask the server to add a house from the request"
def response = server.httpClient.requestSpec { spec ->
spec.body { b ->
b.text(hStr)
b.type("application/json")
}
}
.post("//modeling/housing/{hid}/prop/point/in");
I then have the C# read this code like this:
[Route("modeling/housing/{hid}/prop/point/in")]
[HttpPost]
public HttpResponseMessage AddPoint(int hid, int id, string name, double height, double width, double frequency, List<int> idList, double level)
{
DAL.House h = new DAL.House();
try
{
using (DAL.Entities context = DAL.Entities.CreateContextForComplex(said))
{
if (!context.Houses.Where(a => a.Id == id).Any())
{
h.Name = name;
h.Height = height;
h.Width = width;
h.Frequency = frequency;
h.IdList= idList;
h.Level = level;
h.LastModified = System.DateTime.UtcNow;
context.Houses.Add(ap);
context.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK, ap);
}
else
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, "Housing id already exists");
}
}
}
catch (EntityException)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, "Entity Exception");
}
catch (Exception ex)
{
return Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
}
}
I just can't figure out how to get the data from this post. Particularly getting all of the different types of variables. I found a lot of different answers, but nothing seems to work.
Most likely you need to create a class that has properties matching the incoming request post body's object properties. For example:
public class House
{
public int Hid { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public double Height { get; set; }
public double Width { get; set; }
public double Frequency { get; set; }
public List<int> IdList { get; set; }
public double Level { get; set; }
}
Then you would update your method signature as follows:
public HttpResponseMessage AddPoint(House house)
Try to create a class that represents all the properties in the JSON Object:
public class YouClass
{
public int Id { get; set; }
public string Name { get; set; }
public string Height { get; set; }
......
// add others
}
Then in your controller:
public class HousingController : ApiController
{
[Route("AddPoint")
[HttpPost]
public HttpResponseMessage AddPoint([FromBody] YourClass)
{
}
}
Then modify the URL of API your are calling:
.post("api/Housing/Addpoint")
Your URL might be different, you might use : http://localhost:Port/api/Housing/Addpoint and the port. Make sure you try it in browser first or use Postman. Check this
.post("//modeling/housing/{hid}/prop/point/in");
This line of code should give you a timeout in your java, if this is exactly how you have it typed. What you really want here is something more like:
.post("http://localhost:PortNumber/modeling/housing/"+ ap.id +"/prop/point/in");
Where PortNumber is the port your web api is running on, and ap.Id is the Id of the record you are trying to modify.
After you have corrected your endpoint situation, then move on to the other answers and use JSON.Net to deserialize your JSON back into a class.
Related
I'm developing an api in net core.
I've done a post function in which I send an object containing multiple parameters and a list within another list.
When I'm debugging the code the function is called correctly but I find that the second list always arrives null.
The rest of the data arrives at you correctly. I have done different tests with other objects and everything works correctly.
It is this case in which the list within another the second one arrives null.
My code:
example request input
{
"Name": "TestName",
"Related1":
[{
"id1": "TestNameRelated1",
"Related2":
[{
"id2": "TestNameRelated2"
}]
}]
}
[HttpPost]
public resultExample Test([FromBody]TestClass test)
{
//do something
}
[DataContract]
public class TestClass
{
[DataMember]
public string Name { get; set; }
[DataMember]
public List<TestClassArray> Related1 { get; set; }
}
[DataContract]
public class TestClassArray
{
[DataMember]
public string id1 { get; set; }
[DataMember]
public List<TestClassArray2> Related2 { get; set; }
}
[DataContract]
public class TestClassArray2
{
[DataMember]
public string id2 { get; set; }
}
This api was previously made in .NET framework 4.8 and this case worked correctly.
Now I'm passing the api to .Net5.
Could it be that in .Net5 it is not allowed to pass lists within other lists?
Do you have to enable some kind of configuration to be able to do this now?
You need use class/DTO with constructor like shown below and you should be good to go. I have uploaded this sample API app's code working with .net5.0 on my GitHub here.
public class TestClass
{
public TestClass()
{
Related1 = new List<TestClassArray>();
}
public string Name { get; set; }
public List<TestClassArray> Related1 { get; set; }
}
public class TestClassArray
{
public TestClassArray()
{
Related2 = new List<TestClassArray2>();
}
public string id1 { get; set; }
public List<TestClassArray2> Related2 { get; set; }
}
public class TestClassArray2
{
public string id2 { get; set; }
}
public class ResultExample
{
public string StatusCode { get; set; }
public string Message { get; set; }
}
Controller Post Method
[HttpPost]
[ProducesResponseType(typeof(ResultExample), 200)]
public ResultExample Post([FromBody] TestClass test)
{
ResultExample testResult = new ResultExample();
TestClass test2 = new TestClass();
TestClassArray testClassArray = new TestClassArray();
TestClassArray2 testClassArray2 = new TestClassArray2();
test2.Name = test.Name;
foreach (var item in test.Related1)
{
foreach (var item2 in item.Related2)
{
testClassArray2.id2 = item2.id2;
}
testClassArray.Related2.Add(testClassArray2);
}
test2.Related1.Add(testClassArray);
Console.WriteLine(test2);
testResult.Message = "New Result added successfullly....";
testResult.StatusCode = "201";
return testResult;
}
Swagger Input Sample Payload
Post Controller Result
Response of Sample input payload,(You can change it to default 201 response code as well)
I had a similar issue.
API method shows List was null
In my case a date field was not well formatted
So I use SimpleDateFormat on Android Studio with a correct datetime format
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss",Locale.US);
item.setDate(dateFormat.format(calendar.getTime()));
and works fine
[HttpGet("/api/notes/suggested")]
public JsonResult GetSuggestedNotes(string searchText)
{
//TODO: Podpowiedzi przy wpisywaniu tytułu
JsonResult result = null;
try {
List<Note> n = db.Notes.Include(x => x.NoteTags).ToList();
result = Json(n);
}
catch(Exception e)
{
Console.WriteLine(e);
}
return result;
}
public class Note
{
public Note()
{
CreationDate = DateTime.Now;
NoteTags = new HashSet<NoteTag>();
Parts = new HashSet<Part>();
}
public int ID { get; set; }
public virtual ICollection<NoteTag> NoteTags { get; set; }
public virtual ICollection<Part> Parts { get; set; }
public DateTime? CreationDate { get; set; }
[NotMapped]
public string TagsToAdd { get; set; }
[NotMapped]
public string TagsAsSingleString {
get
{
string result = "";
foreach(var nt in NoteTags)
{
result += nt.Tag.Name + " ";
}
return result;
}
}
}
public class NoteTag
{
public int NoteId { get; set; }
public virtual Note Note { get; set; }
public int TagId { get; set; }
public virtual Tag Tag { get; set; }
}
When I try to get data using this WebAPI controller, I get 502 bad gateway. No errors, everything's fine while debugging server. Data get from database correctly.
I suspect that it could be something similar to "infinite loop" but how to prevent it? (Note class is connected to collection of NoteTag objects that are connected back to Note which probably makes this loop).
And why there are no errors if something went wrong? :/
I don't know if it still relevant but i had the same problem and what worked for me it to Configure Newtonsoft.Json
SerializerSettings.ReferenceLoopHandling = ewtonsoft.Json.ReferenceLoopHandling.Ignore.
If you are using VS2015 MVC you can add the following code:
services.AddMvc().AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
in the ConfigureServices method in the Startup class.
I think the problem its recursion, can you try with an Anonymous type
NoteTags has Note , imagine if the Note->NoteTags->Note->NoteTags->Note->NoteTags ...
`List n = db.Notes.Include(x => x.NoteTags).ToList();
var e = n.select(x=> new {property=value});
result = Json(e);`
I have been struggling with my first c# project. This is a web api controller that will receive a post from AngularJS. The post is coming across but appears to have an extra set of brackets in the JSON object (right click/copy value in vs 2015) . I have tried various methods but everytime I deserialize the JSON object I get null values.
public class LocationsTestController : ApiController
{
[System.Web.Http.HttpPost]
[Route("")]
public IHttpActionResult Post(object json)
{
string sjson = json.ToString();
Coords oCoords = JsonConvert.DeserializeObject<Coords>(sjson);
DBEntities db = new DBEntities();
db.spUpdateLocation(User.Identity.Name, oCoords.latitude.ToString(), oCoords.longitude.ToString());
db.SaveChanges();
return Ok(oCoords.latitude); //return trash data for now
}
}
Here is my JSON copied from the the object received by the post.
{{
"coords": {
"latitude": 43.445969749565833,
"longitude": -80.484091512936885,
"altitude": 100,
"accuracy": 150,
"altitudeAccuracy": 80,
"heading": 38,
"speed": 25
},
"timestamp": 1442113213418
}}
I have tried mapping to the entity framework, but problem is I need to add the authenticated username to the json object as I don't want to trust what is being passed to the API.
Any help would be much appreciated.
Try to receive a model instead of plain string in your WebApi method:
public class CoordsItemModel
{
public double latitude { get; set; }
public double longitude { get; set; }
public int altitude { get; set; }
public int accuracy { get; set; }
public int altitudeAccuracy { get; set; }
public int heading { get; set; }
public int speed { get; set; }
}
public class CoordsModel
{
public CoordsItemModel coords { get; set; }
public long timestamp { get; set; }
}
[System.Web.Http.HttpPost]
[Route("")]
public IHttpActionResult Post(CoordsModel model)
{
DBEntities db = new DBEntities();
db.spUpdateLocation(User.Identity.Name, model.coords.latitude.ToString(), model.coords.longitude.ToString());
db.SaveChanges();
return Ok(model.coords.latitude.ToString()); //return trash data for now
}
There might be some issues with the way you are posting from client side. It's hard to check without the client code and what exactly is coming over network (in fiddler for example).
Generally the web api should be able to get the object directly without you deserializing it. So, if the client is posting proper json, this should work
public IHttpActionResult Post(Coords oCoords)
{
//use oCoords directly
}
If that doesn't work, try changing your web api method to receive string rather than an object, and deserialize that string.
public IHttpActionResult Post(string jsonString)
{
Coords oCoords = JsonConvert.DeserializeObject<Coords>(jsonString);
//rest of the code
}
If you still have double braces, you can do this before you deserialize
jsonString = jsonString.Replace("{{", "{").Replace("}}", "}");
But, obviously, this is not the correct fix. The issue still remains somewhere.
Use It.
public class coordsSample
{
public string latitude { get; set; }
public string longitude { get; set; }
public int altitude { get; set; }
public int accuracy { get; set; }
public int altitudeAccuracy { get; set; }
public int heading { get; set; }
public int speed { get; set; }
}
public class coords1
{
public coordsSample coords { get; set; }
public long timestamp { get; set; }
}
static void Main(string[] args)
{
var jsonFormat = #"[{""timestamp"":""1442113213418"",""coords"":{
""latitude"":""43.445969749565833"",""longitude"":""-80.484091512936885"",""altitude"":""100"",""accuracy"":""150""
,""altitudeAccuracy"":""80"",""heading"":""38"",""speed"":""25""}}]";
var result = JsonConvert.DeserializeObject<coords1>(jsonFormat.Substring(1).Substring(0, jsonFormat.Length - 2));
Console.WriteLine(result.coords.latitude);
Console.WriteLine(result.coords.longitude);
}
Try Like that it will help for you.because those coords you take in json it trated as a properties so for that you need to create a new class and assign this properties in inside it.Thanks
When I create a new record in my table I would like generate an json response with only the primary ID of my new record, somethink like : {"PrimaryID":123}
I actually use this handmade function:
// Inserts a new row into the PatientSession table
public string AddPatientSession(PatientSession p)
{
int id = (int)_dbConnection.Insert<PatientSession>(p, selectIdentity: true);
string Idconvert = id.ToString();
string IdInsert = "{\"PatientSessionId\":" + Idconvert + "}";
return IdInsert;
}
But I assume it's not the best way to do it, have you a suggestion please?
Thanks in advance
If you just want to return a small JSON payload with just an Id you can use a type with only the fields you want to return, e.g:
public class AddPatientSession : IReturn<PatientId> { ... }
public class PatientId {
public int PatientSessionId { get; set; }
}
Then use in your service like:
public class MyServices : Service
{
public object Any(AddPatientSession request)
{
var model = request.ConvertTo<PatientSession>();
return new PatientId {
PatientSessionId = Db.Insert(model, selectIdentity: true);
}
}
}
Returning an object takes advantage of ServiceStack's built-in Content Negotiation to return the object serialized in the preferred Content-Type, e.g. JSON for JSON/ajax clients.
You can also return an anonymous type containing just the Id:
public object Any(AddPatientSession request)
{
var model = request.ConvertTo<PatientSession>();
return new {
PatientSessionId = Db.Insert(model, selectIdentity: true);
}
}
Which will also serialize to JSON when requested, but the lack of a type does prevent this from being called with ServiceStack's generic typed Service Clients.
Thanks you so much #mythz it's working well I just use a convert function to int because "Db.Insert" return a long type.
// Add PatientSession via POST
public class PatientSessionADD : IReturn<PatientSessionResponseId>
{
public int PatientSessionId { get; set; }
public int ByPatientId { get; set; }
public DateTime PatientStartSessionTime { get; set; }
public int PatientStartSessionByUserId { get; set; }
public DateTime PatientEndSessionTime { get; set; }
public int PatientEndSessionByUserId { get; set; }
}
public class PatientSessionResponseId
{
public int PatientSessionId { get; set; }
}
public object Post(PatientSessionADD request)
{
var p =new PatientSession()
{
ByPatientId = request.ByPatientId,
PatientStartSessionTime = request.PatientStartSessionTime,
PatientStartSessionByUserId = request.PatientStartSessionByUserId
};
return new PatientSessionResponseId
{
PatientSessionID = Convert.ToInt16( Db.Insert<PatientSession>(p, selectIdentity: true) )
};
}
To resume this function get a HTTP POST message, store it in database and return a JSON response with only the Primary ID generated.
Have fun and thanks again mythz
I have this issue where I'm sending a request for a JSON Feed. The issue is that the feed has a dynamic header (i.e. when I send a request for "testinput1" the header response will be testinput1.
Therefore I need to make my RootObject dynamic, but I'm not sure how, could you please help me?
I've entered the troublesome part of the code below
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
textBlock1.Text = "Details Loaded.";
short_description.Text = feed.testinput1.short_description; // can I make testinput1 a constant? its based on code below
});
public class Event
{
public string description { get; set; }
public string datetime { get; set; }
}
public class TrackCode
{
public string short_description { get; set; }
public List<Event> events { get; set; }
}
public class RootObject
{
public string tracker;
public TrackCode testinput1// This needs to be based on user input each time
{
get; // Can I do something here to make sure that the "testinput1" changes each time?
set; // And create a constant that can be referred to?
}
}
Hopefully I can do something like this:
short_description.Text = feed.trackcode.short_description; // this is a constant
public class RootObject
{
public string tracker = "AB123456789NZ"; // This is the variable that changes
public TrackCode trackcode // this becomes a constant
{
get { return tracker; } // uses tracking number as value for JSON when it retrieves it
set { tracker = value;}
}
}
Where have I gone wrong? Thankyou!