7
Vote

T4MVC: Problem when not using areas, adds "?Area=" in the Querystring

description

Hi,

I don't know if this is simply a configuration issue that I am not aware of, but in my MVC3 project (where I don't use areas), I kept seeing the parameter "Area" being added to the querystring. This only happened when I was using the overloads of the methods Url.Action(ActionResult) and Html.ActionLink(ActionResult). To override this I changed the T4MVC.tt around line 310, in method InitMVCT4Result where it receives a string parameter for area. My code results in :

public static void InitMVCT4Result(this <#=ActionResultInterfaceName #> result, string area, string controller, string action) {
        result.Controller = controller;
        result.Action = action;
        result.RouteValueDictionary = new RouteValueDictionary();
        <# if (MvcVersion >= 2) { #>result.RouteValueDictionary.Add("Area", String.IsNullOrEmpty(area) ? null : area);<# } #> 
        result.RouteValueDictionary.Add("Controller", controller);
        result.RouteValueDictionary.Add("Action", action);
}

The difference is that I check if the "area" parameter is null or empty and add a null value, which does not include this in the querystring.

I have not really tested this change, just know that it fixes my case. If there is a better way to do this, please inform me. I hope it helps if anyone runs into the same problem.

Thank,
Kostas

comments

davidebbo wrote Jul 29, 2011 at 4:30 PM

This came up here: http://stackoverflow.com/questions/6755729/t4mvc-url-actionmvc-controller-action-renders-area-parameter-in-querystr. It would appear to be an MVC bug, and I'm discussing it with the MVC team. For now, the workaround should do if you're not using areas.

4eburek wrote Aug 7, 2011 at 11:19 PM

I can confirm that it looks like MVC bug
For myself I resolve it removing empty Area RouteValueDictionary item before passing it to UrlHelper.GenerateUrl()
private static string GetT4MvcUrl(HtmlHelper html, string routename, IT4MVCActionResult callInfo)
{
  if ( ( string )callInfo.RouteValueDictionary["Area"] == string.Empty )
    callInfo.RouteValueDictionary.Remove( "Area" );

  return UrlHelper.GenerateUrl( routename, callInfo.Action,
      callInfo.Controller, callInfo.RouteValueDictionary,
      html.RouteCollection, html.ViewContext.RequestContext, true );
}

davidebbo wrote Aug 8, 2011 at 4:33 AM

@4eburek: Copying my comment from the SO thread: the problem with your change is that I think it's not always correct. When you're in an Area view and you're trying to generate a link to a top level (non-Area) view, then passing an empty area is the correct thing to do to 'escape' the current area. But with your check that won't happen.

davidebbo wrote Dec 6, 2011 at 7:31 AM

It turns out that MVC only generates the bogus token if the app doesn't have any areas. So we should just fix T4MVC to only add this token if the app uses areas

panec wrote Dec 19, 2011 at 10:19 AM

I solve this issue in a very easy way, simply by adding to all routes that are not in area empty area route like this:
routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", area = "", id = UrlParameter.Optional });

markuspeter wrote Aug 2, 2013 at 3:17 PM

This problem still exists in T4MVC 3.7.1 and MVC 4:
@Url.Action(MVC.Controller.Action(), hostName: "www.t4mvc.org")
still adds the empty Area query parameter.

Since it is no more possible to use the quick workaround by commenting the line which adds the Area to the RouteValueDictionary, I'll use now:
public static string ActionT4MVC(this UrlHelper urlHelper, ActionResult result, string protocol = null, string hostName = null)
{
    var routeValues = result.GetRouteValueDictionary();
    if (routeValues.ContainsKey("Area")) routeValues.Remove("Area");
    return urlHelper.RouteUrl(null, routeValues, protocol ?? result.GetT4MVCResult().Protocol, hostName);
}

davidebbo wrote Aug 2, 2013 at 5:40 PM

A simpler workaround is to add a bogus area to your site. e.g.
  • Right click Project and choose Add / Area. Name it 'Dummy' (or whatever)
  • You can delete everything in there except for the DummyAreaRegistration.cs file

markuspeter wrote Aug 5, 2013 at 9:44 AM

Thank you David for the quick reply, works great. This is definitely the better workaround!

LaazyJ wrote Mar 1, 2014 at 9:53 AM

I'm finding this same problem only affects views that are rendered as part of a child action that returns a PartialViewResult.
The exact same call to Url.Action in a normal ViewResult does not add the 'Area=' parameter...

davidebbo wrote Mar 3, 2014 at 12:09 AM

@LaazyJ: could be, be either way, the workaround should help.

sergeype wrote Jan 15, 2015 at 2:11 PM

This workaround helped first:
"Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", area = "", id = UrlParameter.Optional });
but then I found that it didn't work for Attribute Routing, and attribute routing "?Area=" issue I have fix with that workaround:

A simpler workaround is to add a bogus area to your site. e.g.
Right click Project and choose Add / Area. Name it 'Dummy' (or whatever)
You can delete everything in there except for the DummyAreaRegistration.cs file

Thanks David.