ASP.NET MVC 5 Url Rewriting to encompass all actions in controller? - c#

I would like to know if it's possible to write a rule in the Route.Config file that can encompass all actions within a single controller? I have read this article but it's a little bit above me (I have just started with url rewriting and routing and the terminology is not familiar).
I have managed to change one of my actions from mydomain.co.za/Trainee/Action?id=123 to mydomain.co.za/Trainee/Action/123 but I was hoping to be able to encompass all actions in the Trainee controller, such that you can have one rule to produce Trainee/Action1/123 or Trainee/Action2/123 This is the code I used:
routes.MapRoute(
name: "ActionRewrite",
url: "Trainee/Action/{id}",
defaults: new { controller = "Trainee", action = "Action" }
);
On a side note, is it possible to hide the parameters in a URL as well, such that you can simply have mydomain.co.za/Action/ no matter what the user is doing?

Try this:
routes.MapRoute(
name: "ActionRewrite",
url: "Trainee/{action}/{id}",
defaults: new { controller = "Trainee", action = {action} }
);
Bear in mind that you can use wildcards your url match.
If you wanted you can specify that the {id} paramater remain optional which means it will also match actions that do not specify parameters.

Try this one ..
Url Rewiring in using custom id and name .
Add in app startup Route config .
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "contactus",
url: "contactus",
defaults: new { Controller = "Cms", action = "Index", id = (int)Common.CMSContactUs },
namespaces: new[] { "QZero.Controllers" }
);
routes.MapRoute(
name: "aboutus",
url: "aboutus",
defaults: new { Controller = "Cms", action = "Index", id = (int)Common.CMSAboutUs },
namespaces: new[] { "QZero.Controllers" }
);
routes.MapRoute(
name: "useragreement",
url: "useragreement",
defaults: new { Controller = "Cms", action = "Index", id = (int)Common.CMSUserAgreement },
namespaces: new[] { "QZero.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "QZero.Controllers" }
);
}
}

Related

MVC Uri Parameter is null

