ASP.NET MVC Routing Strange or Unexpected Behavior - c#

I am very new to ASP.NET MVC and am working over an eCommerce application that uses ASP.NET MVC 2.
For all the scenario, the default route works fine. But I need to define my own rule for URL like below:
http: //localhost/mvc2proj/products
http: //localhost/mvc2proj/products/productname
For this, I defined a new route just above the default routing:
routes.MapRoute(
"Products",
"Products/{productName}",
new { controller = "Products", action = "Index" }
);
It works fine when home page gets displayed. That is when the URL is http: //localhost/mvc2proj, the anchor tag's href attribute for menu header "Products" is "href="mvc2proj/Products" Products".
But when the URL is http: //localhost/mvc2proj/products/productname, the anchor tag's href attribute for menu header "Products" also gets changed to href="mvc2proj/Products/productName" which is not obviously desired. The menu href should not be changed whenever Product's category is clicked individually. It should remain unchanged.
I defined menu as a User Control like this:
<li><%=Html.RouteLink("Home", new { Controller = "Main", Action = "Index" })%></li>
<li><%=Html.RouteLink("Products", new{ Controller = "Products" } ) %></li>
Product's subcategory is defined like this:
<%foreach(var product in Model.Products) {%>
<li><%=Html.RouteLink(Html.Encode(product.ProductName), new { controller = "Products", productName = product.ProductName })%></li>
<%} %>
The HTML for subcategory is:
<li>Product1</li>
<li>Product2</li>
....... and so on. Clicking on these links changes the menu URL.
Please help me.

This may not be the best solution, but I got around a similar issue by defining a different route for the Index page than for the individual product pages, i.e. something like:
routes.MapRoute(
"ProductIndex",
"Products",
new { controller = "Products", action = "Index" }
);
This would be additional to your existing route. I think I actually used different Action methods for each, but there would be no need to if you supplied a default value for the parameter.
I am sure there is a better way and that this solution comes from a lack of understanding of what's really going on, but it may help you solve the immediate problem!

Related

adding custom view name in asp.net mvc4

I am building an application in .net mvc4 that is based on business promotion and sales store.
User on this web application would be able to use product and access his/her personal business page also, that page can be promoted in future.
So I added one controller- Mypanel and a view of user's personal or professional business page _Mypanel.
Now the url access to this page is Bizcopter.com/Mypanel/_Mypanel
I want a custom user defined page name-
i.e. If a business name is - BookStore
Then I want to add a view in this same controller with the name of BookStore, So URL of personal business page would be-
Bizcopter.com/Mypanel/BookStore/ and this business holder can promote his business page with this URL.
Let me know if these are possible-
Replacing the view's name of user's choice
Add a view from client side in this same controller
I don't have any idea how to make it happen so don't have any trying code.
Site URL- http://bizcopter.com/Mypanel/_Mypanel
You don't need a separate view and controller action for each business.
I would create a controller and view called MyPanel. The controller takes a parameter called something like businessName that will load data related to the parameter.
By default you'll have a route in your AppStart/RouteConfig.cs which may look like this:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
The default URL structure might look something similar to: http://localhost:{PortNumber}/{Controller}/{Action}
Where we can attribute the following:
Controller = Home
Action = Index
Now if you want something similar to how you have it, you'd want something along the lines of:
http://testing.com/Fruits/Apples
Controller = Fruits
Action = Apples
By default, a URL pattern will match any URL that has the correct number of segments, in this case {controller}/{action}
Overall you should just need the MyPanel controller, and a controller taking a parameter of string which loads the correct Object/Model into the view.
Source: Pro ASP.NET MVC 4 - Adam Freeman
As the others said you can add a new route.Consider this code:
routes.MapRoute(
name: "MyCustomRoute",
url: "MyPanel/{name}"
defaults: new { controller = "MyPanel", action = "MyAction", name="" }
);
In this route if user type this URL:
Bizcopter.com/Mypanel/
Then it goes to your MyAction in your MyPanel Controller by default.Actually it will always go to MyAction, and in your MyAction, you must take the name parameter and redirect to user to the Relevant Action like this:
public ActionResult MyAction()
{
var name = RouteDate.Values["name"];
// check the name and redirect user to another action if it necessary
if(name == "BookStore") return RedirectToAction("BookStore","Mypanel");
}

Asp.net MVC Routing always to Root with parameters

