I have Controller class like this:
namespace OptionsAPI.Controllers
{
[Route("api/[controller]")]
public class OptionsController : Controller
{
HttpGet("{symbol}/{date}")]
public IActionResult Chain(string symbol, string date)
{
DateTime quotedate = System.DateTime.Parse(date);
}
}
}
When I try to call the chain function through the URL like this:
http://127.0.0.1:5000/api/options/Chain/symbol=SPX&date=2019-01-03T10:00:00
I get this error:
FormatException: The string 'symbol=SPX&date=2019-01-03T10:00:00' was not recognized as a valid DateTime. There is an unknown word starting at index '0
It seems like "SPX" and the "date" are being concatenated as one string. What is the correct way to call this URL?
The given route template on the action
[HttpGet("{symbol}/{date}")]
along with the template on the controller
[Route("api/[controller]")]
expects
http://127.0.0.1:5000/api/options/SPX/2019-01-03T10:00:00
But the called URI
http://127.0.0.1:5000/api/options/Chain/symbol=SPX&date=2019-01-03T10:00:00
maps the Chain in the URL to symbol and the rest to date, which will fail when parsed.
To get the desired URI, the template would need to look something like
[Route("api/[controller]")]
public class OptionsController : Controller {
//GET api/options/chain?symbol=SPX&date=2019-01-03T10:00:00
[HttpGet("Chain")]
public IActionResult Chain(string symbol, string date) {
//...
}
}
Reference Routing to controller actions in ASP.NET Core
Reference Routing in ASP.NET Core
Related
Is there a way to automatically add a suffix on all endpoint routes e.g .json.
v1/users.json
v1/users/{id}.json
so what I have tried so far is I created a BaseController which look like this
[ApiController]
[Route("v1/[controller].json")]
public class BaseController : ControllerBase
{
}
but every time I use it to my controller it looks like this
v1/users.json
v1/users.json/{id}
You can add extra routing to the actual endpoints rather than the controllers
[ApiController]
[Route("v1/[controller]")]
public class BaseController : ControllerBase
{
[HttpGet(".json")]
public IActionResult Get()
{
}
// Without Route Parameters
[HttpGet("{id}.json")]
public IActionResult Get([FromRoute] int id)
{
...
}
// With Route and Query Parameters
[HttpGet("{id}.json/friend")]
public IActionResult Get([FromRoute]int id,[FromQuery] string friendName)
{
...
}
// With Route and Query Parameters and Body
[HttpPost("{id}.json/friends")]
public IActionResult Get([FromRoute]int id,[FromQuery] string message, [FromBody]IFilter filter)
{
...
}
}
You could use the URL Rewriting Middleware to accept URLs with .json and then simply remove it. So something like:
/api/users/123/picture.json?query=123
would become:
/api/users/123/picture?query=123
You can do this by adding the following code to your Startup's Configure method:
var rewriteOptions = new RewriteOptions()
.AddRewrite(#"^(.*?)(?:\.json)(\?.*)?$", "$1$2");
app.UseRewriter(rewriteOptions);
See the docs for more information.
Caveat: If you use Url.Action(...), etc. to generate a URL within code, then it won't include .json. The rewrite only affects incoming requests.
I have the following controller method:
public class MyApiController : Controller
{
[HttpGet("api/custom")]
public async Task<IActionResult> Custom(string data)
{
}
}
If I hit this action method with the following query param localhost:5000/api/custom?data=Y%3D%3DX then I get the value Y==X for my data parameter in the Custom method.
Is it possible to disable this decoding for this method only, so I can get the original unescaped value?
For ASP.Net Core if you need to encode the characters from a query parameter, you could use Uri.EscapeDataString(String) in this way:
string dataEncoded = Uri.EscapeDataString(data);
In your HttpGet request it would become:
public class MyApiController : Controller
{
[HttpGet("api/custom")]
public async Task<IActionResult> Custom(string data)
{
string dataEncoded = Uri.EscapeDataString(data);
}
}
You will still get the decoded string in the data parameter. To my knowledge, there isn't a way to completly disable URL Decoding on a specific controller.
I have a fairly simple controller for my API. One method returns all devices, and another method returns information on just one. Both of them are HttpGet.
My route definition:
[Route("api/device/list/{Id}")]
[ApiController]
public class DeviceController : ControllerBase
This method is always called when I pass in an ID:
[HttpGet]
public ActionResult<poiDevices> GetDeviceList()
The PostMan URL looks like this:
https://localhost:5001/api/device/list/mycoolid
When the call above is made I want it to call this method below, defined as such with an Id parameter:
public ActionResult<DeviceDto> GetDeviceDetails(
[FromRoute] string Id)
The code above has a placeholder for an Id, so my expectation is for this method to be called, instead the generic method is called which returns all. If I take the Id out of the URL the API returns 404 not found, meaning I messed up the routing piece of this.
What am I missing here?
You should change your controller like this.
[Route("api/device")]
[ApiController]
public class DeviceController : ControllerBase
{
[HttpGet]
[Route("list")]
public ActionResult<poiDevices> GetDeviceList() {
}
[Route("list/{id}")]
public ActionResult<DeviceDto> GetDeviceDetails(
[FromRoute] string Id) {
}
}
I'm new to webapi 2 and trying to get my api to bind to this call below.
Can anyone see what I'm doing wrong?
Call:
https://blabla.azurewebsites.net/myjohndeere/authenticated/e33dd8f74c97474d86c75b00dd28ddf8?oauth_token=1539dccf-d935-4d9e-83be-e00f76cabbb9&oauth_verifier=B22dWL
[RoutePrefix("myjohndeere")]
public class ApiMyJohnDeereController : ApplicationController
{
[HttpGet, Route("authenticated/{callbackId}")]
[SwaggerResponse(HttpStatusCode.OK, Type = typeof(ApiResponseModel))]
[SwaggerResponse(HttpStatusCode.InternalServerError, "An unknown error occurred")]
[SwaggerResponse(HttpStatusCode.BadRequest, "Missing FieldMappings")]
public IHttpActionResult Authenticated(string callbackId,[FromUri]string oauth_token, [FromUri]string oauth_verifier)
{
...
}
First of, you missed the 'api' in the route.
Try it like this
https://blabla.azurewebsites.net/api/myjohndeere/authenticated/e33dd8f74c97474d86c75b00dd28ddf8?oauth_token=1539dccf-d935-4d9e-83be-e00f76cabbb9&oauth_verifier=B22dWL
Then, remove the FromUri attribute from your controller method. The attribute is not needed when just reading querystring of value types.
Try it like this
public IHttpActionResult Authenticated(string callbackId, string oauth_token, string oauth_verifier)
The issue was the Azure API gateway was still set to use PUT rather than GET.
I'm trying to use Web API 2 attribute routing to set up a custom API. I've got my route working such that my function gets called, but for some reason I need to pass in my first parameter for everything to work properly. The following are the URLs I want to support:
http://mysite/api/servicename/parameter1
http://mysite/api/servicename/parameter1?parameter2=value2
http://mysite/api/servicename/parameter1?parameter2=value2¶meter3=value3
http://mysite/api/servicename/parameter1?parameter2=value2¶meter3=value3&p4=v4
The last 3 URLs work but the first one says "No action was found on the controller 'controller name' that matches the request."
My controller looks like this:
public class MyServiceController : ApiController
{
[Route("api/servicename/{parameter1}")]
[HttpGet]
public async Task<ReturnType> Get(string parameter1, DateTime? parameter2, string parameter3 = "", string p4 = "")
{
// process
}
}
Web API requires to explicitly set optional values even for nullable types...so you can try setting the following and you should see your 1st request succeed
DateTime? parameter2 = null