When attempting to pass a parameter to a simple controller I receive the parameter as always being null.
Controller
public class GetOrgController : Controller
{
private DirectoryEntities de;
public getOrgController()
{
de = new DirectoryEntities();
}
// GET: getOrg
public ActionResult Index(string district)
{
getorg_Result org = de.getorg(district).FirstOrDefault();
return View(org);
}
}
When I try to navigate to that url with a parameter localhost:660366/GetOrg/Index/D123 the district variable is always null.
I thought maybe it had to do something with the default RouteConfig. When I put a new value ahead of the default route config it worked! However now, whenever I try to launch the application it goes to the GetOrgController first. What happens when I want a new controller with different parameters? I have to do this every time? Here is my new RouteConfig with the new entry.
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "GetOrg",
url: "{controller}/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index", district = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
I actually started doing Rest initially in Web Api 2, but the view-model attracted me to MVC. It is a lot easier specifiying above the method the routes/parameters I wanted like below. Is this possible in MVC?
WebApi2
[Route("Index/{district}")]
public ActionResult Index(string district)
{
getorg_Result orgs = de.getorg(district).FirstOrDefault();
return View(orgs);
}
The above method seems so much cleaner than having to rely on the order of controllers being correct in the RouteConfig
These two routes literally make no sense. The first one says, for ANY controller with ANY method default to GetOrgController. That isn't what you want because now id won't work for all the other controllers and the second MapRoute is close to a duplicate.
routes.MapRoute(
name: "GetOrg",
url: "{controller}/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index", district = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
What you really should be doing is saying for any call starting with GetOrg then call GetOrgController for any method....
routes.MapRoute(
name: "GetOrg",
url: "GetOrg/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index", district = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
thats because both routs are generic thats why it hits the first route by default so you can remove UrlParameter.Optional so that the route should be a little specific
routes.MapRoute(
name: "GetOrg",
url: "{controller}/{action}/{district}",
defaults: new { controller = "GetOrg", action = "Index"}
);
but still you can use the default route for that purpose no need of additional route unless you want to use a custom url like random/234

I cannot figure out RouteConfig.cs file

I am very new to MVC and trying to build my first website. I couldnt set my RouteConfig file properly. I have 2 rules that apply to different ActionResults. But, only one of them works properly. if GetProducts is above the GetProductByCode, then GetProducts works. If GetProductByCode is above the GetProducts, then GetProductByCode works. What am I doing wrong?
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "GetProducts",
url: "{controller}/{action}/{PageNo}",
defaults: new { controller = "Home", action = "GetProducts", PageNo = UrlParameter.Optional }
);
routes.MapRoute(
name: "GetProductByCode",
url: "{controller}/{action}/{ProductCode}",
defaults: new { controller = "Home", action = "GetProductByCode", ProductCode = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
My Solution is like below
routes.MapRoute(
name: "GetProducts",
url: "{controller}/GetProducts/{PageNo}",
defaults: new { controller = "Home", action = "GetProducts", PageNo = UrlParameter.Optional }
);
routes.MapRoute(
name: "GetProductByCode",
url: "{controller}/GetProductByCode/{ProductCode}",
defaults: new { controller = "Home", action = "GetProductByCode", ProductCode = UrlParameter.Optional }
);
If you look at the default route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Then think of the portion after url: as a format or pattern:
{controller}
{action}
{id}
Your 3 URLs Home/GetProducts, Home/GetProductsByCode and Home/Index all match this pattern.
With the {action} portion being GetProducts, GetProductsByCode and Index respectively.
You would need to leverage routing if you wanted to map the parameter to a variables called PageNo or ProductCode in the Action, but in general you don't need routes for each possible combination. If your parameters in these actions are id then it will just work without you needing to create routes for each.
E.g.
public ActionResult GetProducts(int id)
{
// stuff
}
public ActionResult GetProductsByCode(string id)
{
// stuff
}
To have the parameter names, specify the controller and action explicitly:
routes.MapRoute(
name: "GetProducts",
url: "Home/GetProducts/{PageNo}",
defaults: new { controller = "Home", action = "GetProducts", PageNo = UrlParameter.Optional }
);
routes.MapRoute(
name: "GetProductByCode",
url: "Home/GetProductsByCode/{ProductCode}",
defaults: new { controller = "Home", action = "GetProductByCode", ProductCode = UrlParameter.Optional }
);
And
public ActionResult GetProducts(int PageNo)
{
// stuff
}
public ActionResult GetProductsByCode(string ProductCode)
{
// stuff
}
But in general, only define custom routes that differ from the normal {controller}/{action}/{id} pattern.
The default section of MapRoute means that if it can't find a controller and action that exists in your code base use these instead. It's a fallback, not the functionality driver.
All 3 routes are identical in that they contain 3 segments (the controller name, action name and an optional parameter) and which ever of the 3 are placed first will always be hit.
If you want GetProducts to be hit the you could modify the definition to
routes.MapRoute(
name: "GetProducts",
url: "Home/GetProducts/{PageNo}",
defaults: new { controller = "Home", action = "GetProducts", PageNo = UrlParameter.Optional }
);
although there seems no real point. If you just changed the name of the parameter in the GetProducts() and GetProductByCode() to id then the only route definition you require is the Default
There is not way for asp.net to understand if the last parameter is /{ProductCode}", or {ProductCode}", since the action is the same - so your URL looks the same,
Therefor only the first match is taken, a solution would be using a full query string since the /{id} is just a shorthand for id=5 in the query string

How to create query string using Html.ActionLink

In my mvc3 razor project my I have action link
#Html.ActionLink("ActionLinkName","Count","Home",new{id = 3})
This generates localhost/Home/Count/3
but I want it to create localhost/Home/Count?id=3
What changes in route should I make ?
This is because the default route that's used with new MVC projects includes an {id} segment. Removing that segment from your default route will make your existing code produce a query string.
Change this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
To this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
Since the default (fallback) route that Asp.Net registers is including an {id} parameter in the url pattern:
// Default
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Your generated url adheres to this fallback pattern ({controller}/{action}/{id}) and appends your id using /{id}.
You'll need to register a custom route before the default route to exclude the {id}:
routes.MapRoute(
name: "Count",
url: "Home/Count",
defaults: new { controller = "Home", action = "Count" }
);
You can also try to remove the {id} from the default pattern (if it won't affect other actions) or change your id parameter in the Count action to a different name.
remove {id} from default config
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new {
controller = "Home",
action = "Index",
id = UrlParameter.Optional }
);
}
TO
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}",
defaults: new {
controller = "Home",
action = "Index" }
);
}

MVC 5 Routing Issue - Mutiple Routes Incorrectly Targeting Same View