Now, the question. I have an eCommerce website and I have a controller called Store with an action Index. When someone types www.mysite.com/sony, I want to route to controller Store and action Index with parameter brand=Sony. If someone type www.mysite.com/sony-tv, I want to route to controller Store and action Index but with the parameters brand=sony and department=tv.
I obtained that by creating a route for every situation storing in a database, and building the routes dynamically when the app starts. Its works fine in a few cases.
First, i need to index the routes. I need to map the route sony-tv before the sony, otherwise the /sony-tv maps to /sony equally.
When i enter at site's home (www.mysite.com) and click at Url.Action("Index","Store", new {brand=Sony}) it route me to www.mysite.com/sony. NICE!. Now, inside the SONY brand i'll click at Url.Action("Index","Store", new {brand=sony, department=tv}) and I can see all TV's from Sony.
Everything is running fine until here. In the database, I have 1 route to /sony where I say i have a parameter named brand with value Sony and a constrained named brand with value Sony. I have another route saying the same way to sony-tv. The pattern sony-tv has a parameter named brand with value sony and a parameter named deparment with value tv, and the sames constraints of parameters.
In my head, its means that the route for www.mysite.com/Sony is Store/Index/brand=sony and the www.mysite.com/sony-tv is Store/Index/brand=sony&department=tv. With the constraints, i understand that if department is not TV or if the parameter department does not exists, it will send to www.mysite.com/sony
When i'm at www.mysite.com/sony-tv, if I pass my mouse over the other brands, the link build to Url.Action("Index","Store", new {brand=Apple}) is www.mysite.com/Apple-Tv
I have a route to Apple-TV equal to Sony. The URL exists but i'm not passing the TV parameter. I passed on this link (brands links) only the brand. I want to move the user to brand's root he's moved to brands + department.
I don't know, its looks like the department variable is passing through again and I don't know how to cancel that.
I'm completely wrong? What i'm doing is valid? I can do that? Where is my mistake?
At cshtml file:
#Html.ActionLink(febrand.Name.ToUpper(), "Index", new { controller = "Store", brand= febrand.FriendlyName, department = string.Empty })
at final html file (show source code from google chrome):
SONY
Fisrt, that seems like a lot of work for something that you could do with two custom routes. Additionally, as your route table gets larger (eg. adding more brands and/or departments), each request to your site will take longer to fulfill due to having to scan a larger list of routes.
So, lets attempt to fix your route table. Place these two routes above your default route in the global.asax:
routes.MapRoute(
"Department",
"{brand}-{department}",
new { controller = "Store", action = "Index" };
routes.MapRoute(
"Brand",
"{brand}",
new { controller = "Store", action = "Index" });
As for your issue, when you create your action link, the routing engine is holding onto the department route value from the view you are currently on. To make it forget that parameter when generating a link, send a null across for the department variable when you do not need it.
#Html.ActionLink("Apple", "Index", new{controller="Store", brand="Apple", department = string.empty});
EDIT
I feel you may be in a weird edge case with your routing (and there are numerous examples of this problem all across SO, such as here and here). The solution, other than the one I provided, is to switch to Html.RouteLink instead of Html.ActionLink.
RouteLink Signature that we are going to use
Html.RouteLink(string linkText, string routeName, object RouteValues)
Example Brand link for your code
#Html.RouteLink(febrand.Name.ToUpper(), "Brand", new { controller = "Store", action = "Index", brand= febrand.FriendlyName})

MVC Areas and routing issue

I'm having some issues getting Areas working correctly within MVC 3. I have the following folder structure and an Admin area set up:
I'm trying to navigate from the admin page (Index) to the the other view pages in the Admin area for example Admin/Floor/Create etc... but I get The resource cannot be found error on every url combination i've tried for example:
#Html.ActionLink("floors", "Index", "Floor", new { area = "Admin" }, null)
/Floor/Index/
/Admin/Floor/Index/
None of which work. I managed to use the first ActionLink one to link to the admin index page from outside of the area but it's no use here.
The area registration looks like this:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Can anyone offer some help?
Thankyou
The problem is with your routing. You need to set the default controller to be AdminController:
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { controller = "Admin", action = "Index", id = UrlParameter.Optional }
);
If you don't specify this, MVC doesn't know quite what you're looking for and actually expects you to navigate to /admin/admin in order to display the initial view. So change the routing as I've mentioned above and then use this action link to get to FloorController.Create():
#Html.ActionLink("floors", "create", "floor", new { area = "admin" }, null)
To expand a little, with your routing setup this way, your URLs will look like this:
/admin // Executes AdminController.Index()
/admin/floor // Executes FloorController.Index()
Update
Having downloaded Maciej RogoziƄski's project, this gives me the same problem that your project currently has. The link from the default action is linking to /admin/admin/, which as I mentioned earlier, is what your project is looking for because no default controller has been specified for the area routing (this also applies to Maciej's project). Specifying the default controller allows you to navigate to /admin, which results in AdminController.Index() being invoked. Without specifying that controller, you can only retrieve this view from routing to /admin/admin, which again, is what Maciej's application is doing.

