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
Related
I am trying to send data from winform datagridview to webapi, so i convert datagridview to json. While sending json it failed to POST data and send this error:
'Failed to POST data: (BadRequest): {"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title": "One or more validation errors occurred.","status":400,"traceId":"00-fb84f3c1c1802a481cbe7aba7ef73193-80be6fe9c57344d2-00","errors":{"$":["The JSON value could not be converted to LabDataApi.Models.LabData. Path: $ | LineNumber: 0 | BytePositionInLine: 421."]}}'
Codes:
public class LabData
{
public int SerialNumber { get; set; }
public string LabParameterName { get; set; }
public decimal LabValue { get; set; }
public DateTime LabDate { get; set; }
}
private void button2_Click(object sender, EventArgs e)
{
var url = "https://localhost:7248/api/Lab";
dataGridView1.DataSource = LabResult.GetLabData();
var table = JsonConvert.SerializeObject(dataGridView1.DataSource);
ApiSender apiSender = new ApiSender();
apiSender.POSTData(table, url);
}
public class ApiSender
{
private static HttpClient _httpClient = new HttpClient();
public bool POSTData(object json, string url)
{
using (var content = new StringContent(JsonConvert.SerializeObject(json), System.Text.Encoding.UTF8, "application/json"))
{
HttpResponseMessage result = _httpClient.PostAsync(url, content).Result;
if (result.StatusCode == System.Net.HttpStatusCode.Created)
return true;
string returnValue = result.Content.ReadAsStringAsync().Result;
throw new Exception($"Failed to POST data: ({result.StatusCode}): {returnValue}");
}
}
}
Receiving Json data format
[{"SerialNumber":1,"LabParameterName":"abc","LabValue":7.80,"LabDate":"2001-11-16T10:10:00"},{"SerialNumber":2,"LabParameterName":"xyz","LabValue":10.00,"LabDate":"2001-11-16T10:10:00"},{"SerialNumber":3,"LabParameterName":"qq","LabValue":5.00,"LabDate":"2001-03-16T10:10:00"},{"SerialNumber":18,"LabParameterName":"cbc","LabValue":200.0,"LabDate":"2001-11-16T10:10:00"}]
The JSON value could not be converted to LabDataApi.Models.LabData
Well, you are trying to convert an array of LabData into the LabData model. Update the API to receive IEnumerable<LabData>, or update the client to send multiple POST requests (for each LabData entry (not recommended)).
At least that's the answer to the question you've asked - it looks like you have cut off the end of the exception, perhaps you omitted some essential details by mistake?
There is an issue with your objects definitions when converting to json. Also, you'll want to get it as a List or an Array.
Your serialization/deserialization will work better with these objects.
public class LabDatas
{
public LabData[] Value { get; set; }
}
//or if you want list
public class LabDatas
{
public List<LabData> Value { get; set; }
}
public class LabData
{
public int SerialNumber { get; set; }
public string LabParameterName { get; set; }
public float LabValue { get; set; }
public DateTime LabDate { get; set; }
}
I am practicing with web api. My goal is to create a Get endpoint, which receive data from an external api, then return a different result. external api link: https://www.themealdb.com/api/json/v1/1/search.php?f=a, The external api data looks like:
{
"meals": [
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"strDrinkAlternate": null,
"strCategory": "Dessert",
.....
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
....
}
]
}
I want my endpoint provide a different result like the following:
[
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"ingredients": ["Apple", "sugar"...]
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
"ingredients": ["Apple", "sugar"...]
}
]
The following code is what I attempted so far, It's working, but the moment I changed property ingredient1 from public to private, that ingredient in list will become null, also, there are so many ingredients, some of them are null by default, I don't want to add them if they are null, how can I fix these two issues? Thanks a lot
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;
using RestSharp;
namespace testAPI.Controllers;
public class Content
{
[JsonPropertyName("meals")]
public List<Meal> Meals { get; set; }
}
public class Meal
{
[JsonPropertyName("idMeal")]
public string MealId { get; set; }
[JsonPropertyName("strMeal")]
public string Name { get; set; }
[JsonPropertyName("strIngredient1")]
public string Ingredient1 { get; set; }
[JsonPropertyName("strIngredient2")]
public string Ingredient2 { get; set; }
[JsonPropertyName("strIngredient20")]
public string Ingredient20 { get; set; }
public List<string> Ingredients
{
get { return new List<string>(){Ingredient1, Ingredient2, Ingredient20};}
}
}
[ApiController]
[Route("api/[controller]")]
public class DishesController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
var mealList = JsonSerializer.Deserialize<Content>(response.Content);
return Ok(mealList.Meals);
}
}
To address the problems one at a time...
the moment I changed property ingredient1 from public to private, that ingredient in list will become null
Changing the access modifier affects both deserialization and serialization, so this cannot be used to only stop it from serializing the property. You should split the data models up into what you want to receive and what you want to expose/return.
there are so many ingredients, some of them are null by default, I don't want to add them if they are null
Addition to splitting up the data models you can handle this when mapping from one model to the other.
The following code should fix both issues:
namespace TheMealDb.Models
{
// These are the models you receive from TheMealDb
// JSON converted to classes with https://json2csharp.com/
public class Root
{
public List<Meal> meals { get; set; }
}
public class Meal
{
public string idMeal { get; set; }
public string strMeal { get; set; }
public string strIngredient1 { get; set; }
public string strIngredient2 { get; set; }
public string strIngredient3 { get; set; }
// Other properties removed for brevity...
}
}
namespace Internal.Models
{
// This is the model you want to return from your controller action
public class Meal
{
[JsonPropertyName("id")] // No need to use the same name as from themealdb
public string Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("ingredients")]
public List<string> Ingredients { get; set; }
}
}
Now, to fetch, map and return the data in your controller action:
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
// Deserialize to the "TheMealDb" models
var mealList = JsonSerializer.Deserialize<TheMealDb.Models.Root>(response.Content);
// Map to your own models
var myMealList = mealDbList.meals?.Select(MapToInternal);
return Ok(myMealList);
}
// Map "TheMealDb" model to your own model
private Internal.Models.Meal MapToInternal(TheMealDb.Models.Meal externalMeal)
{
return new Internal.Models.Meal
{
Id = externalMeal.idMeal,
Name = externalMeal.strMeal,
Ingredients = new []
{
externalMeal.strIngredient1,
externalMeal.strIngredient2,
externalMeal.strIngredient3,
// ...
}
// Remove empty/null ingredients
.Where(ingr => !string.IsNullOrEmpty(ingr))
.ToList()
};
}
See the code in action.
I need to get both XML and JSON response data based on the request URL.To achieve my requirement I added this code lines to my API's Application_Start method in global.asax
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(
new QueryStringMapping("type", "json", new MediaTypeHeaderValue("application/json")));
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(
new QueryStringMapping("type", "xml", new MediaTypeHeaderValue("application/xml")));
this code works fine for get JSON. I called API this way,
For JSON output: http://localhost:2751/api/student?type=JSON
For XML output: http://localhost:2751/api/student?type=xml
But when I calling for XML this error will be occurred.
The 'ObjectContent`1' type failed to serialize the response body for
content type 'application/xml; charset=utf-8'.
and this is the inner exception message.
Type 'DeleteAPI.Models.StudentModel' with data
contract name
'StudentModel:http://schemas.datacontract.org/2004/07/DeleteAPI.Models'
is not expected. Consider using a DataContractResolver if you are
using DataContractSerializer or add any types not known statically to
the list of known types - for example, by using the KnownTypeAttribute
attribute or by adding them to the list of known types passed to the
serializer.
This is the part of my model class call Student.
public class StudentModel
{
public int StudentID { get; set; }
public int ProjectID { get; set; }
public string WorkDate { get; set; }
public Nullable<int> WorkingHours { get; set; }
public Nullable<int> Overtime { get; set; }
public string Descriptions { get; set; }
}
Part of Controller class,
namespace DeleteAPI.Controllers
{
public class StudentController : ApiController
{
// GET: api/Student
public ArrayList Get()
{
StudentPersistent tp = new StudentPersistent();
return tp.getStudentAll();
}
}
}
and this is the part of StudentPersistent.class
public class StudentPersistent
{
public ArrayList getStudentAll()
{
ArrayList stdArray = new ArrayList();
MySql.Data.MySqlClient.MySqlDataReader mySQLReader = null;
try
{
string sqlString = "select * from tblStudent";
MySql.Data.MySqlClient.MySqlCommand cmd = new MySql.Data.MySqlClient.MySqlCommand(sqlString, conn);
mySQLReader = cmd.ExecuteReader();
while (mySQLReader.Read())
{
StudentModel dm = new StudentModel();
dm.StudentID = mySQLReader.GetInt32(0);
dm.ProjectID = mySQLReader.GetInt32(1);
dm.WorkDate = mySQLReader.GetString(2);
dm.WorkingHours = mySQLReader.GetInt32(3);
dm.Overtime = mySQLReader.GetInt32(4);
dm.Descriptions = mySQLReader.GetString(5);
stdArray.Add(dm);
}
}
catch (MySqlException x)
{
Console.WriteLine(x.Number);
}
return stdArray;
}
}
How can I solve this error and what is the reason for it?
Try changing the action method to :
[HttpGet]
public HttpResponseMessage Get(int isxmlorJson)
{
StudentPersistent tp = new StudentPersistent();
tp = //Get data from Business Layer
var data = new ObjectContent<StudentPersistent>(tp,
((isxmlorJson== 1) ? Configuration.Formatters.XmlFormatter :
Configuration.Formatters.JsonFormatter));
return new HttpResponseMessage()
{
Content = data
};
}
This is the general way of defining the controllers and the configuration in application_start can be removed .
Problem solved. I added KnownType attribute to my model class.
[KnownType(typeof(DeleteAPI.Models.TaskModel))]
public class StudentModel
{
public int DeveloperID { get; set; }
public int ProjectID { get; set; }
public string WorkDate { get; set; }
public Nullable<int> WorkingHours { get; set; }
public Nullable<int> Overtime { get; set; }
public string Descriptions { get; set; }
}
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.
I am using RESTSharp to receive and deserialize result from an API call. Response is JSON. I've created a class for the repsonse that looks like this:
public class JsonResponseClass
{
public class Selector
{
public static string verb { get; set; }
}
public class Points
{
public int definition { get; set; }
}
}
I do following to get the response:
var response = client.Execute<JsonResponseClass>(request);
var resData = response.Data;
How do I read/print values received from above? For example how do I print values verb and definition from the above deserialized response?
You're not supposed to nest the classes. Instead, add a property of each type to the root object's class.
public class JsonResponseClass
{
public Selector selector { get; set; }
public Points points { get; set; }
}
public class Selector
{
public static string verb { get; set; }
}
public class Points
{
public int definition { get; set; }
}
With that in place, the code works as expected:
var response = client.Execute<JsonResponseClass>(request);
var resData = response.Data;
var verb = resData.selector.verb;
var definition = resData.points.definition;
It's not clear what are you asking.
resData variable contains data from request stored in JsonResponseClass so you need to access it's fields like:
string verb = resData.verb;
Console.WriteLine(verb);