Unable to configure route for Get in WebApi 2 - asp.net-web-api2

I'm struggling with something very basic. I'm trying to be get a response from my WebApi2 restful service, and I can't.
I have not edited the default WebApi (WebApiConfig.cs) route.
This is the controller
public class AboutController
{
[Route("api/about/{id:int}/{service1}/{service2}")]
public async Task<IHttpActionResult> Get(int accountId, string mainservice, string secondaryservice)
{
//logic
}
}
If I navigate (in a browser) to http://localhost:58090/api/about I get the error message The requested resource does not support http method 'GET'. I guess this makes sense, as it doesn't match the route (path).
If I update the path to something which matches the signature, such as http://localhost:58090/api/about/1/a/b I get the error message No action was found on the controller About' that matches the request.
Even if I add [HttpGet] to the controller, it makes no difference.
As a sanity test, I updated to
public class AboutController
{
public async Task<IHttpActionResult> Get()
{
//logic
}
}
and it does what is expected. I'm lost as to why adding the parameters has confused things so much.
I'm lost as to what I've done wrong

The route must match the parameters
[Route("api/about/{id:int}/{service1}/{service2}")]
public async Task<IHttpActionResult> Get(int id, string mainService, string secondaryService)
{
The above won't work, because it is expecting to see service1 and service2 based upon the route.
Update as per the example below
[Route("api/about/{id:int}/{service1}/{service2}")]
public async Task<IHttpActionResult> Get(int id, string service1, string service2)
{

Related

How to remove value from route int .net core

I'm writing .net core mvc app. I have two methods
[HttpGet("{action}/{userId}")]
public async Task<IActionResult> ChangeUser(string userId)
{
var user = await _dbContext.Users.Where(x => x.Id == userId).FirstOrDefaultAsync();
...
return View(new ChangeUserVM());
}
[HttpPost("{action}/{userId}")]
public async Task<IActionResult> ChangeUser(ChangeUserVM user)
{
...
}
I need routing in the HttpGet method to get into the first method. But then i want to get from the html to the second method and i have to use routing again otherwise i get 405. How i can get rid of routing in the second method?
I can’t verify my suggestion right now, but over second method, try to remove from HttpPost attribute “userId”.
[HttpPost(“action”)]
public async Task<IActionResult> ChangeUser(ChangeUserVM user)

ASP.Net Core required parameter binding fails to fail using FromBody

I'm developing an Asp.Net Core API.
My controller declaration
[ApiController]
public class BarController : Controller
{
...
}
My endpoint looks like this
[HttpPost, Route("bars")]
public async Task<ActionResult> DoAsync(
[FromBody] UpdateBars command)
{
// Do something with the command
return Ok(result);
}
The command looks like this
public class UpdateBars
{
[Required]
public IEnumerable<string> Ids { get; set; }
// ... more properties
}
Compatibility level is set to 2.1
public IServiceProvider ConfigureSharedServices(IServiceCollection services)
{
// ...
services.AddMvc()
.AddControllersAsServices()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// ...
}
Old question: I'd expect this to return a 400 bad request with a missing Ids parameter, but it fails to return the binding error.
What am I doing wrong?
Updated question: I'd expect this to return a 400 bad request with a missing or empty Ids parameter. The response is as expected if the parameter is missing (null), but returns 200 ok if it is an empty collection.
Is it possible to change something so that I get a bad request when the parameter is present but empty?
You probably didn't put a [ApiController] attribute on your controller.
By default the validation is not 'automatic'.
If you don't want to put that attribute on your controller, you will have to validate the model yourself, in following way:
[HttpPost, Route("bars")]
public async Task<ActionResult> DoAsync(
[FromBody] UpdateBars command)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// Do something with the command
return Ok(result);
}
You have more controll in that way, but if you just need to return a BadRequest with the model state, it will happen automatically if you put the [ApiController] on the controller.
Also in that case it will mark all action parameters as [FromBody], so putting that attribute on params is not needed
You should add the [ApiController] attribute. In that case, an automatic HTTP 400 response containing error details is returned when model state is invalid. For more information, see Automatic HTTP 400 responses. Automatic HTTP 400 responses.

ASP.NET Core routing error

I have a route like http://localhost:63037/api/futuresMarginRuns/7/data which is working however another controller API with route http://localhost:63037/api/futuresMarginRuns/2018-07-11/data is not working, even the breakpoint in the controller API is not hit.
Here are the API signatures
[HttpGet]
[Route("/api/futuresMarginRuns/{id}/data")]
public async Task<IActionResult> GetFuturesMarginRunDataAsync(long id)
{
var data = await _repository.GetAllAsync(id).ConfigureAwait(false);
return Ok(data);
}
[HttpGet]
[Route("/api/futuresMarginRuns/{runDate}/data")]
public async Task<IActionResult> GetFuturesMarginRunDataByDateAsync(DateTime runDate)
{
var data = await _repository.GetAllAsync(runDate).ConfigureAwait(false);
return Ok(data);
}
In the first case I get json data but in the second one the breakpoint is not hit so looks like the route is not mapped to the API properly in which case I would expect an error, but i get empty []
How can I the API to work?
Thanks
You need to add some route constraints to your routes. Route constraints tell the routing engine that if id is supposed to be an int, only match that route if the text in that spot can be converted to an int (and similarly with dates, etc).
So I would change your routes to the following:
[HttpGet]
[Route("/api/futuresMarginRuns/{id:long}/data")]
public async Task<IActionResult> GetFuturesMarginRunDataAsync(long id)
[HttpGet]
[Route("/api/futuresMarginRuns/{runDate:datetime}/data")]
public async Task<IActionResult> GetFuturesMarginRunDataByDateAsync(DateTime runDate)

Web API 2 Post 404s, but Get works

I'm confused... I have a very simple Web API and controller, which works fine if I have a GET request, but 404's if I have a POST request.
[RoutePrefix("api/telemetry/trial")]
public class LoginTelemetryController : ApiController
{
[Route("login")]
[HttpPost]
public IHttpActionResult RecordLogin(string appKey) {
using (var context = new Core.Data.CoreContext()) {
context.ActivityLogItems.Add(new Domain.Logging.ActivityLogItem()
{
ActivityType = "Trial.Login",
DateUtc = DateTime.UtcNow,
Key = new Guid(appKey)
});
context.SaveChanges();
}
return Ok();
}
When I post against this in postman, I get:
{
"message": "No HTTP resource was found that matches the request URI 'http://localhost:47275/api/telemetry/trial/login'.",
"messageDetail": "No action was found on the controller 'LoginTelemetry' that matches the request."
}
If I change it to a [HttpGet] and put the appKey as a querystring, all is fine.
My app startup is very simple:
public void Configuration(IAppBuilder app)
{
log4net.Config.XmlConfigurator.Configure();
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.MapHttpAttributeRoutes(); // <------ HERE
FilterConfig.RegisterHttpFilters(httpConfig.Filters);
LoggingConfig.RegisterHandlers(httpConfig.Services);
ConfigureOAuth(app);
ConfigureWebApi(httpConfig);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(httpConfig);
}
Can anyone spot why POST requests aren't being found? Thanks
If I take string parameter out and replace it with a request object, it works...
Instead of: public IHttpActionResult RecordLogin(string appKey)
I create a request model class:
public class PostLoginTelemetryRequest{
public string appKey {get;set;}
}
Then alter the signature:
public IHttpActionResult RecordLogin(PostLoginTelemetryRequest request)
Everything works fine (why it can't take a regular string like MVC5 web dev, I don't know, but anyway...)
(also note that I had tried this in every format from the client with the string method: form-url-encode, raw body, etc, so I'm fairly certain it wasn't a calling format issue).

Get the route value from url in webapi attribute routing

I have a webAPI controller which is like
Public class TestController:APIController
{
[Route(“Api/Test/{testId}/SubTest”)]
Public void Post(int subTestid)
{
}
}
Our requirement is to get the value of testId from the url inside the post method.
Could anyone suggest the best way to achieve this.
Looking at this link: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
The string "customers/{customerId}/orders" is the URI template for the
route. Web API tries to match the request URI to the template. In this
example, "customers" and "orders" are literal segments, and
"{customerId}" is a variable parameter.
public class OrdersController : ApiController
{
[Route("customers/{customerId}/orders")]
[HttpGet]
public IEnumerable<Order> FindOrdersByCustomer(int customerId) { ... }
}
It seems that you need to change subTestid to testId so it will be a match.