I created the following route in my RouteConfig.cs
config.Routes.MapHttpRoute(
name: "CustomFilter",
routeTemplate: "api/{controller}/{category}/{begin},{pageSize}",
defaults: new
{
category = RouteParameter.Optional,
begin = RouteParameter.Optional,
take = RouteParameter.Optional
}
);
That is used by the method below:
public IHttpActionResult GetStudentsByCategory(string category, int begin, int pageSize)
{
..
}
The custom route works fine, unless the category parameter is missing
1. api/students/tech/1,3 (is working)
2. api/students//1,3 (not working)
Is it possible to make the second URL request (without a category parameter) work?
Add one more Route without category, it should be above current one
config.Routes.MapHttpRoute(
name: "CustomFilter-without-cat",
routeTemplate: "api/{controller}/{begin},{pageSize}",
defaults: new
{
begin = RouteParameter.Optional,
take = RouteParameter.Optional
}
);
config.Routes.MapHttpRoute(
name: "CustomFilter",
routeTemplate: "api/{controller}/{category}/{begin},{pageSize}",
defaults: new
{
category = RouteParameter.Optional,
begin = RouteParameter.Optional,
take = RouteParameter.Optional
}
);
Related
I can call Api with custom route.
(url: 'api/WorkItem/1/GetOne')
[HttpGet]
[Route("api/WorkItem/{id}/GetOne")]
public async Task<IEnumerable<WorkItemDto>> GetOne(int id)
{
//...
}
But I cant call same api if I remove custom route:
This is my route definsion:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}/{action}",
defaults: new { action = RouteParameter.Optional, id = RouteParameter.Optional }
);
I expect this to work without custom route but it does not.
I get 404-NotFound.
What am I doing wrong?
Map route two times. first with action and second time without
config.Routes.MapHttpRoute(
name: "WithAction",
routeTemplate: "api/{controller}/{id}/{action}"
);
config.Routes.MapHttpRoute(
name: "DefaultId",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I've looked through this document on MSDN and can't come up with the answer.
Considering that I have a route defined like this:
config.Routes.MapHttpRoute(
name: "DefaultWithActionAndID",
routeTemplate: "v{version}/{controller}/{action}/{id}",
defaults: null,
constraints: new {
action = #"[a-zA-Z]+",
id = #"\d+"
}
);
config.Routes.MapHttpRoute(
name: "DefaultWithID",
routeTemplate: "v{version}/{controller}/{id}",
defaults: null,
constraints: new {
id = #"\d+"
}
);
config.Routes.MapHttpRoute(
name: "DefaultWithoutActionOrId",
routeTemplate: "v{version}/{controller}",
defaults: null,
);
Now I have two controllers that looks like this:
public class ItemController:ApiController{
[HttpGet]
public Item Get(int id){}
[HttpGet]
public Item GetSomething(int id){}
[HttpPut]
public Item Put(Item newItem){}
}
public class AnotherController:ApiController{
[HttpPut]
public HttpResponseMessage Put(Something item){}
}
I'd like to be able to call all of these endpoints like this:
GET /api/Item/344
GET /api/Item?id=344
GET /api/Item/Something/2334
GET /api/Item/Something?id=2334
PUT /api/Item body={newItem}
PUT /api/Another body={newSomething}
This will work, but only if I add "Get" as the default action name. If I do not specify a default action name in my route, then it complains about multiple matching action names. If I do add the default action name, then I cannot call PUT to the Put() method without an error because the action name doesn't match the default and isn't found.
// Will work in some cases, but not all
config.Routes.MapHttpRoute(
name: "DefaultWithID",
routeTemplate: "v{version}/{controller}/{id}",
defaults: new {
action="Get",
id=RouteParameters.Optional
},
constraints: new {
id = #"\d+"
}
);
// Works
GET /api/Item/344
GET /api/Item?id=344
GET /api/Item/Something/2334
GET /api/Item/Something?id=2334
// Doesn't work
PUT /api/Item body={newItem}
PUT /api/Another body={newSomething}
How can I tell Routing to use the Action with the name that matches my HTTP Verb, if one exists before trying to use
If you define your routes as follows:
config.Routes.MapHttpRoute(
name: "DefaultWithActionAndID",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new {action = #"[a-zA-Z]+", id = #"\d*" }
);
config.Routes.MapHttpRoute(
name: "DefaultWithID",
routeTemplate: "api/{controller}/{id}",
defaults: new { action = "GET", id = RouteParameter.Optional },
constraints: new { id = #"\d*", httpMethod = new HttpMethodConstraint(new string[] { "GET" }) }
);
config.Routes.MapHttpRoute(
name: "DefaultWithoutActionOrId",
routeTemplate: "api/{controller}",
defaults: new { action = "PUT" },
constraints: new { httpMethod = new HttpMethodConstraint(new string[] { "PUT" }) }
);
And also place the ActionName attribute on your GetSomething method as so:
[ActionName("Something")]
public Item GetSomething(int id){}
You should then be able to hit all the endpoints mentioned above.
The way I see it you'd need the following setup:
1.
/api/Item/344
{controller}/{id}
2.
/api/Item/Something/2334
{controller}/{action}/{id}
and decorate the 'GetSomething' method as follows:
[ActionName("Something")]
public Item GetSomething(int id){}
3.
/api/Item?id=344
/api/Item/Something?id=2334
I'm not entirely sure about these - have you tried adding a default to the routes above:
defaults: new { id = RouteParameter.Optional }
4.
I'd expect PUT to just work if #3 is applied
Let me know if that changes anything.
I need to have a custom action for my api controller like api/{controller}/{action}/{id}
This is my config
config.Routes.MapHttpRoute(
name: "DefaultMethodApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "Browse", id = RouteParameter.Optional }
);
This hit the default route /api/dropzone/1
But i try to hit /api/dropzone/browse/1 by the "ApiByAction" configuration, but it doesnt work.
The order of your route definitions is important, make sure you respect it, because they are evaluated in the same order in which you declared them:
config.Routes.MapHttpRoute(
name: "ApiByAction",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new { action = #"^(?!\d)[a-z0-9]+$" }
);
config.Routes.MapHttpRoute(
name: "DefaultMethodApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Also notice that you might need to specify a constraint for the {action} token in the first route definition.
In my TestController I have the following:
[HttpGet]
public IEnumerable<String> Active()
{
var result = new List<string> { "active1", "active2" };
return result;
}
[HttpGet]
public String Active(int id)
{
var result = new List<string> { "active1", "active2" };
return result[id];
}
In RouteConfig the mapping is:
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "", id = RouteParameter.Optional });
In a browser the following request works:
api/test/active/1
But this returns a Internal Server Error:
api/test/active
What do you have to do to return a action that may or maynot have a parameter in a similar manner to the default Get?
Update 1
As Cuong Le suggested, changing the ordering of routes helped, the routes are now:
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I had to remove action = "" from the ActionApi route otherwise the standard Get on the other controllers stopped working (i.e. api/values)
api/test/active is now resolving, but I now get a 500 Internal Server Error for /api/test is it possile to have both resolves, so api/test would return "all" and /test/active only return "some"?
It is probably getting confused since you have two methods named action. Try deleting or renaming one of them and see if that works.
One way to do it is to provide a default value for the parameter,
[HttpGet]
public String Active(int id = 0)
{
var result = new List<string> { "active1", "active2" };
if (id == 0) {
return result;
} else {
return result[id];
}
}
I'm working on my first web api and I'm stuck trying to create rules for these urls
1) http://mydomain.com/values/4 --> this number can be any, this is just an example
2) http://mydomain.com/values/
3) http://mydomain.com/values/?param1=test1¶m2=test2
4) http://mydomain.com/values/?param1=test1
5) http://mydomain.com/values/?param2=test2
My current routing rules are
routes.MapHttpRoute(
name: "Route1",
routeTemplate: "{controller}/{id}/"
);
routes.MapHttpRoute(
name: "Route2",
routeTemplate: "{controller}/{param1}/{param2}",
defaults: new { param1 = RouteParameter.Optional, param2 = RouteParameter.Optional }
);
And my methods serving these urls
// GET values/
// GET values/?param1=test1¶m2=test2
// GET values/?param1=test1
// GET values/?param2=test2
public IEnumerable Get(string param1, string param2)
{
return new string[] { "value1", "value2" };
}
// GET values/5
public string Get(int id)
{
return "value";
}
I have 2 problems
1) http://mydomain.com/values/ is not resolving
2) http://mydomain.com/values/?param1=test1 and http://mydomain.com/values/?param2=test2 are not resolving.
Could you help me to create routes for serving these urls?
routes.MapHttpRoute(
name: "Route1",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Should do what you need. Query string parameters are already mapped to Action parameters as long as they are named the same, no need to add them in the route.
First you don't need the route
routes.MapHttpRoute(
name: "Route2",
routeTemplate: "{controller}/{param1}/{param2}",
defaults: new { param1 = RouteParameter.Optional, param2 = RouteParameter.Optional }
);
Secondly to resolve http://mydomain.com/values/ you need to make parameter id optional by making it int?
// GET values/5
public string Get(int? id)
{
return "value";
}