I have two controllers for my User model. One is a regular MVC controller which handles the views and inherits from Controller. Then I have an API controller which inherits from ApiController. Their names are UsersController and UsersApiController respectively. I wish to remove from "Api" from the API controller's URL so I can type:
www.mywebsite.com/api/Users
rather than:
www.mywebsite.com/api/UsersApi
which contains a redundant "api".
I have tried applying the attribute [Route("Users")] and [Route("api/Users")] to the entire controller but neither work and they seem to just break it. My WebApiConfig.cs has the default route config.
How can I do this?
You should be able to use Attribute routing.
[RoutePrefix("api/users")]
public class UsersApiController : ApiController
{
[Route("")]
public HttpResponseMessage Get()
{
}
}
You should be able to customize it per action methods as well
public class UsersApiController : ApiController
{
[Route("api/users")]
public HttpResponseMessage Get()
{
}
}
Related
I'm trying create an additional Get method on a web api but the return is 404 ( method not found ).
At my APIs before Core I was creating such methods like :
[HttpGet]
[Route("api/MyNewMethodName")]
public object MyNewMethodName(string parameter1)
{}
And for call :
myURL/api/MyNewMethodName?parameter1=somestring
At my controller definition I have :
[Produces("application/json")]
[Route("api/MyController")]
public class MyController : Controller
For the exactly some code I receive the 404 error.
What is wrong please ?
Your controller has a route defined. So for your action method, it will be the route prefix defined for the controller + the route pattern for the action method. That means, with your current code, it will work for the below request
yourBaseUrl/api/MyController/api/MyNewMethodName?parameter1=somestring
Here api/MyController part is from the route definition on the controller level and the api/MyNewMethodName part is from the action method level.
Fix the route prefix at controller or method level as needed. For instance if you want your action method to respond to /api/MyNewMethodName?parameter1=somestring. Just remove the Route decorator on the controller level.
[Produces("application/json")]
public class MyController : Controller
{
[HttpGet]
[Route("api/MyNewMethodName")]
public object MyNewMethodName(string parameter1)
{
return "Sample dummy response : "+parameter1;
}
}
Keep in mind that, removing the controller level routing might break routes to other action methods in that controller. If you want to keep the existing routes as it is (with the controller level route attributes), You may update your action method level route pattern to start with a /
[Produces("application/json")]
[Route("api/MyController")]
public class MyController : Controller
{
[HttpGet]
[Route("/api/MyNewMethodName")]
public object MyNewMethodName(string parameter1)
{
return "Some test"+parameter1;
}
[HttpGet]
[Route("SecondMethod")]
public object SecondMethod(string parameter1)
{
return "SecondMethod : "+parameter1;
}
}
[HttpGet]
[Route("api/[controller]/MyNewMethodName")]
public object MyNewMethodName(string parameter1)
{
}
Try declaring the above format, this worked for me.
I have a web api controller that has two actions, but only one of them can receive requests.
public class ApiBase : ApiController
{
}
[RoutePrefix("api/Test")]
public class TestController : ApiBase
{
[HttpGet]
[Route("")]
public IHttpActionResult Get() {} // I only want this action to handle http://blah/api/Test but it's also handling http://blah/api/Test?id=1
[HttpGet]
[Route("{id}")]
public IHttpActionResult Get([FromUri] int id){} // http://blah/api/Test?id=1 couldn't reach here
}
I realized the problem is with base class. If TestController doesn't inherit from base class, it works as expected. What's missing from my base class?
Your attribute routing definition has a routing pattern api/Test/{id} mapped to the second Get method. So you should be accessing it like /api/test/34
When using attribute routing , the default routing with the querystrings and ? won't work. You should use the pattern defined in the attribute route definition.
/api/test/34 will work for Get([FromUri] int id){}
/api/test/ will work for Get() {}
I have an ASP.NET MVC app. I have seen similar question asked. However, I haven't found a good answer. Essentially, I want to use the following routes:
/admin/users
/admin/users/create
/admin/users/[someId]
/admin/roles
/admin/roles/create
/admin/roles/[someId]
I have the following file structure:
/Controllers
AdminController.cs
/Admin
UsersController.cs
RolesController.cs
/Views
/Admin
Index.cshtml
/Users
Index.cshtml
Detail.cshtml
Create.cshtml
/Roles
Index.cshtml
Create.cshtml
Detail.cshtml
When I run my app, I just get The resource cannot be found.
What am I doing wrong? I set breakpoints, but none of them are being hit. It's like the routes aren't mapping to the controllers. I'm not sure what I need to do though.
You do not need to create sub folders for this to work. Just have 2 controllers(UsersController and RolesController) and you can use attribute routing to define the custom routing pattern you want.
Assuming you have attribute routing enabled
public class UsersController : Controller
{
[Route("admin/users")]
public ActionResult Index() { // to do : Return something }
[Route("admin/users/create")]
public ActionResult Create() { // to do : Return something }
[Route("admin/users/{id}")]
public ActionResult View(int id) { // to do : Return something }
}
Or you can do the RoutePrefix on the controller level.
[RoutePrefix("admin/users")]
public class UsersController : Controller
{
[Route("")]
public ActionResult Index() { // to do : Return something }
[Route("create")]
public ActionResult Create() { // to do : Return something }
[Route("{id}")]
public ActionResult View(int id) { // to do : Return something }
}
You can do the samething for the RolesControllers as well.
You can enable attribute routing in the RegisterRoutes method in RouteConfig.cs file.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes(); //This line enables attribute routing
//Existing default Route definition goes here
}
You may also consider creating an "Admin" area and put your controllers inside that. Areas are the right solution if you want to logically group similar functionality.
If you do not prefer attribute routing ( why not ?) , you an define these custom route patterns in your RouteConfig. The order in you define the route matters.So make sure you define your specific routes before the default generic one.
You can also override your route tables by decorating your action methods with the RouteAttribute class.
For example:
class AdminController
{
[Route("/admin/users/create")]
public ViewResult CreateUser()
{
...
}
}
This has the advantage of separating the method name from the url component.
You can also route multiple URLs to a single method:
class AdminController
{
[Route("/admin/users/{someId:guid}")]
[Route("/admin/users/{someId:guid}/details")]
public ViewResult UserDetails(Guid someID)
{
...
}
}
As mason said, the file structure isn't important in MVC routing.
If you want to use convention (folder) based routing, you could use MvcCodeRouting to do exactly what you have specified here. It uses namespaces by default, so when you add controllers in a hierarchy, it will generate routes in the same hierarchy automatically. No need to apply the [Route] attribute everywhere and setup your routes manually.
I am working on an asp.net 5 mvc api, and I am currently working on the Accounts Controller.
since I saw in many different places that there is a convention of using /api/Tokenrouting to a login in a web api. I would like to route to that specific method without the accounts prefix, I would prefer not using a different controller, and I would prefer using Attributes over routing in Startup.cs to avoid confusion in the future.
this is what I have currently
[Route("api/[controller]")]
public class AccountsController : Controller
{
[HttpPost("login")]
public async Task<JwtToken> Token([FromBody]Credentials credentials)
{
...
}
[HttpPost]
public async Task CreateUser([FromBody] userDto)
{
...
}
}
With attribute routing you can use a tilde (~) on the Action's route attribute to override the default route of the Controller if needed:
[Route("api/[controller]")]
public class AccountsController : Controller {
[HttpPost]
[Route("~/api/token")] //routes to `/api/token`
public async Task<JwtToken> Token([FromBody]Credentials credentials) {
...
}
[HttpPost]
[Route("users")] // routes to `/api/accounts/users`
public async Task CreateUser([FromBody] userDto) {
...
}
}
For ASP.NET Core it seems that the tilde ~ symbol (see accepted answer) is not needed anymore to override the controller's route prefix – instead, the following rule applies:
Route templates applied to an action that begin with a / don't get combined with route templates applied to the controller. This example matches a set of URL paths similar to the default route.
Here is an example:
[Route("foo")]
public class FooController : Controller
{
[Route("bar")] // combined with "foo" to map to route "/foo/bar"
public IActionResult Bar()
{
// ...
}
[Route("/hello/world")] // not combined; maps to route "/hello/world"
public IActionResult HelloWorld()
{
}
}
from https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing
[Route("[controller]/[action]")]
public class HomeController : Controller
{
[Route("~/")]
[Route("/Home")]
[Route("~/Home/Index")]
public IActionResult Index()
{
return ControllerContext.MyDisplayRouteInfo();
}
public IActionResult About()
{
return ControllerContext.MyDisplayRouteInfo();
}
}
In the preceding code, the Index method templates must prepend / or ~/ to the route templates. Route templates applied to an action that begin with / or ~/ don't get combined with route templates applied to the controller.
I just have one quick question about what seems to have been a limitation with ASP.NET Web API Attribute Routing, but hoping I just suck at research. In my controller, I'm trying to do something like this:
public class OrdersController : ApiController
{
[HttpGet]
[Route("{apiRoot}/customers/{id:int}/orders")]
public IHttpActionResult GetCustomerOrders(int id) {...}
}
Where {apiRoot} is defined in either a configuration file.
This may not actually be necessary, but I'd like to know how to put a specific path in the route attribute without having to code a static path. Is the general idea here supposed to be that you only put text into the route path, except for your parameters which go in {}?
How about switching to using a RoutePrefix:
[MyRoutePrefix]
public class OrdersController : ApiController
{
[HttpGet]
[Route("customers/{id:int}/orders")]
public IHttpActionResult GetCustomerOrders(int id) {...}
}
public class MyRoutePrefixAttribute : RoutePrefixAttribute
{
public MyRoutePrefixAttribute()
{
Prefix = "the route prefix";
}
}
RoutePrefixAttribute isn't sealed like RouteAttribute so extending it should allow you do what you need. Assuming, of course, that all of the controllers in a single class using the same root path.
Note: I haven't had a chance to try this but given what I know of attribute routing, I don't see why it shouldn't work.