I'm trying to pass an array of int to the Controller but I'm getting empty array every time. I know I have to use [FromQuery]. What I'm doing wrong?
[HttpGet("top10/{lineId}/{dateTo}/{groupingType}/{lathes}")]
public async Task<IActionResult> GetTop10(byte lineId, DateTimeOffset dateTo, string groupingType, [FromQuery] int[] lathes)
{
// some stuff
}
And my URL looks like that:
https://localhost:44439/api/v1/dashboards/overview/top10/1/2022-09-28/days/lathes=2&lathes=3&lathes=4&lathes=6
The FromQuery attribute "Specifies that a parameter or property should be bound using the request query string." docs
So the issue is that you are including the lathes in the route but asking the framework to read it from the query string.
Specify the endpoint route as this:
[HttpGet("top10/{lineId}/{dateTo}/{groupingType}")]
public async Task<IActionResult> GetTop10(byte lineId, DateTimeOffset dateTo, string groupingType, [FromQuery] int[] lathes)
{
// some stuff
}
And add the lathes as query string ("?")
https://localhost:44439/api/v1/dashboards/overview/top10/1/2022-09-28/days?lathes=2&lathes=3&lathes=4&lathes=6
Related
I have the following get-method:
public async Task<TModel> Get(string id)
{
var filter = Builders<TModel>.Filter.Eq("_id",id);
var result = await _collection.FindAsync(filter);
return result.FirstOrDefault();
}
My Model is defined like this:
public class Entity
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
...
}
If I test this method I get 404 (Not found) back.
What I already checked:
The id parameter has the right id.
Used id exists in database.
_collection is the correct IMongoCollection.
MongoDB server is running and collection exits.
Connection string, credentials and permissions to connect to the MongoDB server is correct (other crud methods are working).
What other troubleshooting steps can I do? What could be the error?
Thank you for your help!
In the Entity class the _id field is defined to be ObjectId, but in the Get function it is string. MongoDB matches are type-sensitive, so you'll need to convert the string to an ObjectId first.
I have the following class
public class UpdateUserRequest
{
public string Id {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public int Age {get;set;}
}
And I have the following endpoint:
[HttpPut]
[Route("/[controller]/update/user/{userId}")]
public IActionResult Update(UpdateUserRequest update, string userId)
{
// code logic to update a user
// etc...
}
If I run my project with that code swagger generates the proper documentation. The problem is that I want to modify my endpoint and instead of taking a UpdateUserRequest update I will like to take a object update. In other words this is how I would like my endpoint to look like:
[HttpPut]
[Route("/[controller]/update/user/{userId}")]
public IActionResult Update(object update, string userId)
{
// code logic to update a user
// etc...
}
The reason why I want to accept an object instead of an UpdateUserRequest is because I will like to enable my API to only update the properties that are sent through the request. In other words if the user sends:
{ "FirstName":"Tono" }
Then I will only update the property FirstName. without making the other properties null!
How can I tell swagger to generate documentation as if the method where to take UpdateUserRequest parameter when in fact it is accepting an object? When I place an object as a parameter swagger displays this:
How can I have it display json with the format of a UpdateUserRequest?
One solution I have found is to do something like this:
app.Use(async (context, next) =>
{
// if its an update?
if (context.Request.Method == "PUT")
{
// enable buffering in order to see raw object
context.Request.EnableBuffering();
using MemoryStream memoryStream = new MemoryStream();
// save body to memory
await context.Request.Body.CopyToAsync(memoryStream);
// convert it to json
var rawJson = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
// save raw json on current context.
context.Items.Add("rawJson", rawJson);
// later that json could be from current context
// reset the position
context.Request.Body.Position = 0;
}
await next();
);
But this is kind of an ugly hack when I just need a different swagger documentation.
Building an ASP.Net Core 5.0 service. In order to make this service mirror our other APIs I want to:
Have a route that supports the following URIs
// returns a single item
/api/Items/{id}
// returns multiple items
/api/Items/?date={date}
In the above, {id} could be an int, or a guid, and date is in the format YYYYMMDD
Couple
[ApiController]
[Route("Items")]
public class ItemController: ControllerBase
{
[HttpGet("{id}")]
public Item Get(string id)
{
}
[HttpGet()]
public IEnumerable<Item> Get([FromQuery] DateTime date)
{
return new List<Item> { new Item() };
}
}
When I run this, which I'm debugging using the Swagger functionality, it appears that I get two methods:
/Items/{id}
/Items/?date={date}
So far so good, except, that I want to support date strings of YYYYMMDD, but the default date converter does not support that.
One kludge is to make this a string and convert in the function(boo).
Ideally, I'd like to register an additional Date parser for all endpoints.
Ideas?
Using WebClient do send an array to an ApiController via query string I get the error 400.
The api method looks like
public IHttpActionResult List([FromUri] Model model)
In the Model class I have
public int[] Ids { get; set; }
In the client side the code looks like:
webClient.QueryString.Add("ids", "1");
webClient.QueryString.Add("ids", "2");
...
await webClient.DownloadStringTaskAsync(url);
If I send just one "ids" parameter the code works fine, but not with two or more.
I found that the client creates the url like "url?ids=1,2" instead "url?ids=1&ids=2".
Is there some configuration I missed?
WebClient will automatically turn multiple values with the same key into a comma separated string. You can change this behavior, see: How to build WebClient querystring with duplicate keys?
I would recommend using HttpClient instead of WebClient though.
Can I add mandatory parameter to all controller?
I develop RESTful api, so I want to require special "apikey" parameter for every route.
[HttpPut]
[PUT("create")]
public PostDto Create(string title, string description, string tag, long photo, float lat, float lon, int error)
{
if (description.Length > DescriptionMaxLength)
throw new ApiException(ErrorList.TooLongDescription, string.Format("Description is more than {0}", DescriptionMaxLength));
throw new NotImplementedException();
}
[HttpPost]
[POST("edit/{id:int}")]
public bool Edit(int id, string title, string description, int? photo)
{
if (description.Length > DescriptionMaxLength)
throw new ApiException(ErrorList.TooLongDescription, string.Format("Description is more than {0}", DescriptionMaxLength));
throw new NotImplementedException();
}
[HttpDelete]
[DELETE("delete/{id:int}")]
public bool Delete(int id)
{
if (id < 0)
throw new ApiException(ErrorList.InvalidValue, "id is smaller than 0");
throw new NotImplementedException();
}
But I don't want to do it manually for every method.
First of all, you need to determine the exact way you are going to retrieve the API key inside the action's body.
Since you don't want to pass it as the method's argument, it can be a property of the controller (not the best way to do this, you have to create a custom base controller class, but it may work for the simple scenarios) or another temporary per-request storage.
Then you need to create a Web API action filter. It's similar to the regular ASP.NET MVC action filters, there are plenty of tutorials over the web, most of them are about the authorization though.
This filter will try to inject the API key from the request into the controller or the temporary storage of your choice - inside the filter's OnActionExecuting method you have an access to both the request info and the controller context.
When it's all done, just register your filter in the Web API config, here is an example on how to do this.