how would one route this using Asp.Net WebAPI? - c#

I'm making a Restful service in Which I have a list of items, which could be queried as such:
GET Api/Items
Which lists all items.
But of course I'd also need these items to be listed as 'most popular', or 'belonging to user x' or 'belonging to category Y'
When glancing at the stackoverflow 2.0 api to see how they solved this they named their URLS as following:
GET Api/Items/MostPopular
And this methodology I'd like to adopt as well as it does seem to make sense and looks good.
However, How can I configure Web-API to allow this URL syntax as well?
The default route is as following:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
So I would guess that I need to add my extra routing in front of it.
I could do it like this: (If this even works)
config.Routes.MapHttpRoute(
name: "SpecializedApi",
routeTemplate: "api/{controller}/MostPopular",
defaults: new { id = RouteParameter.Optional }
);
But then it would add the MostPopular bit for all my controllers which I don't like.
Does something like this work?
config.Routes.MapHttpRoute(
name: "SpecializedApi",
routeTemplate: "api/Items/MostPopular",
defaults: new { id = RouteParameter.Optional }
);
And is this really the way to go as my routing table would quickly become very big and possibly unmaintainable?

The best would be to add another get action and configure a generic route rather then a specific route.
First add action for most popular
// add action for Most Popular
[ActionName("MostPopular")]
public MyResult GetMostPopular()
{
return null;
}
Setup route to handle the action.
// Controller with ID
// To handle routes like `/api/Items/1`
config.Routes.MapHttpRoute(
name: "ControllerAndId",
routeTemplate: "api/{controller}/{id}",
defaults: null,
constraints: new { id = #"^\d+$" } // Only integers
);
// Controllers with Actions
// To handle routes like `/api/Items/MostPopular`
config.Routes.MapHttpRoute(
name: "ControllerAndAction",
routeTemplate: "api/{controller}/{action}"
);

Probably the best maintainable if you do not deviate from the default to much,
however you should specify the controller and action in the route like this:
config.Routes.MapHttpRoute(
name: "SpecializedApi",
routeTemplate: "api/Items/MostPopular/{id}",
defaults: new { controller = "wheretogo",
action = "wichactiontotake",
id = RouteParameter.Optional
}
);
or this works too:
config.Routes.MapHttpRoute(
name: "SpecializedApi",
routeTemplate: "api/test/{action}/{id}.html",
defaults: new { controller = "test" }
);
Check out this link when using fake files for configurating the IIS:
http://haacked.com/archive/2008/11/26/asp.net-mvc-on-iis-6-walkthrough.aspx

Related

C# WEBApi MVC Help pages

I have a custom route below and action.
[System.Web.Mvc.Route("Sites/{id:string}/Cache")]
public ResponseMessage<Result> DeleteCache ([FromUri] string id)
{
and when I got the the help page it gives three examples to use this call:
DELETE Sites/{id}/Cache
DELETE Sites/{id}
DELETE api/Sites/DeleteCache?id={id}
I'd like to keep the first one and remove the others. Is there a built in way to do this?
Here is my WebApiConfig.cs snippit....
config.Routes.MapHttpRoute(
name: "DeleteCache",
routeTemplate: "{controller}/{id}/Cache",
defaults: new { controller = "Sites", action = "DeleteCache" }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
HelpPage will list every valid route for each controller. If you want a route to not apply to a specific controller you have to add contraints to the route to make it not match anymore :
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: new {controller = "((?!Sites).)*" }
);
This uses a negative lookahead regex to match every Controllers not named Sites

Routing Config for Web-API

I am creating a Web-API service using .Net 4.5.2.
I want to have the following URIs:
/api/v1/timeseries/{id}
/api/v1/timeseries/approval/{id}
With this, I expect to have two controllers:
TimeSeriesController
TimeSeriesApprovalController
Using default routing as below, I achieve my first desired outcome (/api/v1/timeseries/{id}), but I'm not sure how to achieve the second outcome. Can someone please show me how to amend the route config to deal with the second URI?
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/v1/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
One option would be to use your existing routes, and use the url like:
/api/v1/timeseriesapproval/{id}
Note that this perfectly matches your existing route:
"api/v1/{controller}/{id}",
where controller matches timeseriesapproval.
Another option would be to setup a new route (prior to your existing one) specific for this need:
config.Routes.MapHttpRoute(name: "PutThisBeforeYourExistingOneApi",
routeTemplate: "api/v1/timeseries/approval/{id}",
defaults: new { controller = "TimeSeriesApproval", id = RouteParameter.Optional } );

How to serve POST request to http://domain_name.com using ASP.NET using a controller

I need to serve POST requests to http://domain_name.com using custom code (i.e. controller)
I understand that I can configure to serve POST requests to a route like
http://domain_name.com/api/SomeController/id
using
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
But I want to serve POST request to http://domain_name.com
How do I do that ?
Please do not downvote without pointing me to answer or a reason.
You can map some controller as default
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "{controller}/{id}",
defaults: new {controller="values", id = RouteParameter.Optional }
);

web api versioning with default link

I have web api with two version v1 and v2, they are like folders in controllers, these folders contains controllers with same names and methods.
My WebApiConfig looks like this
config.Routes.MapHttpRoute(
"DefaultApi",
"api/v{version}/{controller}/{id}",
new {id = RouteParameter.Optional}
);
config.Services.Replace(typeof(IHttpControllerSelector), new HttpControllerSelector((config)));
Respectively my links looks like api/v1/custum/get?id=3 and api/v2/custum/get?id=3, how I can do navigation in link api/custum/get?=3 at last version i.e. at v2/custum/get?id=3
You can set the default value for the version parameter like this
config.Routes.MapHttpRoute(
"DefaultApi",
"api/{version}/{controller}/{id}",
new
{
version="v2",
id = RouteParameter.Optional
}
Have a route config for versioned API and a fallback config. For example,
config.Routes.MapHttpRoute(
name: "VersionedApi",
routeTemplate: "api/{version}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
The first one maps the calls with specific version. The second one has no version in the route. In your HttpControllerSelector, try to get value for version, if it is not there for the second route config, set it to a default version.

Web Api routing trouble

I have an self hosted Web API project, so I had to use Yao's blog post to make help page work. Next, I've had to secure some of my methods from unauthorized use. I've implemented this idea.
Now the fun part. I have 3 routes:
/help which leads to Help Page,
/authentication/authenticate is used to call authentication method and it expects user credentials and returns security token in case of success
and /transaction/{action}/{id} this route needs to be secured from unauthorized use.
So basically, I need to make all routes, where controller = transaction, to be processed by TokenInspector.
1. Scenario: if I have routing configuration like this:
_config.Routes.MapHttpRoute(
name: "AuthenticatedOnly",
routeTemplate: "transaction/{action}/{id}",
defaults: new {controller = "Transaction", action="GetNewTaskId", id=RouteParameter.Optional},
constraints: null,
handler: tokenInspector
);
_config.Routes.MapHttpRoute(
"Default",
"{controller}/{action}/{id}",
defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
);
Everything works fine, except Help page shows only POST Authentication/Authenticate
entry
2. Scenario: if I change routing config to:
_config.Routes.MapHttpRoute(
name: "AuthenticatedOnly",
routeTemplate: "transaction/{action}/{id}",
defaults: new {},
constraints: null,
handler: tokenInspector
);
_config.Routes.MapHttpRoute(
"Default",
"{controller}/{action}/{id}",
defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
);
Help page works fine and shows all the methods, but /transaction is not secured anymore and is working without token.
3. Scenario:
_config.Routes.MapHttpRoute(
name: "AuthenticatedOnly",
routeTemplate: "transaction/{action}/{id}",
defaults: new {id=RouteParameter.Optional},
constraints: null,
handler: tokenInspector
);
_config.Routes.MapHttpRoute(
"Default",
"{controller}/{action}/{id}",
defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
);
Works both authentication and help page, but when I make request like /Transaction/GetNewTaskId with valid Token in it's header, I get 404.
Update
Could anyone explain, how help page generation depends on registered routes? Is there any way to tweak it and enforce ApiExplorer to print out controller contained stuff?
Update 2
After some more struggling and investigating, I found a solution, which matches my goal - to keep documentation as well as security pattern.
I've implemented a custom message handler (basically, I used my TokenInspector, but added url filtering to it's logic).
So, I have single route now:
_config.Routes.MapHttpRoute(
name: "Default",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { controller = "Help", action = "Index", id=RouteParameter.Optional }
);
and this is how I launch the server:
_config = new ExtendedHttpSelfHostConfiguration(ServiceAddress);
TokenInspector tokenInspector = new TokenInspector() { InnerHandler = new HttpRoutingDispatcher(_config) };
_server = new HttpSelfHostServer(_config, tokenInspector);
ConfigureHost(_config);
_server.OpenAsync();
Probably, the question as it was, could not be answered in this way, but anyway, thank you all for your effort!
Regards, insomnium_
//This is for your public controllers
//this route will ONLY catch requests for Help and Authentication controllers only
//you will need to include any new public controller that uses the route pattern
_config.Routes.MapHttpRoute(
name: "Public",
routeTemplate: "{controller}/{action}/{id}",
constraints: new { controller = #"^(Help|Authentication)$" },
defaults: new { controller="Help", action="Index", id = RouteParameter.Optional}
);
//Everything that is not Help or Authentication will use this route, which will check for the valid token you mention
//This route is defaulting to /Transaction/GetNewTaskId
_config.Routes.MapHttpRoute(
name: "AuthenticatedOnly",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { controller = "Transaction", action="GetNewTaskId", id=RouteParameter.Optional},
handler: tokenInspector
);
Use this approach for more flexible method access management
config.Routes.MapHttpRoute(
name: "PublicMethods",
routeTemplate: "api/{controller}/{action}",
constraints: new {action = #"^(public)-(.)*$"},
defaults: new {controller = "Account"}
);
config.Routes.MapHttpRoute(
name: "PublicControllers",
routeTemplate: "api/{controller}/{action}",
constraints: new {controller = #"^(Environment|Account)$"},
defaults: new {controller = "Account"}
);
config.Routes.MapHttpRoute(
name: "AuthorizedUsersOnly",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional },
constraints: null,
handler: tokenInspector
);
So I have few open for each user controllers and if it's necessary I make some methods accessible for not authorized users by adding 'public' prefix to action name

Categories