0

I have a weird problem with some routing in MVC. Here's my scenario:

  1. The user gets presented to the front page, once visiting the site: testproject.com:57416/Home.
  2. The user has a menu on the left side, with the menu item "Solutions".
  3. The user presses the menu item "Solutions" and the menu item expands, showing 5 sub items.
  4. The user presses the sub item "Demo", and redirects to testproject.com:57416/Solutions/SetLayout?layoutString=page1%7Csize15
  5. As the param layoutString is defined, the grid (DevExpress) know how to filter the data to show.
  6. The grid is presented to the user, and (s)he can now navigate around the grid, manipulating the layout.
  7. The user now wants to see the clean Demo layout again, and (s)he presses the menu item "Solutions" -> sub item "Demo".
  8. 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
  9. 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">
    <a href ="#" class="navigation-submenu-toggler show-solution-views">Solutions</a>

    <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 }
);
tereško
  • 58,060
  • 25
  • 98
  • 150
Detilium
  • 2,868
  • 9
  • 30
  • 65
  • @SometimesCode already have, just forgot to put it in. Has been corrected – Detilium May 27 '16 at 10:13
  • Have a look at [Why map special routes first before common routes in asp.net mvc](http://stackoverflow.com/a/35674633/181087) for the reason why this happens and a list of possible ways to fix it. Suffice to say here that your routing is misconfigured. `RouteLink` is a workaround (not a solution) to the problem because incoming requests are not matching the route you intended them to, and you have unreachable execution paths in your route table. – NightOwl888 Jun 01 '16 at 12:17

3 Answers3

0

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.

Tetsuya Yamamoto
  • 24,297
  • 8
  • 39
  • 61
  • I understand that would solve any problems related with the `layoutString` being empty. What I don't understand is why it's empty? – Detilium May 27 '16 at 10:13
0

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..

Sometimes Code
  • 591
  • 3
  • 14
  • 33
  • I forgot to put that in. I already have the fifth parameter = null. My apologies. Has been corrected – Detilium May 27 '16 at 10:12
0

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");
}
Detilium
  • 2,868
  • 9
  • 30
  • 65