I'm using routing in my ASP.NET MVC 4 application and I'm experiencing a very strange problem. I am attempting to establish a route to an area named Ekstranett, but if I use Ekstranett as the first URL parameter I get an Internal Server Error. I can use any word except for Ekstranett and I find that very strange. This is my setup:
context.MapRoute(
"Exception",
"Ekstranett/Exception/{action}/{*handle}",
new { controller = "Exception", action = "General", handle = UrlParameter.Optional },
new[] { "MyProject.Areas.Ekstranett.Controllers" }
);
context.MapRoute(
"Support",
"Ekstranett/Support/{action}/{*handle}",
new { controller = "Support", action = "Tickets", handle = UrlParameter.Optional },
new[] { "MyProject.Areas.Ekstranett.Controllers" }
);
context.MapRoute(
"Ekstranett_default",
"Ekstranett/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
new[] { "MyProject.Areas.Ekstranett.Controllers" }
);
If I change Ekstranett to something like Ektranett, Testing, Foobar or anything else it works perfectly, but if I use Ekstranett it does not. Does anyone have any clue as to why I'm experiencing this behaviour?
Just a guess, but it could be because Ekstranett is the name of the Area? Could be causing a routing collision of some kind. Out of interest, if you use all lower case within the route, does that work? (e.g. "ekstranett/Support/{action}/{*handle}")
The problem has been solved! Ages ago I made a virtual directory called ekstranett, I deleted it and everything works wonderfully now!
Related
Route definition:
context.MapRoute(
name: "VeranderingsTraject",
url: "Detail/{action}/{id}/{viewDate}/{toekomstBeeldId}",
defaults: new { controller = MVC.Detail.Name, action = MVC.Detail.ActionNames.VeranderingsTraject, viewDate = UrlParameter.Optional, toekomstBeeldId = UrlParameter.Optional },
namespaces: new[] { typeof(DetailController).Namespace }
);
DetailController:
public virtual ActionResult VeranderingsTraject(int id, DateTime? viewDate = null, int? toekomstBeeldId = null)
{ ... }
ActionLink in view:
The current view is actually also from the DetailController so I thought that I didn't need the controller name. Since it wasn't working, I added it, but to no avail.
#Html.ActionLink(linkText:"TEST LINK", actionName: "VeranderingsTraject", controllerName: "Detail", routeValues: new {id= 1, viewDate = Model.VersieDatum}, htmlAttributes: null)
Result in browser:
<a href="">
TEST LINK
</a>
Expected result:
<a href="/Detail/VeranderingsTraject/1/{date, i need to encode the url i know)/">
TEST LINK
</a>
So after some reading left and right (thank you google)
Seems that my routing was done completely wrong. So I cleaned up my whole routing table and now I'm getting a lot better results, it's still not perfect, but it can be fixed thanks to the answers given on other ActionLink related questions here on stackoverflow
I have about 10 actions on the detail controller giving the same view (shared info amongst different objects) I used to have a route for each of these so the correct route could not be determined.
Now all 10 routes are brougth to this one:
context.MapRoute(
name: "Detail",
url: "Detail/{action}/{id}/{viewDate}/{toekomstBeeldId}",
defaults: new { controller = MVC.Detail.Name, action = MVC.Detail.ActionNames.Persoon, viewDate = UrlParameter.Optional, toekomstBeeldId = UrlParameter.Optional },
namespaces: new[] { typeof(DetailController).Namespace }
)
The generated link is now the following:
So I just need to format that date a bit better and then read up to change the /persoon?id=... to /persoon/14/01-22-2014/ but I've seen some questions and answers on stackoverflow to remedy that problem.
Thanks for reading and thinking, hope this helps somebody
This is my code that i'm using to create a link to top level link:
#Html.ActionLink("Edit",Url.Action("Edit","Home", new{row.Application_ID}))
// supposed to return /Home/Edit/x (application_id)
Instead, it returns:
/Home/Home/Edit/x // Current View is Home/Edit
Please help.
Edit 1:
Route Table information:
//This is for Edit
routes.MapRoute(
"Edit", // Route name
"Home/Edit/{application_id}", // URL with parameters
new { controller = "Home", action = "Edit", application_id = UrlParameter.Optional } // Parameter defaults
);
// This is the default route, I've modified it to LogOn.
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Account", action = "LogOn", id = UrlParameter.Optional } // Parameter defaults
);
As a small edition to haim770 answer. if you want for some reason use Url.Action instead Html.ActionLink you are always free to write it like that:
Edit
Some developers prefere this way because it more similar to plain Html, but result is the same as Html.ActionLink
You don't need the inner #Url.Action, try this instead:
#Html.ActionLink("Edit", "Edit", "Home", new { application_id = row.Application_ID }, null);
tried this work around and it worked:
Edit
now it returns the link as Home/Edit/x :)
In my MVC4 application, I want to show the data to users according to the client. I want to achieve this using URL routing.
e.g.
1. http://mysite.com/abc/account/login
2. http://mysite.com/xyz/account/login
Here, 'abc' and 'xyz' are referred as clientcode. If user enters first url, then the application will connect to database for client 'abc'. If user enters second url, then it will connect to database for client 'xyz'.
I want to achieve the above functionality. So how should i make use of routing.
I have used following code in RouteConfig -
routes.MapRoute(
name: "Default",
url: "{clientcode}/{controller}/{action}/{id}",
defaults: new { clientcode = UrlParameter.Optional, controller = "Account", action = "Login", id = UrlParameter.Optional }
);
Thanks in advance.
You can only make the last parameter optional in ASP.NET MVC. Instead of changing the default route, create a new route for this specific URL. Make sure you add this one before the default route.
routes.MapRoute(
name: "Login",
url: "{clientcode}/account/login",
defaults: new { clientcode = UrlParameter.Optional, controller = "Account", action = "Login" }
);
You can achieve this by reading ControllerContext.RouteData. The RouteData object contains Values RouteValueDictionary that you can read and query for clientcode. For example:
var clientCode = ControllerContext.RouteData.Values["clientcode"];
if (String.IsNullOrWhiteSpace(clientCode))
{
// Set to a default value
clientCode = "default_value";
}
// Do something with clientCode
return ViewResult(); // or RedirectToAction("ActionName")
That's about it.
Here is my RouteConfig.cs
routes.MapRoute(null,
"{controller}/Page{page}",
new {controller = "Product", action = "Index", category = (string) null},
new {page = #"\d+"}
);
routes.MapRoute(null,
"{controller}/{category}",
new {controller = "Product", action = "Index", page = 1}
);
routes.MapRoute(null,
"{controller}/{category}/Page{page}",
new {controller = "Product", action = "Index"},
new {page = #"\d+"}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
And here is the code for generating url:
#Html.ActionLink("View Cart", "Index", "ShoppingCart", null, new { #class = "btn btn-orange" })
It works well when I navigate to, for example, Product/Page2, Product/Laptop, Product/Laptop/Page2. The problem is, whenever my current URL contains Page segment, it will try to reuse that segment for generating outgoing URL. So, if I'm at Product/Page2 the above generated URL would be ShoppingCart/Page2. I don't know how to avoid this.
Please help me. Thank you so much.
EDIT!!!
I've found a workaround way. Instead of using ActionLink, I use RouteLink like this:
#Html.RouteLink("View Cart", "Default", new { controller = "ShoppingCart", action = "Index" }, new { #class = "btn btn-orange" })
But I still want to use ActionLink, so please help me.
EDIT!!!
The workaround way doesn't work when I generate a link to ShoppingCart/Checkout. It still take me to Index action in ShoppingCart controller.
Create a new route pattern specific to ShoppingCart and make it the first route by placing it at the TOP.
routes.MapRoute(null,
"ShoppingCart/{action}",
new {controller = "Product"});
);
As a rule all the specific routes should come first.
This is because of the way the routing system tries to evaluate the value of segment variables when trying to match against a route.
So when the call to render the link occurs with the following arguments:
#Html.ActionLink("View Cart", "Index", "ShoppingCart", null, new { #class = "btn btn-orange" })
the framework when evaluating the route with template
{controller}/Page{page}
will resolve the controller segment variable to be ShoppingCart however when it cannot find a value for the page segment variable (via any of the arguments in the method call), it will then try and resolve that value from the RouteData object in the ViewContext. Since you have navigated to Product/Page2, the current value of page within the routes value dictionary is 2.
You can inspect this by looking at the value of ViewContext.RouteData.Values["page"] when rendering that view.
I have a custom route defined:
routes.MapRoute(
"FabricDetails", // Route name
"fabric/details/{designerUrlFriendlyName}/{collectionUrlFriendlyName}/{fabricUrlFriendlyName}", // URL with parameters
new { controller = "Fabric", action = "Details", designerUrlFriendlyName = UrlParameter.Optional, collectionUrlFriendlyName = UrlParameter.Optional, fabricUrlFriendlyName = UrlParameter.Optional }, // Parameter defaults
new[] { "StashFabrics.Web.Controllers" }
);
I have two nearly identical actionlinks and one is working while the other is not
#Html.ActionLink(fabric.FabricName, "Details", "Fabric", new RouteValueDictionary(new { designerUrlFriendlyName = fabric.DesignerUrlFriendlyName, collectionUrlFriendlyName = fabric.CollectionUrlFriendlyName, fabricUrlFriendlyName = fabric.FabricUrlFriendlyName }), null)
#Html.ActionLink(fabric.FabricName, "Details", "Fabric", new RouteValueDictionary(new { designerUrlFriendlyName = fabric.DesignerUrlFriendlyName, collectionUrlFriendlyName = "grand_hotel", fabricUrlFriendlyName = fabric.FabricUrlFriendlyName }), null)
For whatever reason, as soon as I replace the hard coded value for collectionUrlFriendlyName the link doesn't get built correctly
http://localhost:55089/Fabric/Details?designerUrlFriendlyName=jenean_morrison&collectionUrlFriendlyName=grand_hotel&fabricUrlFriendlyName=ballroom_in_azure
http://localhost:55089/fabric/details/jenean_morrison/grand_hotel/ballroom_in_azure
This has me stumped. Any advice would be appreciated.
Well I figured it out.
In the model of the view I have collectionUrlFriendlyName defined at two different levels; first on the model itself and then again on the class to which the model has a list.
I wasn't defining a value for collectionUrlFriendlyName at the list level, where the URL was being formed. But I guess when constructing the URL it would later find the value at the upper level and use it to form the ugly url (thus hiding the problem that it wasn't populated on the lower level)
If that make sense.