Does Attribute Routing with Conventional mapped routes make sense - c#

We have many web api solution with 2 projects. One project sets up the web api config stuff and the other project contains the controllers.
Each web api config is setup with this:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
As we use Route/Prefix-Attributes on every controller/action I asked myself does the config.Routes.MapHttpRoute method call still take effect?
Actually as soon as I annotate a Route Attribute on the controller at least I overwrite the convention behavior of the web api. Thus the method call is obsolete.
Is that correct? Or is there still something to consider, because I want to remove this method call in every project.

The convention-based route will still be applied. Your attribute-based routes will take precedence (because they are configured first) but if an action method has both matching attribute routes and conventional routes, both routes will map to the action in question.
If you want to use exclusively attribute-based routing, removing the convention-based route mapping is probably a wise move in order to prevent unexpected behaviour (i.e. exposing actions under unintended routes).
Of course, you will want to be sure that you're not inadvertently relying on convention-based routing anywhere first!

Related

Running Angular 2/4 Route instead of .net Core route

in my Angular Module I have the following Route:
{ path: "something/:id", component: SomeComponent }
which runs fine when using "routerLinks" frontend, but as soon as I manually write the ID in the URL and press Enter, It runs the C# backend method instead and ignores the angular route.
[HttpGet("{myid:guid}")]
The backend method returns Json as it should but I cant get my Angular route to display my component, seeing I go straight to the Controller.
So my question is: How do I tell my application to run my frontend route instead of my backend route, or work my way around this problem when manually writing the id in the url?
Any help would be greatly appreciated.
I realise this isnt strictly answering your question, but unless you have a specific requirement to handle them on similar routes, isnt it simpler to serve your API on a clearly distinct route using a subdomain or specific base url fragment?
E.g. front end routes go on:
www.example.com
API routes go on:
www.api.example.com or www.example.com/api/
Note that if you cant use the subdomain option, you'll need to configure URL rewrites in your web.config to route between your API and front end.
Have you tried configuring your startup.cs? On the configure method try:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});

MVC5 / WEBAPI 2 routing HomeApiController to /api/home rather than /homeapi

I have an existing webapi 2 application that needs a basic front end adding. The existing webapi controllers have been created in the Controllers directory root named xController yController.
Controllers
-XController.cs
-YController.cs
with the following route
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}"
);
Each one of these controllers needs an accompanying MVC controller. What i would like to do is to rename the API controllers to XApiController YApiController and use routing to ensure existing usages of the service done break. Then I can add standard MVC controllers for the front end.
Controllers
-XApiController (previously XContoller)
-XController
-YApiController (previously YController)
-YController
Can you not just use the RoutePrefix attribute to do this? then you can call your controllers whatever you want and just have the attribute decide where it should be hosted, there are pros and cons to controlling your routing at the controller level but it seems to be a common use case, so for example:
[RoutePrefix("api/home")]
public class SomeHomeController: ApiController
{
// ...
}
Controllers are separate types in each framework, and each framework can discover them regardless of their location (provided they have the right name). There is no reason to mess with routing to get your desired result. The only thing you need (assuming it is acceptable) is to put your controllers into a different namespace/folder so you can have 2 controllers (MVC and Web API) with the same name.
ApiControllers
-XController
-YController
Controllers
-XController
-YController
If you ask me, it is still better to keep the MVC and API controllers in a separate location even if you cannot deploy them as separate applications.

Web api versioning method

I have read many links over the internet about web api versioning and every blog post or resource I have found is very clear about how to implement this feature.
However, unfortunately, I have to implement this feature for an API which is already in production and that does not respect any of the solutions I have read until now.
This API has a base address like http://api.server.com and handle more than one resource. These resource all have been routed by ASP.NET attribute routing like {resource}/{id}. For example
POST http://api.server.com/peoples/new
GET http://api.server.com/peoples/5
Actually the web api configuration is very simple like the following
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
I have been assigned the task to reenginer this api and would like to create and implement a new versioning scheme that sits side by side to the existing one.
I would like to use the url versioning method in a way that next realease will have the version in the url like
POST http://api.server.com/{version}/peoples
GET http://api.server.com/{version}/peoples/5
and implement a better adherence to restful recommendations in this new version (like removing the verb from the url for example).
How can I obtain this? Could you give some recommendations, examples or link to read which explain how to implement this feature and leave the actual version working?

