MVC Routes with/without actions and with/without id - asp.net-mvc

I have an asp.net MVC site and i would like to go to a controller without an action, but i would also like to be able to give an action on the same or other controllers.
So lets say i have Page.
I would like to be able to access the following urls
MY_URL (nothing else) - This would get another page with id = 1, or name = Home (business logic doesnt matter)
MY_URL/Page/id - This will get a page with a particular Id
MY_URL/Page/Create - Create a new page
MY_URL/Page/Delete - Delete a page
MY_URL/Page/Edit - Edit a page
I thought this would do it, but Create/Delete/Edit dont work (they just go to MY_URL/page with no id)
routes.MapRoute(
name: "PageWithId",
url: "Page/{id}",
defaults: new { controller = "Page", action = "Index" }
);
routes.MapRoute(
name: "default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Page", action = "Index", id = UrlParameter.Optional }
);
Here is my controller
public class PageController : Controller
{
private PageService _service;
public PageController(PageService service)
{
_service = service;
}
public async Task<ActionResult> Index(int? id)
{
... code to get page if id <> null
... code to get home page id id = null
// return view
return View(model);
}
public ActionResult Create()
{
return View();
}
... Delete, Edit methods implemented
}
Any help would be appreciated

Related

MVC - Passing path to action in controller

Fairly new to MVC, I would like the URLs of my article pages to be like this:-
http://www.example.com/article1
http://www.example.com/article2
http://www.example.com/article3
How can I set up the routing such that whenever someone types in the above it calls an action called article in the controller and passes the path to it?
I tried something like this but to no avail: -
routes.MapRoute(
name: "article",
url: "{article}",
defaults: new { controller = "Home", action = "article" }
);
One solution is to add multiple routes.
routes.MapRoute(
name: "article1",
url: "article1",
defaults: new { controller = "<YourControllerName>", action = "article1" }
);
routes.MapRoute(
name: "article2",
url: "article2",
defaults: new { controller = "<YourControllerName>", action = "article2" }
);
Edit:
From OP's comment, it is understood that there would be 'n' number of articles(urls). To deal with that, we can create a custom route handler.
Step 1: Create a new custom route handler inheriting from MvcRouteHandler
public class CustomRouteHandler : MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
{
var controller = requestContext.RouteData.Values["controller"].ToString();
requestContext.RouteData.Values["controller"] = "Home";
requestContext.RouteData.Values["action"] = "Index";
requestContext.RouteData.Values["articleId"] = controller;
return base.GetHttpHandler(requestContext);
}
}
Step 2: Register the new route. Make sure to add this route before default route.
routes.Add("Article", new Route("{controller}", new CustomRouteHandler()));
In the given CustomRouteHandler class, the Controller and Action is hard coded with "Home" and "Index" respectively. You can change that to your own controller and action name. Also you would see a "articleId" setting to RouteData.Values. With that setting, you would get the articleId as a parameter in your Action method.
public ActionResult Index(string articleId)
{
return View();
}
After all the changes, for the url http://www.example.com/article1, the Index() method of HomeController gets invoked with articleId set to 'article1'.
Similarly for http://www.example.com/article2, the Index() method gets invoked with parameter articleId set to 'article2'.

MVC 5 Routing - parameters to a different page

Not sure if I'm going about this the wrong way but I would like to have mydomain/mycontroller/myaction return one page and mydomain/mycontroller/myaction/{id} return a different page.
For example mydomain.com/User/Services would return a list of services, where as mydomain.com/User/Services/2 would return just the service of the id (2 in this example).
This way the URL would appear logical to the end user, and if they so wished they could just enter an id and it would bring up the page of just that Service.
With the code below I get a non-optional parameter error if I don't make it int? as it forgoes the named Services ActionResult and tries to use the re-routed one.
Is this possible?
Code
Controller:
[Route("Services/{id}")]
public ActionResult Service(int? id)
{
return View();
}
public ActionResult Services()
{
return View();
}
RoutConfig:
routes.MapRoute(
name: "Service",
url: "{controller}/Services/{id}",
defaults: new { controller = "User", action = "Service", id = UrlParameter.Optional }
);
you need to define multiple routes
routes.MapRoute(name: "Services",//Service_withoutid
url: "{controller}/Services",
defaults: new
{
controller = "User",
action = "Services",
// nothing
}
);
routes.MapRoute("Service", //Service_withid
url: "{controller}/Service/{id}",
defaults: new
{
controller = "User",
action = "Service",
id = UrlParameter.Optional
}
);

How to create a nested action in mvc?