I have multiple routes configured, but for some reason, despite the rules addressing different Controllers and different Views, different links are routing to the same view. Please see below, I have included my RouteConfig file and example links below:
RouteConfig.cs
using System.Web.Mvc;
using System.Web.Routing;
namespace WebApplication1
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Account",
url: "Account/{action}/{id}",
defaults: new { controller = "Account", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Member",
url: "Member/{action}/{id}",
defaults: new { controller = "Member", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Root",
url: "{action}/{id}",
defaults: new { controller = "Home", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Details",
url: "{controller}/{action}/{u}",
defaults: new
{
controller = "Member",
action = "Details",
u = UrlParameter.Optional
}
);
routes.MapRoute(
name: "Article",
url: "{Home}/{Article}/{id}/{articleName}",
defaults: new { controller = "Home", action = "Article" }
);
routes.MapRoute(
name: "Item",
url: "{News}/{Item}/{id}/{itemName}",
defaults: new { controller = "News", action = "Item" }
);
}
}
}
Links
http://localhost:11508/Home/Article/2/Participate
http://localhost:11508/News/Item/2/Second-Test
As so can see, the links and rules are most certainly unique but for some reason the Item rule is being ignored, it is simply passing Id 2 to the Home/Article view.
You shouldn't include controller / action names in brackets - just pass them as is, so that path can be matched. Your last two routes should look like this:
routes.MapRoute(
name: "Article",
url: "Home/Article/{id}/{articleName}",
defaults: new { controller = "Home", action = "Article" }
);
routes.MapRoute(
name: "Item",
url: "News/Item/{id}/{itemName}",
defaults: new { controller = "News", action = "Item" }
);
Also, it is good to place such specific routes before any other routes, not after default routes.
UPDATE
Basically it should be separate question, but it is easier to just answer it here.
From comment:
how I can get http://localhost:11508/Member/Details?u=testuser to be routed to http://localhost:11508/Member/Details/testuser instead of a showing parameter.
Create controller action which accepts this parameter, like this one:
public ActionResult Details(string u, ...)
{
var model = new ...
...
return View(model);
}
Register route, which accepts u parameter as URL part, like this one
routes.MapRoute(
name: "MyRoute",
url: "Member/Details/{u}",
defaults: new { controller = "Member", action = "Details", u = UrlParameter.Optional }
);
Here {u} actually declares parameter name, and how it should be used (parsed / rendered) inside URL.
Render link to the URL like this one:
linktext
In all these steps, u is that name of parameter which you will use.
The Mapping takes the first matching rule.
The "Item"-Route would never be used because the Article-Root will catch all request that could match "Item"-Route.
Check the order of the routes AND delete the {} surrounding news.
routes.MapRoute(
name: "Item",
url: "News/Item/{id}/{itemName}",
defaults: new { controller = "News", action = "Item" }
);
Your problem is in the order in which you are registering your routes. The rule is that you should register them from the most specific to the least. In other words, your "default" route(s) should be the very last.
With how you have it right now, MVC gets a hit on your default route, because your item route matches that, so once it hits on that, it stops looking for other routes and uses it.
Move your item route up to the top of your RegisterRoutes method and it should work fine.

MVC4 Route as /{controler}-{id} instead of /{controler}/{id}

During my work I must solve one URL rewriting problem. I have to use URLs as a template:
{controller}/{action}-{id}
instead of
{controller}/{action}/{id}
so the processed url should look like:
myController/myAction-128
where 128 is a parameter
My route map:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "NewRoute", // Route name
url: "{controller}/{action}-{id}/{extId}", // URL with parameters
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional, extId = UrlParameter.Optional } // Parameter defaults
);
}
Controller code:
[HttpGet]
public ActionResult DocumentDetails(int? id)
{
if (doc.HasValue)
{
...
}
}
This route doesn't provide any successful results. I still have 404 Errors. When I use / instead of "-" everything is ok, but my JS View environment won't work.
Is there something I could do to fix this? All help will be appreciated, thanks.
Routes are evaluated in the same order as you defined them, so make sure you respect the same order. Also adding a constraint for the id (as being a number for example) would help the routing engine disambiguate your routes. Not to mention that in your example you have made the id token optional which of course is not possible, only the last part of a route can be optional.
So:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "NewRoute",
url: "{controller}/{action}-{id}/{extId}",
defaults: new { controller = "Home", action = "Index", extId = UrlParameter.Optional },
new { id = #"\d+" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
I'm thinking your request is being processes by the first routing rule and then action-id is considered as a whole action and not being found.
Set your NewRoute before the Default route. Just move the code up.

Categories