What is the difference between the way routes are registered with MVC and Web API?

In my MVC and WebAPI application I see two different ways of doing routes.
One for MVC which calls RegisterRoutes and passes RouteTable.Routes
One for Web API which calls CustomizeConfig and passes GlobalConfiguration.Configuration.
For WebAPI:
WebApiConfig.CustomizeConfig(GlobalConfiguration.Configuration);
public static void Register(System.Web.Http.HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: ApiControllerOnly,
routeTemplate: "api/{controller}");
}
For MVC:
RouteConfig.RegisterRoutes(RouteTable.Routes);
public static void RegisterRoutes(System.Web.Routing.RouteCollection routes)
{
routes.MapRoute("DefaultRedirect",
"",
new { controller = "Home", action = "Index" });
}
Can someone explain if there is any difference in me registering my routes in one or the other method calls? Also why is it done this way with one using.
MVC routes register with ASP.NET (system.web) route collection. Web API however is designed to run either in IIS on top of system.web or as a self host without changing the code.
Hence Web API has a different registration mechanism, where it can use the system.web routing under the hood, or it's own routing system when using self hosting (Either WCF self host, or Owin host are supported out of the box).
There is one other small difference, Web API routes require naming of the route, where MVC routes do not.
One of the significant differences in the web API compared to traditional ASP.NET MVC controllers is how the web API will route request into the action methods.
With the web API, the HTTP method being used plays a role. The HTTP method is the verb used in the HTTP message and the common verbs are get, post, put, and delete. Those are the verbs that the web API will route by default. You an also handle additional verbs if you need to do something like webDAV. You can do that and handle additional verbs by using an except verbs attribute.
What the web API will do is if there is a request for "/movies", the web API will look for a movie controller and then look for a method on that controller starting with the word "Get." So I could have an action called get movies and because this is an HTTP get message, the framework will invoke get movies. But you could also call it GET whatever is just because it starts with the letters G-E-T that's why that particular action method will receive the request.
The web API also registers these routes slightly differently since there is no action that's going to be in the URL for the routing engine to pick apart, it's using the verb instead. If you look at the default route configuration for a web API, it's done with an extension method MapHttpRoute.
For Web API it is:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
For MVC, it is:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Notice that for Web API there is no action in the URL template and it's also important to note that the path of this needs to start with "api".
After looking at this, the proper way to reach a controller (say Movies) is to use /api/movies as a URL on the browser. That will invoke the get method since we have a get request.
Note: Web API controllers inherit from System.Web.Http.Controller, but MVC controllers inherit from System.Web.Mvc.Controller. Both the libraries are different but acts in similar fashion. Web API's MapHttpRoute is defined as an extension method in System.Web.Http class. MVC's MapRoute is defined in System.Web.Mvc as an extension method.

How to know when Web API Routing Engine Doesn't Find a Matching Service?

I'd like to log the requests to my Web API application that results in 404 (which means the routing engine couldn't find a matching service).
How would that be possible?
For example, if I have the below mapping:
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new
{
id = RouteParameter.Optional
}
);
then calling the below will return 404:
api_rootNotValid/controllername
I want to capture such requests and log them.
I've created a class inheriting from DelegatingHandler but only when the routing engine succeeds finding a service then it goes into the DelegatingHandler.
So I think there should be something else that can help?
I think this is a tricky thing to do...some info which you might need to consider:
Route matching happens at different stages when compared to WebHost(IIS) and SelfHost. Web API Stack Diagram for reference.
WebHost - happens even before any message handlers are run. So your
delegating handler wouldn't even be executed if a route doesn't
match.
SelfHost - happens after the message handlers are run and at
the HttpRoutingDispatcher. In this case your Delegating handler would
be executed and could probably check for the response's status code,
but even this is error prone due to the next point.
A 404 response could be due to route not being matched or if the route matched but some application level code has responded with 404 (ex: api/Products/10 can return 404 if product with id 10 was not found). So here the task is to find whether the route matching generated the 404 or the application level code.

Categories

Resources