The question is as simple as the title.
Is it possible to have a route that looks like this: {controller}/{id}/{action}?
This is what I have in code right now (just a simple function) (device is my controller):
[HttpGet]
[Route("Device/{id}/IsValid")]
public bool IsValid(int id) {
return true;
}
But when I go to the following URL the browser says it can't find the page: localhost/device/2/IsValid.
And when I try this URL, it works just fine: localhost/device/IsValid/2
So, is it possible to use localhost/device/2/IsValid instead of the default route localhost/device/IsValid/2? And how to do this?
Feel free to ask more information! Thanks in advance!
You are using Attribute routing. Make sure you enable attribute routing.
Attribute Routing in ASP.NET MVC 5
For MVC RouteConfig.cs
public class RouteConfig {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
//...Other code removed for brevity
}
}
In controller
[RoutePrefix("device")]
public class DeviceController : Controller {
//GET device/2/isvalid
[HttpGet]
[Route("{id:int}/IsValid")]
public bool IsValid(int id) {
return true;
}
}
try using this before Default route in RoutingConfig
config.Routes.MapHttpRoute(
"RouteName",
"{controller}/{id}/{action}"
);
Related
I´m trying to set up a route in MVC so that when POSTing to the following url
/organizations/55/repositories
I get all the repositories for organization 55
I've tried using the following route but to no avail, it never reaches the controller action method
[Route("/organizations/{id}/repositories")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Repositories(long id, OrganizationSearchParametersDTO parameters)
However if I do it in the RegisterRoutes method, it works:
routes.MapRoute("OrganizationControllerRoute", "organizations/{id}/repositories", new {controller = "Organizations", action = "Repositories"});
But I'd prefer to have it running using attributes because it's our way to work
What am I doing wrong, any ideas?
If your routes.MapRoute(..) definition works, but not the [Route(...)] attribute, it means that you have not enabled attribute routing in the RouteConfig.cs file
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// Add the following line before any route definitions
routes.MapMvcAttributeRoutes();
... // add routes.MapRoute(...) definitions as required
}
}
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 have this class:
[RoutePrefix("api/v2/Foo")]
public class SomeController : BaseController
{
[Route("")]
[HttpGet]
public async Task<HttpResponseMessage> Get(SomeEnum? param)
{
//...
}
}
I want to call it via:
api/v2/Foo?param=Bar
but it doesn't work.
If I change the routing attribute thusly to include something in the RouteAttribute:
[Route("SomeRoute")]
[HttpGet]
public async Task<HttpResponseMessage> Get(SomeEnum? param)
{
//...
}
...then I can call
api/v2/Foo/SomeRoute?param=Bar
, but that isn't what I want.
How do I get the first circumstance to work?
EDIT:
Domas Masiulis steered me toward the answer: the above scenario DOES work, it's just that a default global routing screwed things up. I solved the issue by adding a separate default routing that matched our convention...
public static void RegisterRoutes(RouteCollection routes)
{
//ADDING THIS FIXED MY ISSUE
routes.MapHttpRoute(
name: "API Default",
routeTemplate: "api/v2/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//SOURCE OF THE ORIGINAL PROBLEM
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Administration", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
Any special conditions? Maybe something hidden in BaseController? Any custom configurations in RouteConfig?
Your given example works for me, made a quick test:
Used code:
[RoutePrefix("api/v2/Foo")]
public class SomeController : ApiController
{
[Route("")]
[HttpGet]
public Task<int> Get(int param)
{
return Task.FromResult(2);
}
}
Calling
http://localhost:1910/api/v2/Foo?param=1 works as expected - returns 2.
1) You have to specify [FromUri] attribute for query parameter
2) If you use nullable parameter like SomeEnum? setup a default value for it
[Route("")]
[HttpGet]
public async Task<HttpResponseMessage> Get([FromUri] SomeEnum? param = null)
{
//...
}
I have a blog that I have built. It uses a web api in c# .NET.
If you click here: http://www.judsondesigns.com/api/blogapi/17
You will see it return an entry from the server. How can I easily rewrite the url to use the blog title instead of the ID?
So instead you can access it via: http://www.judsondesigns.com/api/blogapi/my_blog_tite_here
I have done this with isapi rewrites in the past on linux, but wasnt clear how to in .NET. I have heard different way but would like the less is more approach here. Thanks in advance. -Judson
What you want to do is create a custom RouteBase. This code review post is a good place to start.
The jist of it is:
public class MyRoute : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
// parse url and turn into route
}
public override VirtualPathData GetVirtualPath(
RequestContext requestContext,
RouteValueDictionary values)
{
// create url from route
}
}
Which you then register along with any other routes like
routes.Add(new MyRoute());
By editing the route configuration:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{blogTitle}",
defaults: new { controller = "Home", action = "Index", blogTitle = UrlParameter.Optional }
);
}
}
or rewrite the action to use the name instead and using a named parameter
http://www.judsondesigns.com/api/blogapi/?blogtitle=my_blog_tite_here
I am creating an ASP.NET MVC 5 application and I have some issues with routing. We are using the attribute Route to map our routes in the web application. I have the following action:
[Route("{type}/{library}/{version}/{file?}/{renew?}")]
public ActionResult Index(EFileType type,
string library,
string version,
string file = null,
ECacheType renew = ECacheType.cache)
{
// code...
}
We only can access this URL if we pass the slash char / in the end of url, like this:
type/lib/version/file/cache/
It works fine but does not work without /, I get a 404 not found error, like this
type/lib/version/file/cache
or this (without optional parameters):
type/lib/version
I would like to access with or without / char at the end of url. My two last parameters are optional.
My RouteConfig.cs is like this:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
}
}
How can I solve it? Make the slash / be optional too?
Maybe you should try to have your enums as integers instead?
This is how I did it
public enum ECacheType
{
cache=1, none=2
}
public enum EFileType
{
t1=1, t2=2
}
public class TestController
{
[Route("{type}/{library}/{version}/{file?}/{renew?}")]
public ActionResult Index2(EFileType type,
string library,
string version,
string file = null,
ECacheType renew = ECacheType.cache)
{
return View("Index");
}
}
And my routing file
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// To enable route attribute in controllers
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
I can then make calls like
http://localhost:52392/2/lib1/ver1/file1/1
http://localhost:52392/2/lib1/ver1/file1
http://localhost:52392/2/lib1/ver1
or
http://localhost:52392/2/lib1/ver1/file1/1/
http://localhost:52392/2/lib1/ver1/file1/
http://localhost:52392/2/lib1/ver1/
and it works fine...
//its working with mvc5
[Route("Projects/{Id}/{Title}")]
public ActionResult Index(long Id, string Title)
{
return view();
}