From route configuration to attribute routing - asp.net-web-api

I have the following route configured in my ASP.NET Web API 2 Project:
config.Routes.MapHttpRoute(
name: "1MandatoryStringParameter",
routeTemplate: "api/{controller}/{data}",
defaults: null,
constraints: new { data = #".+?" }
It is used with the following controller method (notice the ArrayInput attribute):
[ArrayInput("data",Separator = ',')]
public async Task<IHttpActionResult> Get(int[] data)
{
...
}
I would like to use Attribute routing instead.
I tried to replace the call to MapHttpRoute with the following attributes:
[HttpGet]
[Route("api/ActionsForItemTypesList/{data:regex(.+?)}", Name = "1MandatoryStringParameter")]
Out of the box it does not work. I can't reach my method with an URL like:
api/ActionsForItemTypesList/1,2
If get a 404 Method not found.
This is working fine with route configuration.
Any help appreciated.
EDIT : fixed the client URL.
EDIT 2 : This is an ApiExplorer Issue (Swashbuckle leverage ApiExplorer)
If I modify the Route attribute and remove the parameter (ie. {data}) the ApiDescription becomes available.

Make sure you have enabled attribute routing:
config.MapHttpAttributeRoutes();
Also in your Route attribute you have specified that the data parameter must be part of the path and not a query string. So make sure that you are calling the action correctly from the client:
api/ActionsForItemTypesList/1,2
Also notice that the prefix that you indicated in your Route attribute is api/ActionsForItemTypesList and not api/Controller like you were trying to invoke it.

Related

web api support parameters while they don't have one

http://localhost:xxxx/api/BindAppointmentResources
works fine for me but when I'm trying to add any invalid object after controller (with this ? "http://localhost:xxxxx/api/BindAppointmentResources?Userid") in URL its gets the same result
I tried action-based routing , attribute routing so far but same result?
PS : I don't have parameters in WEB API
Route Config :
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
}
Query string parameters will automatically get bound to your parameters that have the same name in web api.
If no parameter names are found it will route the request to the base url (which is the url before the question mark).
So this url
http://localhost:xxxx/api/BindAppointmentResources?UserID=1
will, if no method with parameter name that match UserID are found, end up being routed to
http://localhost:xxxx/api/BindAppointmentResources
In the Get method you can still get the query string
var queryString = this.Request.GetQueryNameValuePairs();
To prevent binding parameters from query string and only allow bindings from route values, you could remove the default QueryStringValueProviderFactory from the default HttpConfiguration configuration. Read more about it in this article

The route template separator character '/' cannot appear consecutively when adding action to default route

I have a Web API 2 project hosted through an OWIN middleware. Everything worked perfectly fine and I am able to call my APIs as expected. But, my WebApiConfig defines the default route as follows:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Accordingly, I have to call my APIs using URLs similar to: /api/values/dosomething
This worked for me until I decided to document my API. For that, I first tried using the WebAPI Help Page package which did not work. Then I thought I should try Swashbuckle Swagger and see if that helps me avoid the problem altogether, but unfortunately, in both cases I got the same error:
The route template separator character '/' cannot appear
consecutively. It must be separated by either a parameter or a literal
value. Parameter name: routeTemplate
After trying a few things, it turned out that when change the route template and remove the {action} part, the error is gone. But, I cannot really do that because the whole project assumes that URLs include the action method name in them.
So anyway, I would like to know the following:
Why is this happening in the first place?
Is there a way to modify this behavior?
Thanks in advance!
I fetch the same problem. Below is my working code.
[RoutePrefix("api/User")]
public class UserController : ApiController
{
[Route("login")]
public IHttpActionResult Get()
{ }
}
when I change Route before methods from
[Route("login")]
public IHttpActionResult Get()
{ }
to
[Route("/login")]
public IHttpActionResult Get()
{ }
I got same error.
It will generate if you add an extra / before any methods of your controller(if it is not called at first time).
I am not sure about your condition. I share my situation if anyone gets help.

Why does my Web API return 405 for everything?

I have a ASP.NET Web API 2 controller in a custom Area.
(I also have some API controllers in the default route)
I have registered the route:
// Web API routes
config.MapHttpAttributeRoutes();
// NEW ROUTE FOR AREAS
config.Routes.MapHttpRoute(
name: "API Area MyArea",
routeTemplate: "api/MyArea/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
My controller and method:
[RoutePrefix("myarea/api/accountapi")]
public class AccountAPIController : ApiController
{
...
[System.Web.Http.HttpGet]
[AcceptVerbs("GET")]
[AllowAnonymous]
[Route("emailexists")]
public async Task<IHttpActionResult> EmailExsists([FromUri]string email)
{
var user = await UserManager.FindByEmailAsync(email).ConfigureAwait(false);
return Ok(user != null);
}
...
}
But I can't get this to work, no matter what I try I get:
https://localhost:44300/api/accountapi/emailexists?email=info#something.com
{"message":"The requested resource does not support http method
'GET'."}
In fact, I can't get it to return an expected 404. For example, this:
https://localhost:44300/api/accountapi/jibberish
Also returns a 405.
My API controllers in the default route works as expected, i.e. returning a 404 when it should.
Any ideas ?
Let's analyze the endpoints you are calling.
The first URI:
https://localhost:44300/api/accountapi/emailexists?email=info#something.com
Looking at your routing configuration this will match only api/{controller}/{id} route template. That's because the first convention routing config will only match URI parts starting with api/MyArea, while the attribute routing prefix of your controller will only match paths starting with myarea/api/accountapi).
This will translate in the following route attributes:
{controller}: accountapi
{id}: emailexists
?email: info#something.com (this will be ignored for routing purposes because is not included in the template)
Looking at your AccountAPIController I can't see any Action that allows GET and also has a string parameter called (explicitly) id: thus a 405 is returned.
The second URI:
https://localhost:44300/api/accountapi/jibberish
Will again only match the same route template as before:
{controller}: accountapi
{id}: jibberish
For the same reason a 405 response is returned.
What to do?
Your main problem is that you are mixing different routing methods without correctly matching the URI for your action. Without modifying the current route configuration the correct address for your EmailExsists method is the following one:
https://localhost:44300/myarea/api/accountapi/emailexists?email=info#something.com
This will match your RoutePrefix and Route attributes in the AccountAPIController.
The following URIs should also match your action method based on the two routing convention you configured (they should be equivalent):
https://localhost:44300/api/accountapi?email=info#something.com
https://localhost:44300/api/MyArea/accountapi?email=info#something.com
My suggestion is to avoid the use of too many different routing templates and configurations: if you need the maximum flexibility use only attribute routing and remove the convention-based routing configuration.

Visual Studio Web API: How to change the routing path

I am working on Web Api. By default, it uses the api/{controller}/{id} as a url. I am able to have it to route api/device/{controller}/{id} but this will affect to all Web API route to that path.
But I only want certain controller to be in api/device/{controller}/{id} and the rest will go to another path.
I saw something like RoutePrefix but it doesn't seem to work...
[RoutePrefix (api/data/abc)] where abc is the controller name.
Add the custom route mapping in WebApiConfig.cs file before default route map:
By adding this before, any requests which matches the custom route will be executed, else the other one.
config.Routes.MapHttpRoute(
name: "CustomRoute",
routeTemplate: "api/device/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
If you want to customize the routing with a per controller approach, then you have to use Attribute Routing instead of the standard convention-based routing.
Decorate your controllers with RoutePrefix attribute, and your actions with Route attribute in this way:
[RoutePrefix("api/device/mydevice")]
public class MyDeviceController : ApiController {
[Route("{id}")]
[HttpGet]
public IHttpActionResult Get(int id) {
//DoWork
//...
}
}
And remember to enable attribute routing on the HttpConfiguration object:
config.MapHttpAttributeRoutes();
You may also remove MapHttpRoute method calls if you do not want to allow access to your actions in the standard convention-based way.
More on attribute routing on the official documentation.

Web Api - Swagger documentation error 500

When I access to the swagger url: http://localhost:28483/swagger/ui/index, it generates this error:
500 : undefined http://localhost:28483/swagger/docs/v1
Any ideas?
UPDATED:
See this detail error in firebug:
Not supported by Swagger 2.0: Multiple operations
with path 'api/BimModel' and method 'GET'. See the config setting - \"ResolveConflictingActions\" for
a potential workaround
Swagger might be considering two actions as one operation (like in the case of this common scenario)...
GET api/Products
GET api/Products/{id}
It seems you can use attribute routing to fix this and use these attributes above your actions so swagger will recognize them separately.
[Route("api/Products")]
[Route("api/Products/{id:guid}")]
Have you tried enable this in you swagger config?
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
In the controller, it got two different GET operations and it is disallowed by Swagger.
I suggest to either have only single GET operation for each controller or modify the router in WebApiConfig
I had the same issue when mixing attribute routing with default routes.
When I removed the default route the problem went away. The downside is, without the default route defined, I had to add attribute routing to all my controllers.
So from my WebApiConfig I removed:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
And added attribute routing to my controller:
[Route("Session")] // Added this attribute
public async Task<IHttpActionResult> Get()
...
[Route("Session/{id}")] // Added this attribute
public async Task<IHttpActionResult> Get(int id)
In reality I use a [RoutePrefix("Session")] on my Controller and use [Route("")] on my methods, but the result should be the same.
I was getting this error due to the parameter names not matching between the Attribute Routing statement and the method signature.
[HttpGet("{id}")]
public IActionResult Get(string deviceNumber){
...
After changing "{id}" to "{deviceNumber}" it fixed the error.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);

Resources