133

How do you get the current area name in the view or controller?

Is there anything like ViewContext.RouteData.Values["controller"] for areas?

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
user202448
  • 2,552
  • 5
  • 22
  • 25

14 Answers14

232

From MVC2 onwards you can use ViewContext.RouteData.DataTokens["area"]

Ciaran Gallagher
  • 3,895
  • 9
  • 53
  • 97
artvolk
  • 9,448
  • 11
  • 56
  • 85
  • 22
    If not in an area, ViewContext.RouteData.DataTokens["area"] == null. – user202448 May 10 '10 at 21:27
  • 4
    Lol.. the joke is on you @Dante ... well to be fair it is called `ASP.NET Core 1.0` instead of `MVC6`.. :-) – Rosdi Kasim Feb 13 '16 at 09:54
  • FYI - figured out what was wrong with my ajax POST were not working... please check ur ajax requests have the area in the URL... they may still find!!! the view, but they wont maintain the area... if the url is missing the area when the request is made. – Seabizkit Aug 27 '18 at 09:12
49
HttpContext.Current.Request.RequestContext.RouteData.DataTokens["area"]
JackPoint
  • 4,031
  • 1
  • 30
  • 42
Slava
  • 3,445
  • 1
  • 20
  • 16
  • 3
    This is the best, *universal* way to get the area info, if you're not within a view or controller. Thanks for posting this! – bdrelling Oct 02 '13 at 01:36
20

You can get it from the controller using:

ControllerContext.RouteData.DataTokens["area"]
JackPoint
  • 4,031
  • 1
  • 30
  • 42
Matt Penner
  • 1,082
  • 12
  • 22
  • @user202338 Areas were introduced in MVC2 so I would suspect so, but I'm not sure if they have changed the way they populate the DataTokens collection. I do see posts like this one: [link](http://forums.asp.net/t/1549680.aspx/1) that talk about using it in MVC2. – Matt Penner Aug 01 '11 at 18:03
15

In ASP.NET Core 1.0 the value is found in

ViewContext.RouteData.Values["area"];

zerox981
  • 346
  • 3
  • 5
9

I just wrote a blog entry about this, you can visit that for more details, but my answer was to create an Extension Method, shown below.

The key kicker was that you pull the MVC Area from the .DataTokens and the controller/action from the .Values of the RouteData.

public static MvcHtmlString TopMenuLink(this HtmlHelper htmlHelper, string linkText, string controller, string action, string area, string anchorTitle)
    {
        var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
        var url = urlHelper.Action(action, controller, new { @area = area });

        var anchor = new TagBuilder("a");
        anchor.InnerHtml = HttpUtility.HtmlEncode(linkText);
        anchor.MergeAttribute("href", url);
        anchor.Attributes.Add("title", anchorTitle);

        var listItem = new TagBuilder("li");
        listItem.InnerHtml = anchor.ToString(TagRenderMode.Normal);

        if (CheckForActiveItem(htmlHelper, controller, action, area))
            listItem.GenerateId("menu_active");

        return MvcHtmlString.Create(listItem.ToString(TagRenderMode.Normal));
    }

    private static bool CheckForActiveItem(HtmlHelper htmlHelper, string controller, string action, string area)
    {
        if (!CheckIfTokenMatches(htmlHelper, area, "area"))
            return false;

        if (!CheckIfValueMatches(htmlHelper, controller, "controller"))
            return false;

        return CheckIfValueMatches(htmlHelper, action, "action");
    }

    private static bool CheckIfValueMatches(HtmlHelper htmlHelper, string item, string dataToken)
    {
        var routeData = (string)htmlHelper.ViewContext.RouteData.Values[dataToken];

        if (routeData == null) return string.IsNullOrEmpty(item);

        return routeData == item;
    }

    private static bool CheckIfTokenMatches(HtmlHelper htmlHelper, string item, string dataToken)
    {
        var routeData = (string)htmlHelper.ViewContext.RouteData.DataTokens[dataToken];

        if (dataToken == "action" && item == "Index" && string.IsNullOrEmpty(routeData))
            return true;

        if (dataToken == "controller" && item == "Home" && string.IsNullOrEmpty(routeData))
            return true;

        if (routeData == null) return string.IsNullOrEmpty(item);

        return routeData == item;
    }

Then you can implement it as below :

<ul id="menu">
@Html.TopMenuLink("Dashboard", "Home", "Index", "", "Click here for the dashboard.")
@Html.TopMenuLink("Courses", "Home", "Index", "Courses", "List of our Courses.")
</ul>
JackPoint
  • 4,031
  • 1
  • 30
  • 42
