On the controller method, before returning the value, result array is filled correctly. However, generated JSON response is truncated from start. This is on asp net core 2.1. I have one middleware block but doesn't get called while returning response, only in requests.
I already tried ReferenceLoopHandling option, didn't work, I am working on quite small array anyways.
[HttpGet("GetAll")]
public IEnumerable<Job> GetAll()
{
var result = _dbManager.GetAllJobs();
return result;
}
Response should be fully constructed Json array, however I am getting this:
[{
You can map like that easily.
[HttpGet("GetAll")]
public async Task<IActionResult> GetAll()
{
var result = _dbManager.GetAllJobs();
return Ok(result.Select(x=> new JobDto(){ Id = x.Id, JobName = x.Name ....}));
}
Related
I have written method that returns the result in the object. I need to capture current HttpStatusCode rather than I create my own and save in the following object before returning a result
[HttpPost]
public ActionResult CreateUser([FromBody]UsereDto user)
{
try
{
var data = UserService.CreateUser(user);
var result = new ResultDto
{
Ok = true,
Data = data,
Error = "No",
StatusCode = HttpStatusCode. ???????????????
};
return Ok(result);
}
catch(Exception exp)
{
var errorResult = new ResultDto
{
Ok = false,
Data = null,
Error = exp.ToString()
StatusCode = ????????????
};
return Ok(errorResult);
}
}
Can't capture existing http code
you can manually enter http codes yourself.
For Example:
Created Code=201
Error Code =400
BadRequest:301
NotFound:404
return StatusCode(200,object);
You can also return it this way.
I am not 100% sure what do you want to achieve or why do you even want that since HTTP Response already will contain an http status, so returning it additionally in a JSON response does not add more information than is already available.
But you can just hardcode the status since it is always 200 in your example, unless there is some error during serialization of the response, etc.
Right after your ??? line you do return an Ok() response that will return 200.
You don't need to create your own status code inside dto...
return Ok(errorResult); will return 200 with error and this is bad.
Instead, you should return BadRequestResult(errorResult) and ui will receive 500 result containing your DTO.
Also, instead of return Ok(result);, you can return OkResult(result) and this will return 200 to UI, also containing your DTO...
Also, you should extract Dto creation to it's own method in separate class, to follow DRY and single responsibility principles..
This is my ASP.NET CORE WEB API Method
[HttpGet]
[Route("schooltypegroups")]
[Produces("application/json")]
[SwaggerOperation("GetSchoolTypeGroups")]
[SwaggerResponse(400, "Bad input parameter")]
[SwaggerResponse(404, "Not found")]
[SwaggerResponse(500, "Internal server error")]
public async Task<IActionResult> GetSchoolTypeGroups()
{
try
{
var devicetypegroups = await _context.SchoolTypeGroups
.Include(b => b.SchoolTypes)
.Include(p => p.Students)
.ThenInclude(student=> student.StudentGroup)
.ToListAsync();
//Now, studenttypegroups is having all proper data
return Ok(studenttypegroups);
//But returned Null child entities
//Student and StudentGroup is empty in json response like this []
}
catch (Exception exception)
{
return new ServerErrorResult();
}
}
I see all the proper values inside studenttypegroups while debugging.
But, returned JSON has null values for child entities.!!
Anything I am missing?
My Guess
I was using ResponseType attribute in .net framework. But I do not see it in asp.net code
Json Output shows Students empty
I think it's lazy loading issue, which is not implemented in .net core https://github.com/aspnet/EntityFrameworkCore/issues/3797
I have an action on my web project which calls to an API
[HttpPost]
public async Task<IActionResult> ExpireSurvey(int id)
{
var token = await HttpContext.GetTokenAsync("access_token");
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var path = "/api/forms/ExpireSurvey";
var url = Domain + path;
var data = JsonConvert.SerializeObject(id);
HttpContent httpContent = new StringContent(data, Encoding.UTF8, "application/json");
var response = await client.PutAsync(url, httpContent);
return Json(response);
}
}
In the API project this is received as follows:
[HttpPut]
public IActionResult ExpireSurvey([FromBody] int surveyId)
{
_repository.ExpireSurvey(surveyId, expiryDate);
return Ok();
}
This works fine - however, say I want to pass in an int id and a DateTime variable, how do I serialise and pass them both into the HttpContent? I can do it with a DTO object, but I don't want to be setting up DTO objects when there is only two fields.
You can use anonymous types like this
var x = new { id = 2, date = DateTime.Now };
var data = JsonConvert.SerializeObject(x);
When receiving the data, you can only have one [FromBody] parameter. So that doesn't work for receiving multiple parameters (unless you can put all but one into the URL). If you don't want to declare a DTO, you can use a dynamic object like this:
[HttpPost]
public void Post([FromBody] dynamic data)
{
Console.WriteLine(data.id);
Console.WriteLine(data.date);
}
Don't overdo using anonymous types and dynamic variables though. They're very convenient for working with JSON, but you lose all type checking which is one of the things that makes C# really nice to work with.
I think it would be helpful to recognize that ASP.NET Core is REST-based and REST fundamentally deals with the concept of resources. While not an unbreakable rule, the general idea is that you should have what you're calling DTOs here. In other words, you're not posting distinct and unrelated bits of data, but an object that represents something.
This becomes increasingly important if you start mixing in things like Swagger to generate documentation for your API. The objects you create become part of that documentation, giving consumers of your API a template for follow in the development of their apps.
Long and short, I'd say embrace the concept of resources/objects/DTOs/whatever. Model the data your API works with. It will help both you as a developer of the API and any consumers of your API.
You can pass multiple parameters in as URL as below example
Parameter name must be the same (case-insensitive), If names do not
match then values of the parameters will not be set.
[HttpPost]
[Route("{surveyId}/{expiryDate}")]
public IActionResult Post(int surveyId, DateTime expiryDate)
{
return Ok(new { surveyId, expiryDate });
}
Call URL
http://localhost:[port]/api/[controller]/1/3-29-2018
Based on the answers above, I got the following code working. Hope this helps someone! (thanks to others of course for getting me on the right track)
/// <summary>
/// Post api/dostuff/{id}
[HttpPost]
[Route("dostuff/{id}")]
public async Task<IActionResult> DoStuff([FromBody]Model model, int id)
{
// Both model and id are available for use!
}
You can replace the line
var data = JsonConvert.SerializeObject(id);
with
var data = new StringContent(JsonConvert.SerializeObject((surveyId, expiryDate)), Encoding.UTF8, "application/json");
The trick is that you use a Tuple object containig your parameters as a single parameter.
You should use the Tuple type on the the server side as well. It could look like:
[HttpPost]
public Task MyWebApiMethod([FromBody] (int SurveyId, DateTime ExpiryDate) parameters)
{
int surveyId = parameters.SurveyId;
DateTime expiryDate = parameters.ExpiryDate;
// Process your parameters ...
}
I do not have Visual Studio now and sorry if there are any compilation issues etc.
you can do it with a dictionary
Dictionary<int, object> dict = new Dictionary<int, object>();
dict["id"] = 1
dict["date"] = DateTime.Now;
JsonConvert.SerializeObject(dict);
I have written asp.net web-api project with following api-s:
Controller Method: Uri:
GetAllItems: /api/items (works)
GetItem(int id) /api/items/id (works)
and
GetListOfItem(IEnumerable<Items> items) /api/items/List of items (doesn't work)
The function is similar to this (don't care about logic)
public IHttpActionResult GetByArray(IEnumerable<Book> bks)
{
var returnItems = items.Select(it => it).Where(it => it.Price < bks.ElementAt(0).Price || it.Price < bks.ElementAt(1).Price);
if (returnItems == null)
return NotFound();
else
{
return Ok(returnItems);
}
}
I am using postman to send requests and following requests works correct
http://localhost:50336/api/items/
http://localhost:50336/api/items/100
but not
http://localhost:50336/api/items/[{"Owner":"MySelf","Name":"C","Price":151},{"Owner":"Another","Name":"C++","Price":151}]
How should i format the last request where i have a list of items in json format in order to get it works?
You want to decorate your method with a HttpPostAttribute and FromBodyAttribute:
[HttpPost]
public IHttpActionResult GetByArray([FromBody]IEnumerable<Book> bks)
{
}
Then send the json as post body.
Your Postman shoud look like this:
Specifically for
GetListOfItem(IEnumerable<Items> items)
[FromBody] is definitely best option.
In case you are using primitive types you can do following:
GetListOfItem([FromUri] int[] itemIds)
And send request as:
/GetListOfItem?itemIds=1&itemIds=2&itemIds=3
I'm new to Odata have been writing an api using .net (c#) and this video https://docs.oasis-open.org/odata/odata/v4.0/odata-v4.0-part2-url-conventions.html.
The problem is that i have this constructor method like so:
[EnableQuery]
public ObjectResult<InclusionWorkBookResult> GetInclusionWorkBooks()
{
string query = this.Url.Request.RequestUri.Query;
if (string.IsNullOrEmpty(query))
{
return Request.CreateErrorResponse(HttpStatusCode.Forbidden, "");
}
return db.GetInclusionWorkBookData();
}
As you will be able to see, the idea is that it returns a Forbidden error code if the user does not specify a query (this is to force them to filter as the full data set is millions of rows).
However this does not work because the Request.CreateErrorRespons is a HttpResponseMessage and the get returns ObjectResult.
I know you can get a forbidden error when querying odata (by messing up the url query).
My question is this:
How can i return a custom error message without messing up the return headder of the GET?
Thank you in advance.
you can return IHttpActionResult instead, eg:
public IHttpActionResult GetInclusionWorkBooks()
{
string query = this.Url.Request.RequestUri.Query;
if (string.IsNullOrEmpty(query))
{
return BadRequest();
}
return Ok(db.GetInclusionWorkBookData());
}
if a query has been provided, the result will be 200(OK) and the requested data, otherwise it will be 400 Bad Request