Currently I am using the default route but I need a route that works like this:
localhost/Admin/Users/Index
localhost/Admin/Users/Add
localhost/Admin/Users/Delete
Where index add and delete are views with controllers in the AdminController.cs
The current structure everywhere else is fine, as it doesn't require multiple subdirectories.
Currently I have the the file I need to start with in:
{Project}/Views/Admin/Users/Index.cshtml
How would I create this route and how do I apply it to the controller?
Am I approaching this incorrectly?
This can be easily resolved using Route attributes, like:
[Route("Admin/Users/Edit/{id?}")]
public ActionResult TestView(string id)
{
if (!string.IsNullOrEmpty(id))
{
return View(“OneUser”, GetUser(id));
}
return View(“AlUsers”, GetUsers());
}
MSDN: https://blogs.msdn.microsoft.com/webdev/2013/10/17/attribute-routing-in-asp-net-mvc-5/
You can register another route specifying the route path and the controller in RegisterRoutes:
routes.MapRoute(
name: "Admin",
url: "{controller}/Users/{action}/{id}",
defaults: new { id = UrlParameter.Optional },
constraints: new { controller = "Admin" }
);
To handle your directory structure you need to extend the default view engine to add the new view paths:
public class ExtendedRazorViewEngine : RazorViewEngine
{
public ExtendedRazorViewEngine()
{
List<string> existingPaths = new List<string>(ViewLocationFormats);
existingPaths.Add("~/Views/Admin/Users/{0}.cshtml");
ViewLocationFormats = existingPaths.ToArray();
}
}
And register the engine in Application_Start:
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ExtendedRazorViewEngine engine = new ExtendedRazorViewEngine();
ViewEngines.Engines.Add(engine);
...
}
Related
I want the default action method to be called in route.config should be the action method of an area. So I have done something like this:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
routes.MapRoute(
name: "Default",
url: "{culture}/{controller}/{action}/{id}",
defaults: new { culture = "en", controller = "LocationCon", action = "LocationIndex", id = UrlParameter.Optional },
namespaces: new[] { "Locator.Areas.LocationArea.Controllers" }
);
}
Here - LocationIndex is the action name, LocationCon is the controller and LocationArea as area.
This is not working. Any help would be appreciated.
I think that No resource found error originated from MVC view engine, where your view engine still using default parameters to find proper cshtml file even action methods executed successfully.
AFAIK, by default MVC view engine searching view files in Project/Views/ControllerName and Project/Views/Shared directory, which your Project/Culture/ControllerName doesn't included.
You can configure custom view engine to search corresponding view files like example below:
using System.Web.Mvc;
public class ViewEngine : RazorViewEngine
{
public ViewEngine()
{
MasterLocationFormats = new[]
{
// your layout cshtml files here
};
ViewLocationFormats = new[]
{
// your view cshtml files here. {0} = action name, {1} = controller name
// example:
"~/Culture/{1}/{0}.cshtml"
};
PartialViewLocationFormats = ViewLocationFormats;
FileExtensions = new[]
{
"cshtml"
};
}
}
Hence, on Global.asax file place your custom view engine on Application_Start method:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
...
// other code here
...
ViewEngines.Engines.Add(new ViewEngine()); // add your custom view engine above
}
CMIIW.
I want the url to be
domain.com/doc/{project}
I have a controller called Projects or "ProjectsController.cs."
This controller has an action (ActionResult) I want to reach with my custom url route called "DocumentationIndex."
DocumentationIndex does have a parameter. It's a simple string parameter.
The following continues to give me a 404.
routes.MapRoute(
name: "Documentation",
url: "doc/{project}",
defaults: new { controller = "Projects", action = "DocumentationIndex", project = "" }
);
Can anyone point me in the right direction?
You can use attribute routing to define this within the controller:
public class ProjectsController
{
[Route("doc/{*project}")]
public ActionResult DocumentationIndex(string project = "")
{ // ... }
}
You'll need to ensure attribute routing is enabled in your Route Config:
routes.MapMvcAttributeRoutes();
The * in the {*projects} will ensure that the route parameter matches the rest of your URL, even if it contains special characters.
Try this:
routes.MapRoute(
"Documentation",
"doc/{project}",
new { controller = "Projects", action = "DocumentationIndex" }
);
Your controller code:
public class ProjectsController ... {
//
public ActionResult DocumentationIndex(string project = "") {
// ...
}
}
I have a .aspx page in the following path:
Areas/Management/Views/Ticket/Report.aspx
I want to route that to the following path in my browser:
http://localhost/Reports/Tickets
How can i do that?
I try this:
routes.MapRoute(
"Tickets", // Route name
"Areas/Management/Views/Ticket/Report.aspx", // Original URL
new { controller = "Reports", action = "Tickets" } // New URL
);
But i got the 404 error.
What i'm doing wrong?
Obs: I put that before the Default route.
If you are trying to utilise web forms in a MVC project then I would move your .aspx out of the views folder, as it isn't really a view, so something like WebForms/Tickets/Report.aspx.
In web forms you map a route by calling the MapPageRoute method.
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapPageRoute("Tickets", "Reports/Tickets", "~/WebForms/Tickets/Report.aspx");
routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
You'll need to put that before the default MVC route.
Solved! So, we need to add a route contraint to the webforms route to ensure that it only catches on incoming routes, not outgoing route generation.
Add the following class to your project (either in a new file or the bottom of global.asax.cs):
public class MyCustomConstaint : IRouteConstraint{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection){
return routeDirection == RouteDirection.IncomingRequest;
}
}
Then change the Tickets route to the following:
routes.MapPageRoute(
"Tickets",
"Reports/Tickets",
"~/WebForms/Reports/Tickets.aspx",
true, null,
new RouteValueDictionary { { "outgoing", new MyCustomConstaint() } }
);
you are doing it opposite. this maps your url Areas/Management/Views/Ticket/Report.aspx to { controller = "Reports", action = "Tickets" }
what u should do instead is
set the url as Reports/Tickets
EDIT:- you can create a routeHandler just for routing to this .aspx page.. like this.
public class ASPXRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
return BuildManager.CreateInstanceFromVirtualPath("~/Areas/Management/Views/Ticket/Report.aspx", typeof(Page)) as Page;
}
}
then u can add ur route to the existing routes table using
Route customRoute = new Route("Reports/Ticket",null, new ASPXRouteHandler());
routes.Add(customRoute);
if you leave the default routing when you create the asp.net project
public class ReportsController : Controller
{
public ActionResult Ticket()
{
return View();
}
}
this should do the trick.
The routing in asp.net mvc means that you don't link directly to .aspx but to Actions (methods) that in turn return an appropriate view (.aspx)
I am creating a blog engine, and I need a custom route, like this:
localhost/blogname/posts/1
Where blogname should be handled by a BlogsController, and posts will be an action.
How would I define such a route?
I don't think you need to define {controller} in your Url if you define it as a constraint. I think this should work:
routes.MapRoute("Default",
"{action}/{id}",
new { controller = "Blogs", action = "Posts" },
new { controller = "Blogs"});
It might cause problems with other routes though, I'm not sure. If it doesn't work, David's answer of http://site.com/blogs/posts/id is the best way to go.
This feels like a weird approach. If you use the default routing in ASP.NET MVC, you would need one controller class per blog--not something you can easily create on the fly.
If you use the classname BlogsController, then the default routing would work for URLs of the form:
/Blogs/SomeAction/123
Maybe this is what you're looking for:
public class BlogsController : Controller
{
public ActionResult List()
{
return View(GetPostsOrSomething());
}
public ActionResult Posts(int id)
{
return View(new BlogViewModel(id));
}
[HttpPost]
public ActionResult Comment(int id, string comment)
{
// do comment
}
}
And your routing would need to look like this:
routes.MapRoute(
"Blogs", // Route name
"{blog}/{action}/{id}", // URL with parameters
new { controller = "Blogs", action = "List", id = UrlParameter.Optional }
);
Note
Bear in mind, this would match default style URLs, and everything might be routed to your BlogsController. Maybe you could consider a regular expression for the {blog} part of the pattern:
routes.MapRoute(
"Blogs", // Route name
"{blog}/{action}/{id}", // URL with parameters
new { controller = "Blogs", action = "List", id = UrlParameter.Optional },
new { blog = "(blogname1|blogname2|blogname3|etc)" }
);
But, this isn't very flexible either. Any time you added a blog to your site, this regular expression would require an update. I would probably reconsider your URL structure--something similar to the default style.
Something like this
routes.MapRoute(
"Blogs", // Route name
"{blogname}/{action}/{id}", // URL with parameters
new { controller = "Blog", action = "Posts", id = UrlParameter.Optional } // Parameter defaults
);
would work, meaning you could have your blog controller like this:
public class BlogController : Controller
{
public ActionResult Posts(string blogname, int id)
{
... get posts based on blog name and id and return view...
}
}
but then if you want a url like localhost/admin/dostuff/1 to go to an admin controller, how will MVC know that you don't just mean a 'blogname' called 'admin'?
You would need to do something like the regex matching that David suggests, or else specifically add a route for any other controllers you have before you add the Blog route
e.g.
routes.MapRoute(
"Admin Controller Routes", // Route name
"admin/{action}/{id}", // URL with parameters
new { controller = "Admin", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Account Controller Routes", // Route name
"account/{action}/{id}", // URL with parameters
new { controller = "Account", id = UrlParameter.Optional } // Parameter defaults
);
... etc - one for each controller ...
I found this approach to be best for my needs. Very simple, goal is to have the title of the blog as the parameter but also the URL (I didn't want a ? to set a parameter value, I have been told it is not helping SEO. Goal is MYURL.com/blog/my-blog-title
ASP.NET MVC
add to your RouteConfig.cs file
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Blog",
url: "blog/{title}",
defaults: new { controller = "Blog", action = "GetBlog" },
constraints: new { title = #"[\w\-]*" }
);
Add a Controller and call it Blog and then add the following Action to that Controller
[Route("blog/{title}")]
public ActionResult GetBlog(string title)
{
// do what ever code you need to do here to get the blog from the title and pass a model to the view using return View(MyBlogObject)
return View();
}
iam having controller like below which is not registered in routes table
public class InternalController : Controller
{
/*this controller is not registered in routes table*/
public ActionResult Foo()
{
return Content("Text from foo");
}
}
From another controller which is registered in Routes table i want to call/redirect action of previous controller, one which is not registered in routes table.
public class AjaxController : Controller
{
/*this controller is registered in routes table*/
public ActionResult Foo()
{
/*FROM HERE HOW DO I RETURN CONTENTS OF
controller=InternalController, action = Foo
*/
/*
i tried below piece of code but that doesnt seem to work
*/
return RedirectToAction("Foo", "InternalController ");
}
}
Defined Routes (only one item added)
public void RegisterRoutes(RouteCollection routes)
{
routes.MapRoute("Ajax","ajax/{action}",new {
controller="Ajax",
action="Index"
});
}
If you are choosing not to register a route... then you probably have the file/controller in a specific location that will not change.
In that event, just use the "Redirect" method, instead of "RedirectToAction".
For example:
return Redirect("~/Internal/Foo");
Now that you have shown your routes definition, it is obvious that you can never invoke any other controller than AjaxController. You simply forbid them in your routes, so InternalController could never be served. You will have to change your route definition.
Depending on what you want to achieve and how you want your urls to look like you have a couple of possibilities:
Leave the default route
Modify your existing route definition like so:
routes.MapRoute(
"Ajax",
"{controller}/{action}",
new { controller = "Ajax", action = "Index" }
);
You can create RedirectController for redirecting more Url and pages:
public class RedirectController : Controller
{
public ActionResult Index()
{
var rd = this.RouteData.Values;
string controller = rd["controller2"] as string;
string action = rd["action2"] as string;
rd.Remove("controller2");
rd.Remove("action2");
rd.Remove("controller");
rd.Remove("action");
return RedirectToActionPermanent(action, controller, rd);
}
}
And then you can define redirect from old url in routing tables:
routes.MapRoute(
null, // Name
"ajax/foo",
new { controller = "Redirect",
action = "Index",
controller2 = "InternalController",
action2 = "Foo"}
);
This pattern is also useful if you redirect old url to new one. For example:
routes.MapRoute(
null, // Name
"default.aspx", // redirect from old ASP.NET
new { controller = "Redirect",
action = "Index",
controller2 = "Home",
action2 = "Index" }
);