I have a route with an optional parameter:
[Route("{categoryId?}")]
public HttpResponseMessage Get(int? categoryId=null)
However, when I don't provide a value for categoryId the call includes {categoryId?} in the request itself...
http://myhost/api/%7BcategoryId%7D
Swagger has no support for optional path parameters. If you wish to document it this way, you'd have to create two separate paths - one without the path parameter and one with.
Related
I'm using attribute routing for a current project and in a few of the routes, I'm using some optional parameters. So for a URL like...
/detail/H40466/wood-to-wood-foundation-and-boxspring-frame-assembly
With its route definition like...
[Route("detail/{productName}/{applicationSlug?}")]
The wood-to-wood... is an optional parameter. What I'm wanting to do (if possible) is to have a static value only show up if the second parameter is present. Something like...
/detail/H40466/for/wood-to-wood-foundation-and-boxspring-frame-assembly
Where the word for is only part of the url when the last optional parameter is present. Is there any mechanism available to accomplish this beyond setting up another action that maps to that route?
You can define 2 different routes for the same action method. In that case, the "optional" parameter should be required for one route and not present on the other.
[Route("detail/{productName}/for/{applicationSlug}", Order = 1)]
[Route("detail/{productName}", Order = 2)]
I currently have a set of action methods in a web api controller that use Attribute Routing.
[RoutePrefix("Paper")]...
[Route("Shape/Octagon/{id:minlength(1)}]
public IEnumerable<sampleShape> PostactionName(string id){..}
[Route("Shape/Hexagon/{id:minlength(1)}]]
public IEnumerable<sampleShape> PostactionName(string id){..}
which would work for the following URIs
api/Paper/Shape/Octagon/"1,2,3"
api/Paper/Shape/Hexagon/"3,2,1"
but becomes unusable once the id parameter becomes to long. Is there anyway to have routing use the parameter id as a form data rather than part of the URI but still keep the Route attribute.
You can use FromBody attribute to let the engine know that parameter will come from post body
[RoutePrefix("Paper")]...
[Route("Shape/Octagon"}]
public IEnumerable<sampleShape> PostactionName([FromBody]string id){..}
[Route("Shape/Hexagon"}]]
public IEnumerable<sampleShape> PostactionName([FromBody]string id){..}
I have the following code
[HttpGet]
[Route("publish/{id}")]
public IHttpActionResult B(string id, string publishid=null) { ... }
So as far as I understood,
~/..../publish/1?publishid=12
~/..../publish?id=1&publishid=12
Should work and bind both parameters but it won't work on the second case.
In the first case, publishid will not be bound.
So I do not understand why this is not working. Any idea why it is in this way?
The second case will not work because id is a required variable in the route template publish/{id}. In Web API first route template matching happens and then the action selection process.
other cases:
publish/1 - will not work as action B is saying that publishid is required. To prevent this you can change the signature of action to be something like B(string id, string publishid=null) and only id is bound
publish/1?publishid=10 - works as expected where both are bound.
This is a simple issue with managing many methods across an asp.net web api project.
We have quite a few methods like this:
ProductsApiController.GetByType(string type, string x)
ProductsApiController.GetByType(string type, int limit)
//method has a number of arguments..
ReportsApiController.GetAll(string x, string y)
The problem: We have a ton of methods with custom parameters and we have to define a custom route for each of them
routes.MapRoute(
name: "ProductRoute",
url: "ProductsApiController/{type}/{x}"
);
routes.MapRoute(
name: "ReportRoute",
url: "ReportsApiController/{x}/{y}"
);
I'm simplifying the signatures, there are many methods with a lot of params and these methods don't usually have params in common.
What is the general pattern to this? Is there a better way to do this or am I only left with this.
I'd say for your scenario, the most logical solution would be to use attribute routing.
Yes, it would still mean you have to create a lot of routes, but since they are effectively tied to a single action, it makes most sense to have the route in an attribute decorating this action.
You can get AR from Nuget:
PM> Install-Package AttributeRouting.WebApi
In your case it would look like this:
[GET("mytype/{type}/{x}")]
public MyType GetByType(string type, string x)
[GET("mytype/{type}/{limit}")]
public MyType GetByType(string type, int limit)
and so on...
which, IMHO is much more manageable
A while ago I wrote an intro post to AR - http://www.strathweb.com/2012/05/attribute-based-routing-in-asp-net-web-api/
You can also visit their excellent wiki - https://github.com/mccalltd/AttributeRouting/wiki
This is a case where passing URI parameters in the query string becomes really handy. You could define just one route and then have all the URI parameters for that action passed in through the query (e.g. ReportsApi/GetAll?x=5&y=6). You would just define a route with a path template that also includes the action ({controller}/{action}).
Otherwise, if you want all the parameters passed in within the path in different ways, I can't think of a better way. Because you have to let the routing system know where to get each parameter and what parameter name it should bind to. There isn't a convention for deciding on a parameter name the way there is for query string parameters. You could look into Filip's good suggestion of using attribute routing below. It won't reduce the number of routes you'll have to write, but at least they'll be closer to the code where you need them.
Some MVC sites have querystring params appended to the route Url (of which I noticed StackOverflow does), such as:
https://stackoverflow.com/questions/tagged/java?page=9802&sort=newest&pagesize=15
What are the advantages of having the parameters as more conventional ?querystring params, rather than /param/values/ ?
Also, how are these params appended to routes that have been set up? I'm familiar with setting up mvc routes with params like "users/details/{id}" etc. but don't know how to configure routes for use with 1 or more ?params as per the example url above?
Query string parameters are useful when you have multiple optional parameters and don't want to include default values for non-specified parameters just to satisfy a path.
And you don't have to do anything special to include these parameters in a rendered URL.
Take the following route for example:
routes.MapRoute
(
"QuestionsTagged",
"questions/tagged/{tag}",
new { controller = "Questions", action = "Tagged" }
);
If you render a link to that route using:
Url.RouteUrl
(
"QuestionsTagged",
new
{
tag = "java",
page = 9802,
sort = "newest",
pagesize = 15
}
)
...then the routing engine is smart enough to see that the route contains a parameter named tag and that the passed route values object also has something named tag so it uses that value in the route.
Any provided route values that don't have corresponding parameters in the route (page, sort and pagesize in this case) get tacked on as query string parameters. So the Url.RouteUrl call above would return /questions/tagged/java?page=9802&sort=newest&pagesize=15.
And your action method can explicitly list these parameters in its signature (promotes readability and maintainability) or you can access them via Request.QueryString.
public class QuestionsController : Controller
{
// I can explicitly list the parameters in my signature and let routing do
// its magic, like this...
public ViewResult Tagged(string tag, int? page, int? pagesize)
{
// ...or I can grab parameters like this:
string sort = Request.QueryString["sort"];
return View();
}
}
Note that the parameters to the action method do not have to match the parameters specified in the route. (In the route, I only specified tag, but the action method's signature lists tag, page, and pagesize.) However, any parameter of the action method that is not also a parameter of the route must be a reference or nullable type.
I've normally seen paging and filtering data be passed as querystring parameters since it gives information to the user in the URI. It is also normally harmless if a user alters this data since it will just filter the data you see on the page. Any sensitive data is normally posted so as it is not as easily seen or modified, but I would argue to keep your URI's clean and use quesrystrings as little as possible.
You don't need to do anything special when specifying routes to be able to handle quesrystrings. They will just be extra data that is passed to your action. On your action you will need to do some work to handle the data though. Using your querystring above you will have to specify the querystring names as the parameter names and then whatever datatype you are expecting.
public ActionResult Index (int page, string sort, int pagesize)
In this example, page will be the value of 9802, sort will be "newest" and pagesize will be 15.