MVC 5 Routing - parameters to a different page - asp.net-mvc

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
}
);

Related

Optional id for default action

I got a site with only this Route:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Image", action = "Image", id = UrlParameter.Optional }
);
}
This is the controller:
public class ImageController : Controller
{
public ActionResult Image(int? id)
{
if (id == null)
{
// Do something
return View(model);
}
else
{
// Do something else
return View(model);
}
}
}
Now this is the default action so i can access it without an ID just by directly going to my domain. For calling the id it works just fine by going to /Image/Image/ID. However what i want is calling this without Image/Image (so /ID). This doesn't work now.
Is this a limitation of the default Route or is there a way to get this to work?
Thanks
Create a new route specific for this url:
routes.MapRoute(
name: "Image Details",
url: "Image/{id}",
defaults: new { controller = "Image", action = "Image" },
constraints: new { id = #"\d+" });
Make sure you register the above route before this one:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional });
Otherwise it will not work, since the default route will take precedence.
Here I'm stating that if the url contains "/Image/1" then the ImageController/Image action method is executed.
public ActionResult Image(int id) { //..... // }
The constraint means that the {id} parameter must be a number (based on the regular expression \d+), so there's no need for a nullable int, unless you do want a nullable int, in that case remove the constraint.

MVC Routes with/without actions and with/without id

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

MVC Action has the same name, but diffrent controller

Routemap structure:
routes.MapRoute(
name: "NaturalStonesDetails",
url: "{lang}/natural-stones/{title}-{id}",
defaults: new { lang = "en", controller = "NaturalStones", action = "Details" }
);
routes.MapRoute(
name: "ProductCategorieList",
url: "{lang}/products/{title}-{id}",
defaults: new { lang = "en", controller = "Product", action = "Index" }
);
Link structure:
<a href="#Url.Action("Index", "Product", new { title = stoneguide.com.Models.DealerProduct.GetTitleUrlFormat(items.CategoryName), id = Convert.ToInt32(items.ID) })" style="padding:2px;">
Problem:
When I click on the link, go to the product page, which should go to NaturalStones page. I can not solve this problem, a kind.
Please help!
Your routing is quite neat and should work just fine with the code provided. I think you just got confused by which controller to use. So
#Url.Action("Index", "Product", new { title = "mytitle", id = "myid" })
returns /en/products/mytitle-myid which the routing correctly recognises as the request to Product controller, Index action with two parameters.
On the other hand
#Url.Action("Details", "NaturalStones", new { title = "mytitle", id = "myid" });
generates /en/natural-stones/mytitle-myid which is interpreted as request to NaturalStones, Details action with two parameters, and that's probably the one you want to use.
On the side note, providing title and id for Product, Index action is a bit awkward. By convention Index action usually returns a list of items, hence a reference to a specific id seems to be out of place. You might consider changing your routing to:
routes.MapRoute(
name: "NaturalStonesDetails",
url: "{lang}/natural-stones/{title}-{id}",
defaults: new { lang = "en", controller = "NaturalStones", action = "Details" }
);
routes.MapRoute(
name: "ProductCategorieList",
url: "{lang}/products",
defaults: new { lang = "en", controller = "Product", action = "Index" }
);
and then have controllers as follow:
public class ProductController : Controller
{
public ActionResult Index()
{
return View();
}
}
public class NaturalStonesController : Controller
{
public ActionResult Details(string title, string id)
{
return View();
}
}

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.

URL rewriting issue through Route.Config

I am able to do the URL rewriting of my MVC Application by using a Route.Config file as below:
//Offline Consult Route
routes.MapRoute(
name: "WrittenStep2",
url: "written/step2/{id}",
defaults: new { controller = "Offline", action = "Step2", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Written",
url: "written",
defaults: new { controller = "Offline", action = "Index" }
);
In the above code, I have Controller as "Offline" and have some actions.
I am able to change the route:
TO: www.abc.com/written
FROM www.abc.com/Offline
My problem is that I am still able to access the URL: www.abc.com/Offline. How can I resolve this issue?
I have tried to deny access of this URL to the users by using the Begin_Request method of Global.asax file.
But after doing that I won't be able to access my methods which I am calling using jQuery Ajax.
$.ajax({
type: "POST",
url: "/Offline/HelloWorld",
data: jsonString,
contentType: "application/json",
...
Is there any way to restrict users from using the same URL?
Try this, it might be helpful for you
...
for the given example, if you want to restrict or navigate users for a specific URL, you can try:
1- include a route for Offline with custom route handler
routes.MapRoute(
"OfflineWithoutParameterRoute",
"Offline"
).RouteHandler = new NewUrlRouteHandler();
routes.MapRoute(
name: "WrittenStep2",
url: "written/step2/{id}",
defaults: new { controller = "Offline", action = "Step2", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Written",
url: "written",
defaults: new { controller = "Offline", action = "Index" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
2- Create your MvcRouteHandler as
public class NewUrlRouteHandler : System.Web.Mvc.MvcRouteHandler
{
protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
{
//restrict or navigate to any destination
requestContext.RouteData.Values["controller"] = "Home";
requestContext.RouteData.Values["action"] = "index";
return base.GetHttpHandler(requestContext);
}
}
which you can maintain any approach
so any hit for www.abc.com/Offline will hit to custom handler and any route for www.abc.com/Offline/prm will follow the default route.
I have tried with controller/action you given as an example and it should be helpful for you.
public class OfflineController : Controller
{
// GET: Offline
public ActionResult Index()
{
return View();
}
public ActionResult Step2(int id)
{
return View();
}
public ActionResult HelloWorld(int id)
{
return View();
}
}

Resources