Is there a way to make the route mapping based on specific path

I code lots of ASP.NET but I'm kind of new with .net MVC, I've a default route registered like this:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
And I want to add another Administrator area on the site and all the URL would be something like "http://localhost/Administrator/controller1", "http://localhost/Administrator/controller2", etc. I've lot of controllers in the Administrator namespace and I'm trying to register those controller with only one MapRoute, I did something like this:
routes.MapRoute("Administrator_default", "Administrator/{controller}/{action}/{id}", new { controller = "Administrator", action = "Index", id = "" });
it works with those controller but one problem is that in some other controller while I try to do a redirect like:
return RedirectToAction("Index", "Forum");
Then I'll always be redirect to http://localhost/Administrator/Forum instead of http://localhost/Forum, it's not a big issue but make the URL looks strange, I tried to restrict to certain namespace but it's not working. It looks just as I'm trying to register two default route and .Net just match the first one, I'm wondering is there a way to make it two default route and map on only specific path only?
This exact issue is why Areas were added to MVC 2. http://www.asp.net/whitepapers/what-is-new-in-aspnet-mvc#_TOC3_2
Agree with Zach's answer.
Not ideal, but you do have the option to have controllers in the controller root folder (e.g. /controllers/HomeController.cs) of your project as well as the controllers in Areas (maybe high level root pages that display menus for areas).
Secondly a quick tip on using the RedirectToAction method. You can specify the area you would like to redirect too using the route parameters e.g:
RedirectToAction("Index","Form", new { area = "MyOtherArea" });

mvc.net dynamic urls

I am looking to produce an MVC site which has complete control of the url structure using routing.
routes.MapRoute(
"BlogView", // Route name
"view/{blogurl}", // URL with parameters
new { controller = "view", action = "view", productLink = ""} // Parameter defaults
);
routes.MapRoute(
"ProductGrid", // Route name
"category/{category}", // URL with parameters
new { controller = "category", action = "Index", category = "" } // Parameter defaults
);
I currently have the follwoing urls;
www.myblog.com/view/first-post
www.myblog.com/view/another-post
www.myblog.com/category/code
www.myblog.com/category/example
The first two urls relate to the detail view, the latter two relating ot a category view.
I have a database with the following structure; I ensure that the url (chrUrl) is a unique key.
url ( idurl (int),
chrURL,
chrAction,
chrController
)
My plan is that it is possible to look up rewrite the route lookup table so that the follwoing urls redirect to the correct view and page in the site;
www.myblog.com/first-post
www.myblog.com/another-post
www.myblog.com/code
www.myblog.com/example
Is this possible? Perofmance aside, is there a problem with this and how shoudl I go about this?
Since you don't have anything to differentiate between view and category items, I'd think about using a default controller which checks if the id is in the categories table and passes control to either the View or the Category controller.
routes.MapRoute(
"Root", // Route name
"/{id}", // URL with parameters
new { controller = "default", action = "redirect"} // Parameter defaults
);
But if you can live with having "/category/" in your category urls, that will be the more elegant solution on the back end.
First up, I would suggest coming up with a URL scheme that you are happy with. (seems you have one already)
Then I would use a ControllerFactory that will be responsible of Instantiating and
running the right action on the right controller. That is independent of any routes that you define in your route table - in fact it wont matter what you have there since you want your URL to be "database driven". You invoke the controller factory from your Global.asax file :
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new Controllers.ControllerFactory());
}
Then in the GetControllerType method in your ControllerFactory, you inspect the URL with
RequestContext.RouteData.Values.ContainsKey("keyname")
to work out the url scheme the user is presenting, and do a database look-up based on that.
If you want to take this one step further, your database can also contain references to the controller to instantiate, but that would be an overkill in your situation. As a quicknote, we use that in a solution where it was important to provide the ability for non-developers to create templates without involving dev - the database held url schemes, controller and views to render on that controller.
While you are at it, if you want to make things more elegant, create a BaseController that your controllers inherit from, and in there set things in your ViewData such as your SEO tags (MetaDescription, Title, etc) - look these up from your database.

Categories

Resources