I have a weird problem with some routing in MVC. Here's my scenario:
The user gets presented to the front page, once visiting the site: testproject.com:57416/Home.
The user has a menu on the left side, with the menu item "Solutions".
The user presses the menu item "Solutions" and the menu item expands, showing 5 sub items.
The user presses the sub item "Demo", and redirects to testproject.com:57416/Solutions/SetLayout?layoutString=page1%7Csize15
As the param layoutString is defined, the grid (DevExpress) know how to filter the data to show.
The grid is presented to the user, and (s)he can now navigate around the grid, manipulating the layout.
The user now wants to see the clean Demo layout again, and (s)he presses the menu item "Solutions" -> sub item "Demo".
The action ActionResult SetLayout(string layoutString) is not hit in this case, but instead the action ActionResult Index() is hit, thereby not setting the layout as the layoutString is not sent in as a param
The url that the user is redirected to, looks like this: testproejct.com:57416/Solutions?undefined=undefined
This might be a bit tiresome to read through, but it's the best way possible for me to explain my scenario as I have never seen anything like this before in MVC. I truly have no idea what's going on, and why the action ActionResult SetLayout(string layoutString) is not hit the second time.
I suppose I should show some code so we can narrow down the possibilities.
_Layout.cshtml (has menu items)
<li class="has-submenu">
Solutions
<ul class="nav sub-menu-list">
<li>
#Html.ActionLink("Demos", "SetLayout", "Solutions", new { layoutString = "page1|size15" }, null)
</li>
</ul>
</li>
ActionResult SetLayout(string layoutString)
public ActionResult SetLayout(string layoutString)
{
Session["Layout"] = layoutString;
return RedirectToAction("Index", "Solutions");
}
ActionResult Index()
public ActionResult Index ()
{
using(var db = new DataBasecontext())
{
var list = db.Solutions.ToList();
return View(list);
}
}
EDIT
I've found out that this only happens when I'm inside the same controller. The controller holding the action ActionResult SetLayout(string layoutString) is the SolutionsController. If I'm coming from, let's say the AccountController everything works fine, but changing from SolutionsController to another action in the SolutionsController doesn't work.
Come to think of it, could have something to do with my map routes?
routes.MapRoute(
name: "ControllerIdActionId",
url: "{controller}/{id}/{action}/{id2}",
default : new { id2 = UrlParameter.Optional }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
default : new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.MapRoute(
name: "Solutions",
url: "{controller}/{id}/{action}",
default : new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Seems that the layoutString parameter has missing parameter value on its second firing, thus empty string value inserted into Session key (and Javascript function related to that Session treat the empty string as undefined).
public ActionResult SetLayout(String layoutString)
{
// Test if the string is null or empty before filling session key,
// if it is empty one, leave the session key as is
if (!String.IsNullOrEmpty(layoutString)) {
Session["Layout"] = layoutString;
}
return RedirectToAction("Index", "Solutions");
}
Perhaps this is not the best way to do, I just viewed from SetLayout method perspective to fill Session key with proper query string.
Pass 5th parameter as null in your actionlink as below:
#Html.ActionLink("Demos", "SetLayout", "Solutions", new { layoutString = "page1|size15" },null)
I have not tested it but may be it is the issue..
I managed to solve the problem on my own.
I'm not quite sure what the issue was, but changing the Html.ActionLink() into Html.RouteLink()'s I was able to define what MapRoute to use.
I solved it by using the following MapRoute
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
)
I could then use the Html.RouteLink like so:
Html.Routelink("Demos", //Display text
"Default", //The MapRoute to use
new { layoutString = "page1|size15|", //The param (layoutString)
controller = "Solutions", //The controller
action = "SetLayout" }) //The action
I made no changes to the action:
public ActionResult SetLayout(string layoutString)
{
Session["Layout"] = layoutString;
return RedirectToAction("Index", "Solutions");
}
Related
I have the following in my RouteConfig.cs file
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
Home Controller has the following:
[Route("NewIncident")]
public ActionResult NewIncident()
{
var viewModel = new IncidentFormViewModel();
viewModel.NextPage = 2;
return View("NewIncident",viewModel);
}
[Route("EditIncident/{id?}")]
public ActionResult EditIncident(int? id)
{
return View("EditIncidentPage" + id);
}
[Route("SaveIncident")]
public ActionResult SaveIncident(IncidentFormViewModel incidentviewmodel)
{
return RedirectToAction("EditIncident/" + incidentviewmodel.NextPage);
}
From my index view, I can click a button that has the #Html.ActionLink as follows:
#Html.ActionLink("New Incident", "NewIncident", "Home", null, new { #class = "btn btn-primary" })
I access the site at http://sitename/ and it loads my index page. I can click the New Incident button and it loads http://sitename/NewIncident just fine, but when I click the Save button on the New Incident form, it calls the SaveIncident function just fine, but when it hits the return RedirectToAction("EditIncident/" + incidentviewmodel.NextPage); it sends me to http://sitename/Home/EditIncident/2 instead of just http://sitename/EditIncident/2.
Any idea why its adding the /Home in there?
The parts of the URL are http://sitename/Controller/Action/Parameter.
Your EditIncident ActionResult lives inside your Home Controller, and so you will therefore always see Homein front of EditIncident.
When you redirect to another Action, you can specify which controller to look for the ActionResult in with RedirectToAction("ActionName", "ControllerName"). If no Controller is specified, it assumes you want to use the same controller that you are currently in.
yes, Tot Zam are ok, and you need to create an action result method on your controller, this should be bind with a view
Found the issue.
Apparently I need to use Redirect(), not RedirectToAction() for my purposes.
Once I changed this, it rendered the correct URL without adding /Home to it
My goal is have the link appear as mydomain.com/viewPhone/1
Currently, the link is appearing as Home/phoneCatalog , and without displaying my ID
ROUTING
routes.MapRoute(
name: "phoneCatalog",
url: "viewPhone/{phoneID}",
defaults: new { controller = "Home", action = "phoneCatalog",}
);
CONTROLLER
public ActionResult phoneCatalog(int phoneID)
{
//CODE HERE
}
MVC VIEW
<span class="floatL w100">#Html.ActionLink(title, "phoneCatalog", "Home", new { phoneID = orderItem.phoneID }, null)
</span>
Use #Html.RouteLink instead. You probably still have the fall-back {controller}/{action}/{id} route defined.
#Html.RouteLink(title, "phoneCatalog", new { phoneID = orderItem.phoneID })
You should use attribute routing. It gives you more flexibility if you like different names for your actions rather than default values.
It is easy to use.
Check out:
http://blogs.msdn.com/b/webdev/archive/2013/10/17/attribute-routing-in-asp-net-mvc-5.aspx
[Route("viewPhone/{phoneID:int}")]
public ActionResult phoneCatalog(int phoneID)
{
//CODE HERE
}
Try this.
I have a single controller and view working that calls a web service, and returns a result. At the moment, it's my default controller, called Home, and it uses the Index view page.
It's working. I can post data and then put something on the refreshed screen. It reloads the same view.
Now, once I submit, and I get a good reply, I want to load a different controller/view.
My routes look like this right now:
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Home",
"{lang}",
new { controller = "Home", action = "Index", lang="English" });
routes.MapRoute(
"Location",
"{lang}",
new { controller = "Location", action = "Index", lang = "English" });
I created a controlled called Location, and it just has this:
//LocationController
public class LocationController : Controller
{
public ActionResult Index()
{
return View();
}
}
In my home controller, I am doing the logic, and then attempting to load the new page.
[HttpPost]
public ActionResult Index(HomeModel model)
{
var proxy = new Proxy();
var r = proxy.GetLocationByAddress(model.SearchString, o.ToString());
if(r==null)
{
ViewBag.Error = "Error during search";
return View(model);
}
ViewBag.Error = string.Format("Found {0} at {1}, {2}", r.StreetName, r.Latitude, r.Longitude);
return RedirectToAction("Index", "Location");
}
But when I run it, submit it, step through, it hits the RedirectToAction - but ... the Home screen simply refreshes. I never see the new Location view. What am I doing wrong here? I have't grasped Routes yet... I need to pass a new object to the Location.Index screen to display...
Your route mapping is incorrect, check this out: http://www.asp.net/mvc/tutorials/controllers-and-routing/creating-custom-routes-cs
routes.MapRoute(
"Location",
"Location/{lang}",
new { controller = "Location", action = "Index", lang = "English" });
I don't think so you need to make any changes. As in your case you want to load different controller with its respecting view you need below change only
replace this code return RedirectToAction("Index", "Location");
with this code return Redirect("http://www.yoursite.com/Location/Index");
Your change is like redirection from one page to another therefore you need to put your complete path here
please try & reply if any problem
I have two very simple routes
routes.MapRoute(
"post", // Route name
postPage + "/{slug}", // URL with parameters
new { controller = "Home", action = "Article" } // Parameter defaults
);
routes.MapRoute(
"page", // Route name
"{slug}", // URL with parameters
new { controller = "Home", action = "Page", slug = homePage} // Parameter defaults
);
And here is my controller logic
public ActionResult Article(string slug)
{
return View(repo.GetPost(slug));
}
public ActionResult Page(string slug)
{
if (slug.ToLower() == MetaData.PostsPage.ToLower())
return View("listPosts", repo.GetAllPosts());
else
return View("page", repo.GetPage(slug));
}
homePage and postPage are set from value's in the database. Allowing the user to define the default page as well as the page to show posts.
My issue occurs when adding an area named "Admin". I get a controller added to my RouteTable
context.MapRoute(
"Admin_default",
"Admin/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
Now when a user Access Admin/Account/Logon the page loads fine, but my debugger still tries to go into the Home controller and the Page action. But the RouteDebugger says it doesn't match the current request. I'm puzzled on how to fix this.
RouteDebugger screenshot: http://i.stack.imgur.com/7cpHm.png
Debugger going into my HomeControler Page AtionResult: http://i.stack.imgur.com/uSJBK.png
Actually the problem is, Area routes are overriding the global routes, to distinguish both the routes set the relevant namespace of area's controller in the context.MapRoute method in adminAreaRegistraton.cs file. i.e.
context.MapRoute(
"admin_default",
"admin/{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional },
null,
new string[] { "MVCApplication1.Areas.admin.Controllers" }
);
I found out the issue.
I had a favicon.ico set in the main area of my site, but not the Admin area.
So when I went to the Admin area the browser made a request for favicon.ico that got picked up by that route. Thats why my routes looked fine in the RouteDebugger, because they were.
Thanks for the help Kundan!
trying to map the following style of route: http://site.com/username in the same way that you can do http://www.twitter.com/user
My initial solution was to have these routes:
//site.com/rathboma - maps to user details for rathboma
routes.MapRoute("Users", "{id}", new { controller = "Users", action = "Details" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "oneday" } // Parameter defaults
);
And that was working fine, until I tried to do the following in my 'Links' controller:
public ActionResult Details(string id)
{
int newId;
if (!int.TryParse(id, out newId))
return RedirectToAction("Index");
WebLink results = Service.GetWebLink(newId, 5);
if (results == null)
return RedirectToAction("Index");
return View(results);
}
These RedirectToAction methods try and return the browser to http://site.com/Users (I do have a users controller) instead of directing to http://site.com/Links/index
Why is this is happening?
How should I be organizing my routes to make this work properly?
I'm happy sacrificing http://site.com/links and moving to http://site.com/links/index if I have to. But how would I enforce that?
Thanks to all for any help
EDIT:
I know what's causing this, it's trying to redirect to http://site.com/links (the index page), but links is being picked up as a username and redirecting to /users/details, when it can't find the user 'links' it tries to redirect to the UsersController Index action which maps to /users, and the cycle continues ('users' is not a user it can find so redirects infinately).
So I guess My sub-question is: how to I make mvc always use /links/index instead of just using /links for the index page?
Try adding this route before your Users route:
routes.MapRoute("Links",
"{controller}/{id}",
new { controller = "Links", action = "Details" });
This should then work for
http://mysite.com/Links/id
&
http://mysite.com/username
I believe changing RedirectToAction("Index"); to RedirectToAction("Index", "Links"); in your Links controller should solve the issue without having to change your routes.
The problem is you have two very greedy routes. What I'd do is to break apart the default route to less greedy routes like this :
routes.MapRoute("Links",
"Links/{id}",
new { controller = "Links", action = "Index" });
routes.MapRoute("Users",
"{id}",
new { controller = "Users", action = "Details" });
routes.MapRoute("Default",
"",
new { controller = "Home", action = "Index" });
Causing the urls to be like the following :
site.com/links/5 - hits the Links controller
site.com/name - hits the Users controller
site.com/ - hits the home controller