Routing Config for Web-API - c#

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 } );

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

custom route with namespaces

this might be a stupid question but is it possible to add a namespace before the "api" on route?
i have this current code:
config.Routes.MapHttpRoute(
name: "Api",
routeTemplate: "{namespace}/api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
this "works" but it accepts any words i enter for the {namespace}. i want to add {namespace} on my route because there are controllers with the same name from different namespaces.

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.

WebAPI accepts broken JSON send via Fiddler

For some reason I can send these two JSON requests to my WebAPI and it'll accept and create an User. One with double quotes and one without.
{"Username":"Bob", "FirstName":"Foo", "LastName":"Bar", "Password":"123", "Headline":"Tuna"}
{Username:"Bob", FirstName:"Foo", LastName:"Bar", Password:"123", Headline:"Tuna"}
This is the method which creates an User.
// localhost:12345/api/controller/create
[ActionName("create")]
public HttpResponseMessage PostUser(User user)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, user);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = user.UserId }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
However I'm able to make a successful POST request without the /create at the end of URL. I'm assuming that the reason for the success POST request is because whether or not the action name is present it will search for a Post in the method name.
So my question is, what's the purpose of the action name then? How can I make it so it's a must in the URL? Also why is it accepting both JSON requests and how can I make it accept one or the other.
EDIT:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Routing by Action-name
config.Routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{username}",
defaults: new { username = RouteParameter.Optional }
);
Thank you for your time
/twice
How can I make it so it's a must in the URL?
By changing your route definition in ~/App_Start/WebApiConfig.cs and making the action name explicitly appear in your route:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Also why is it accepting both JSON requests and how can I make it accept one or the other.
Because the Web API uses JSON.NET as JSON serializer which accepts both of them.
If you look in App_Start for the route that's registered for your API calls you'll see:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You'll notice that no action is specified. If you want to map to action names, you can change it to:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "get", id = RouteParameter.Optional }
);
But then you'll always be required to set an action (unless it's a GET which is the default). You can no longer POST directly toe controller, you'll always need to add an action.
Per this link the default behavior is to look for a method that starts with the HTTP method used:
To find the action, Web API looks at the HTTP method, and then looks
for an action whose name begins with that HTTP method name. For
example, with a GET request, Web API looks for an action that starts
with "Get...", such as "GetContact" or "GetAllContacts". This
convention applies only to GET, POST, PUT, and DELETE methods. You can
enable other HTTP methods by using attributes on your controller.
We’ll see an example of that later.
Another option is to create different controllers for your different GET calls, which is what I've done in the past.

how would one route this using Asp.Net WebAPI?

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

Categories