404 on new asp.net web api, after route config is setup - c#

I have a controller which works perfectly fine:
[Authorize]
[Route("api/Version")]
public class VersionController : ApiController
{
However if I omit the Route attribute in other controllers it doesnt work, when I go to: url/api/User or Users, I get a 404
[Authorize]
public class UserController : ApiController
{
my webappi config
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Services.Add(typeof(IExceptionLogger), new AiExceptionLogger());
}
}
my routeconfig
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
}
User Controller GetUsers
[HttpGet]
public async Task<IHttpActionResult> GetUsers()
{

You seem to be defining two different configuration classes that specify different route schemes in their methods:
In WebApiConfig.Register(...), you have routeTemplate: "api/{controller}/{action}/{id}";
In RouteConfig.RegisterRoutes(...), you specified url: "{controller}/{action}/{id}".
Please note that these routes overlap each other, so you have to be careful when employing these configurations in your application.
Regarding the VersionController and UserController, it seems that it is in fact the Route attribute that is defining your route.
In VersionController, if you specify [Route("api/Version")], you are correctly able to access /api/version. If you remove this, you may be able to access /version instead of /api/version, or are you not? (This may help understanding what configuration - WebApiConfig, RouteConfig or any - is used.
Likewise, in UserController, given that you don't specify [Route("api/User")], you may be able to access /user (without the /api prefix). Can you confirm this, please? On the other hand, if you were defining the Route attribute, then you should be able to access api/user.
I am assuming that you are already mapping your controllers to endpoints, since I understood that you are able to access api/version.
This documentation is pretty good on explaining Routing in MVC projects (in this case, for .NET Core), and it explians the multiple routes approach that perhaps you are trying to achieve with WebApiConfig and RouteConfig.

Related

Implementing Attribute Routing

I'm trying to get a handle on attribute routing in MVC.
Initially, the routing for my sitemap controller was as follows:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "SitemapXml",
url: "sitemap.xml",
defaults: new { controller = "Sitemap", action = "Index" }
// Additional mappings...
}
}
That works fine. But then I tried commenting out the SitemapXml routing above and instead adding an attribute in my controller.
// GET: Sitemap
[Route("sitemap.xml")]
public ActionResult Index()
{
// Generate sitemap
}
I also added the following line at the end of RegisterRoutes:
routes.MapMvcAttributeRoutes();
But now when I navigate to domain.com/sitemap.xml, I get a page not found error.
Questions:
What steps am I missing to get my routing attribute to work?
Since mappings can now be specified in two places (as attributes or set directly in the RouteCollection), what happens when those two places contradict each other?
if you remove the extension .xml , your attribute routing will work perfectly. And its better to use the extension related code in action method.
Also make sure your route config looke like (routes.MapMvcAttributeRoutes(); should exist before default route)
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Account", action = "Login", id = UrlParameter.Optional }
);

Web API 2 routing - Route attribute

Question is regarding defining custom routes with the Route attribute.
I know that in the WebApiConfig class you always define the default route,
configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
What I cannot get working is when I want to pass another parameter. I know I can do this (code below is defined underneath the default route listed above):
//configuration.Routes.MapHttpRoute(
// name: "GetBrandImagePaths",
// routeTemplate: "api/{controller}/{id}/{type}");
But I'd rather, instead of defining all these routes in the WebApiConfig file, use custom routing. However, if I do not have the commented out code above in the file, I get a 404. Thus leading me to believe the custom Route is not even being looked at.
public class HelperApiController : ApiController
{
[HttpGet]
[Route("api/helperapi/{id}/{type}")]
public string GetBrandImages(int id, string type)
{
.....
}
}
How can I have it so I can use routes defined in the WebApiConfig file, AND defining custom routes inside individual API controllers.
Note that this project is also a MVC project (not just WebApi). Is there something I'm missing, doing incorrectly etc? I know there's numerous posts out there defining how to pass multiple params, but I think my question is a little more specific on to why one works and not the other.
You need to call config.MapHttpAttributeRoutes().
This will parse all the Controller classes and derive the routes from the attributes.
I would not mix this with the standard routing.
Attribute Routing in ASP.NET Web API 2
Enabling Attribute Routing
To enable attribute routing, call MapHttpAttributeRoutes during
configuration. This extension method is defined in the
System.Web.Http.HttpConfigurationExtensions class.
using System.Web.Http;
namespace WebApplication
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown.
}
}
}
Attribute routing can be combined with convention-based routing. To
define convention-based routes, call the MapHttpRoute method.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Attribute routing.
config.MapHttpAttributeRoutes();
// Convention-based routing.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}

ASP.net web api 2 Route-Attribute not working