christesene
  • 91
  • 1
  • 2
  • For some reason I can't find the `area` token in the `Values` but needed to look in the `DataTokens` ... no idea why. – Syska Jan 04 '14 at 22:07
8

I created an extension method for RouteData that returns the current area name.

public static string GetAreaName(this RouteData routeData)
{
    object area;
    if (routeData.DataTokens.TryGetValue("area", out area))
    {
        return area as string;
    }

    return null;
}

Since RouteData is available on both ControllerContext and ViewContext it can be accessed in your controller and views.

It is also very easy to test:

[TestFixture]
public class RouteDataExtensionsTests
{
    [Test]
    public void GetAreaName_should_return_area_name()
    {
        var routeData = new RouteData();
        routeData.DataTokens.Add("area", "Admin");
        routeData.GetAreaName().ShouldEqual("Admin");
    }

    [Test]
    public void GetAreaName_should_return_null_when_not_set()
    {
        var routeData = new RouteData();
        routeData.GetAreaName().ShouldBeNull();
    }
}

There is no need to check if RouteData.DataTokens is null since this always initialized internally.

JackPoint
  • 4,031
  • 1
  • 30
  • 42
Ben Foster
  • 34,340
  • 40
  • 176
  • 285
8

Get area name in View (.NET Core 2.2):

ViewContext?.ActionDescriptor?.RouteValues["area"]
SZL
  • 805
  • 8
  • 12
3

I know this is old, but also, when in a filter like ActionFilter, the context does not easily provide you with the area information.

It can be found in the following code:

var routeData = filterContext.RequestContext.RouteData;

if (routeData.DataTokens["area"] != null)
    area = routeData.DataTokens["area"].ToString();

So the filterContext is being passed in on the override and the correct RouteData is found under the RequestContext. There is a RoutData at the Base level, but the DataTokens DO NOT have the area in it's dictionary.

JackPoint
  • 4,031
  • 1
  • 30
  • 42
gcoleman0828
  • 1,541
  • 3
  • 30
  • 49
3

MVC Futures has an AreaHelpers.GetAreaName() method. However, use caution if you're using this method. Using the current area to make runtime decisions about your application could lead to difficult-to-debug or insecure code.

Levi
  • 32,628
  • 3
  • 87
  • 88
  • 1
    Is there a method like that for controllers? I hate using string literals into a collection. – Erick T Nov 04 '10 at 23:38
  • for controller use `this.GetName()` and for the current Method use `MethodBase.GetCurrentMethod().Name` – Nerdroid Aug 18 '15 at 03:02
3

To get area name in the view, in ASP.NET Core MVC 2.1:

@Context.GetRouteData().Values["area"]
Netstep
  • 492
  • 3
  • 12
2

I dont know why but accepted answer is not working. It returns null with e.g ( maybe about mvc, i use .net core )

http://localhost:5000/Admin/CustomerGroup

I always debug the variable and fetch data from in it.

Try this. It works for me

var area = ViewContext.RouteData.Values["area"]

Detailed logical example

Layout = ViewContext.RouteData.Values["area"] == null ? "_LayoutUser" : "_LayoutAdmin";
Farukest
  • 1,498
  • 21
  • 39
1

Asp .Net Core 3.1

Scenario: I wanted to retrieve the current area name in a ViewCompnent Invoke method.

  public IViewComponentResult Invoke()
  {
       string areaName = this.RouteData.Values["area"];

       //Your code here...

       return View(items);
  }
JohnnyJaxs
  • 321
  • 3
  • 6
0

I know this is a very very old post but we can use the Values Property exactly the same way as the DataTokens

Url.RequestContext.RouteData.Values["action"] worked for me.

0

In MVC 5, this seems to be needed now. When in a Controller, pass this.ControllerContext.RouteData to this routine:


    /// <summary>
    /// Get the name of the Area from the RouteData
    /// </summary>
    /// <param name="routeData"></param>
    /// <returns></returns>
    private static string GetArea(RouteData routeData)
    {
      var area = routeData.DataTokens["area"]?.ToString();
      if (area != null)
      {
        // this used to work
        return area;
      }

      // newer approach
      var matchedList = routeData.Values["MS_DirectRouteMatches"] as List<RouteData>;
      if (matchedList != null)
      {
        foreach (var matchedRouteData in matchedList)
        {
          if (matchedRouteData.DataTokens.TryGetValue("area", out var rawArea))
          {
            return rawArea.ToString();
          }
        }
      }

      return "";
    }
Glen Little
  • 6,951
  • 4
  • 46
  • 68
  • It looks like this has been the case for a number of years when using attribute routing. See also https://stackoverflow.com/a/30482853/32429 – Glen Little Jul 14 '22 at 17:10