I want to use blow URL for my delete and edit and detail of my product
localhost:3891/Administrator/ShowProduct/delete/id?AdminId=12
localhost:3891/Administrator/ShowProduct/Edit/id?AdminId=12
localhost:3891/Administrator/ShowProduct/detail/id?AdminId=12
I tried blow code for RouteConfig:
routes.MapRoute(
name: "Administrtor",
url: "Administrator/ShowProduct/{action}/{id}",
defaults: new { controller = "Administrator", action = "ShowProduct", id = UrlParameter.Optional }
);
My controller is Administrator and my action is ShowProduct
How I can create Another Action Subset of ShowProduct?
You can create Controller with the name Administrator with Delete, Edit and Details actions.
Route Code
routes.MapRoute(
name: "Administrtor",
url: "Administrator/ShowProduct/{action}/{id}",
defaults: new { controller = "Administrator", action = "Delete", id = UrlParameter.Optional }
);
Controller Code
public class AdministratorController : Controller
{
public ActionResult Delete(int adminId)
{
return View();
}
public ActionResult Details(int adminid)
{
return View();
}
public ActionResult Edit(int adminid)
{
return View();
}
}
Generated URLs
http://localhost:64922/Administrator/showproduct/Edit/1
http://localhost:64922/Administrator/showproduct/Details/1
http://localhost:64922/Administrator/showproduct/Delete/1
If you want to display adminId in URL (?adminId=) then change the adminId to Id in route.
I used Area in asp.net-mvc like this first right click on project name and go add and select Area and then right click on Area folder and Add Area, then type name of Area in my case :Administrator
every Area have model,view,controller
For Controller in my case : right click on controller folder and type this name
ShowProduct
and now I can write any action for it like edit,delete and detail

Why does #Html.ActionLink not use RouteData

I have the simplest setup:
An empty asp.net MVC application with one controller:
public class HomeController : Controller
{
public ActionResult Edit(int id)
{
return View();
}
public ActionResult Commit(int id)
{
return View();
}
}
My Edit.cshtml has a call to ActionLink() like so:
#Html.ActionLink("Commit Data", "Commit")
If I now access the Edit-Action through "/Home/Edit/2" I would expect that the rendered link directs the user to "/Home/Commit/2".
It does not :( ... The link is created to "Home/Commit", completely disregarding the current RouteData entries.
I am using the default routing configuration (have not added any routes).
One way to fix this would be to add an explicit route for both actions:
routes.MapRoute(
name: null,
url: "Home/Edit/{id}",
defaults: new { controller = "Home", action = "Edit" }
);
routes.MapRoute(
name: null,
url: "Home/Commit/{id}",
defaults: new { controller = "Home", action = "Commit" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
This works - but I really dont want to explicitly define every single route in the app - if I am using the "default" pattern...
The second solution would be to just add the routing-values manually like so:
#Html.ActionLink("Commit Data", "Commit", "Home", new {id = Model.Id})
But this also seems not right - ActionLink SHOULD use the current routing information, should it not?
What am I missing?
Ok, in case someone else is wondering the same thing - or just wants to have a solution that works...
I simply created my own #ActionLink() helper method on my custom ViewPage base class:
protected MvcHtmlString ActionLink(string linkText, string actionName)
{
var routeData = ViewContext.RequestContext.RouteData;
var id = routeData.Values["id"];
if (id != null)
return Html.ActionLink(linkText, actionName, new {id = id});
return Html.ActionLink(linkText, actionName);
}
This is exactly what I wanted. Now I can call
#ActionLink("Commit", "Commit")
and when I'm in the context of something with an id, the link will point to the appropriate route for this Id.

Asp.Net MVC 4 routing and link generation

In ASP.NET MVC 4 I wonder about the behavior, how links are generated for me.
Imagine a simple controller with 3 actions, each taking an integer parameter "requestId", for example:
public class HomeController : Controller
{
public ActionResult Index(int requestId)
{
return View();
}
public ActionResult About(int requestId)
{
return View();
}
public ActionResult Contact(int requestId)
{
return View();
}
}
and this registered route (before the default route):
routes.MapRoute(
name: "Testroute",
url: "home/{action}/{requestId}",
defaults: new { controller = "Home", action = "Index" }
);
I call my index-view using http://localhost:123/home/index/8
On this view, I render links for the other two actions:
#Html.ActionLink("LinkText1", "About")
#Html.ActionLink("LinkText2", "Contact")
Now I expect MVC to render this links including the current route-value for "requestId", like this:
http://localhost:123/home/about/8
http://localhost:123/home/contact/8
But i get these links (without the paramter):
http://localhost:123/home/about
http://localhost:123/home/contact
...but not for the index-action if i would specify one:
#Html.ActionLink("LinkText3", "Index")
What I want to avoid is to explicitly specify the parameters in this manner:
#Html.ActionLink("LinkText1", "Contact", new { requestId = ViewContext.RouteData.Values["requestId"] })
When I move the requestId parameter before the action paramter it works like I expect it, but I don't want to move it:
routes.MapRoute(
name: "Testroute",
url: "home/{requestId}/{action}",
defaults: new { controller = "Home", action = "Index" }
);
Can someone explain me this behavior? How can I get this to work without specifying the parameter explicitly?
InController:
Replace the int to nullable int
For Routing:
set requestId as optional in routing
routes.MapRoute(
name: "Testroute",
url: "home/{action}/{requestId}",
defaults: new { controller = "Home", action = "Index" ,requestId=RouteParameter.Optional }
);

Resources