I've the following problem, my route attribute is not working.
I have the following action:
[HttpGet]
[Route("~api/admin/template/{fileName}")]
public HttpResponseMessage Template(string fileName)
{
return CreateHtmlResponse(fileName);
}
and i want to access the action like .../api/admin/template/login.html, so that Template get login.html passed as the file name.
But i alsways get: No HTTP resource was found that matches the request URI 'http://localhost:50121/api/admin/template/login.html'.
The following request works: /api/admin/template?fileName=login.html
Does anyone know, what i am doing wrong with my routing?
EDIT:
My route configuration
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{action}",
new { id = RouteParameter.Optional });
You have to call MapHttpAttributeRoutes() so that the Framework will be able to walk through your attributes and register the appropriate routes upon application start:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
// you can add manual routes as well
//config.Routes.MapHttpRoute(...
}
}
See MSDN
Check your Route attribute's namespace. It should be System.Web.Http instead of System.Web.Mvc.
try adding a forward slash after the tilde
[HttpGet]
[Route("~/api/admin/template/{fileName}")]
public HttpResponseMessage Template(string fileName)
{
return CreateHtmlResponse(fileName);
}
Verify that you are using System.Web.Http.RouteAttribute and not System.Web.Mvc.RouteAttribute
Try this routing in your WebApiConfig
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
You have to add RoutePrefix.
With my Web API 2 project I had to add a [RoutePrefix("events")] to the controller for it to pickup the action route attribute.
In my case, I added Route("api/dashboard") to api controller.
Changed it to RoutePrefix("api/dashboard") . And it works perfectly.
Also you need config.MapHttpAttributeRoutes(); in webapiconfig.cs

Combining route mappings in WebApi

I am using routing in my WebApi Katana application. I have the following two route mappings that work fine. My question is, can I combine these into a single route mapping using optional parameters? I can’t see an obvious way to do it and keep the required functionality. I am new to this and may have missed a technique that my help me achieve this. If the routes have to stay this way then this isn’t a problem.
config.Routes.MapHttpRoute(
name: "UnRegister",
routeTemplate: "api/services/{serviceName}/{location}",
defaults: new {controller = "MyController", location = RouteParameter.Optional});
config.Routes.MapHttpRoute(
name: "UnRegister2",
routeTemplate: "api/services/{serviceName}/{instanceId}",
defaults: new { controller = "MyController" });
The required functionality is to unregister a service by supplying the following details:
Servicename
Servicename and location
Servicename and instanceId
In ASP.NET Web API 2 you can use attribute routing and you don't have to define all your routes that way with MapHttpRoute.
The explanation can be found here.
In your Owin Startup you have to enable the attribute routing using MapHttpAttributeRoutes:
public class Startup
{
public static void Configuration(IAppBuilder app)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
// Enable attribute based routing
config.MapHttpAttributeRoutes();
app.UseWebApi(config);
}
}
and your controller should look something like this:
[RoutePrefix("api/service")]
public class ServicesController : ApiController
{
[HttpGet]
[Route("{location}")]
public IHttpActionResult GetByLocation(string location)
{
return Ok();
}
[HttpGet]
[Route("{instanceId:int}")]
public IHttpActionResult GetByInstanceId(int instanceId)
{
return Ok();
}
}
As you can see I've used RoutePrefix to define the endpoint and route constraints to restrict parameters, as suggested in the article.
You can even create your own custom constraints.
The article suggest that you have to install the NuGet package Microsoft.AspNet.WebApi.WebHost.
That's not necessary aymore.

Catch-all route fails to find route with WebApi2 ApiController

I am creating a WebApi2 service, and one of the methods I want to implement represents an HTTP GET from an object within an internal tree structure - so the request would be along the lines of:
GET /values/path/path/to/object/in/tree
So I would want my method to receive "path/to/object/in/tree".
However, I just get a 404 when I run this, and it's interesting that I get a 404 that is different looking to the standard IIS 404. It's titled 'Server Error in '/' Application.', whereas the one for a completely invalid resource is titled 'HTTP Error 404.0 - Not Found'.
I am playing around with the default template to try and see if I can get this to work, hence the similarity.
I have this for my RouteConfig
public static void RegisterRoutes(RouteCollection routes)
{
var route = routes.MapRoute(
name: "CatchAllRoute",
url: "values/path/{*pathValue}",
defaults: new { controller = "Values", action = "GetPath" });
}
And this is my ValuesController:
[System.Web.Mvc.AuthorizeAttribute]
[RoutePrefix("values")]
public class ValuesController : ApiController
{
[Route("test/{value}")]
[HttpGet]
public string Test(string value)
{
return value;
}
[HttpGet]
public string GetPath(string pathValue)
{
return pathValue;
}
}
Interestingly, if I derive from Controller rather than ApiController it works OK, but then the normal attribute routing doesn't work.
I tried following the methodology in this post (http://www.tugberkugurlu.com/archive/asp-net-web-api-catch-all-route-parameter-binding) but I couldn't get it to work.
I'm sure I'm missing something stupidly easy, but having spent a few hours on it I thought it prudent to ask what I'm doing wrong.
Thanks
M
Web api routing is not the same as routing MVC. instead of
route.MapRoute
try
public static void Register(HttpConfiguration config) {
config.MapHttpAttributeRoutes
config.Routes.MapHttpRoute(
name: "CatchAll", routeTemplate: "values/path/{*pathvalue}",
defaults: new {id = RouteParameter.Optional });
}
The reason it works from controller is that MapRoute is the correct format for routing an MVC controller, while MapHttpRoute is designed for API controllers.

Categories

Resources