简体   繁体   中英

How to determine Controller's Area in ASP.NET MVC

I have an ActionDescriptor from which I retrieve information about an action and its controller:

ActionDescriptor desc = ...;
string action = desc.ActionName;
string controller = desc.ControllerDescriptor.ControllerName;
string area = ?;

I'm wondering if there is a better way to determine the controller's area than having to parse its namespace, which I'm currently doing like so:

// e.g., Company.Areas.Foo.Controllers
var parts = desc.ControllerDescriptor.ControllerType.Namespace.Split('.').ToList();
var areaIndex = parts.IndexOf("Areas");
if (areaIndex > -1) area = parts[areaIndex + 1];
// area = "Foo"

EDIT:

I should clarify that I'm not in the context of a view or controller and am trying to determine the area only given its Type information and such.

ASP.NET MVC doesn't keep the AreaRegistration objects around, but AreaRegistration is how ASP.NET determines which Area a Controller belongs to.

You can just enumerate AreaRegistration types on your own within the relevant assemblies, then determine if the AreaRegistration's namespace is a prefix of the Controller's namespace. Once resolved, an AreaRegistration instance has the Area name as a property.

Rather than using reflection, you could include this in your AreaRegistration implementations themselves by providing a base class that implements RegisterArea and maintains a Namespace=>Area map.

Here's what I've scrambled together to get this working for every controller:

private string findAreaForControllerType(Type controllerType)
{
    var areaTypes = getAllAreasRegistered();

    foreach (var areaType in areaTypes)
    {
        if (controllerType.Namespace.StartsWith(areaType.Namespace))
        {
            var area = (AreaRegistration)Activator.CreateInstance(areaType);
            return area.AreaName;
        }
    }
    return string.Empty;
}

private IEnumerable<Type> getAllAreasRegistered()
{
    var assembly = getWebEntryAssembly();
    var areaTypes = assembly.GetTypes().Where(t => t.IsSubclassOf(typeof(AreaRegistration)));

    return areaTypes;
}

static private Assembly getWebEntryAssembly()
{
    if (System.Web.HttpContext.Current == null ||
        System.Web.HttpContext.Current.ApplicationInstance == null)
    {
        return null;
    }

    var type = System.Web.HttpContext.Current.ApplicationInstance.GetType();
    while (type != null && type.Namespace == "ASP")
    {
        type = type.BaseType;
    }

    return type == null ? null : type.Assembly;
}

This fetches all the AreaRegistration types from the Web project assembly and matches the namespace of your controller to the namespace of the area. Ie When you have a controller of type My.WebProject.Areas.Admin.UserController the system will return the Admin area based on the match of namespace My.WebProject.Areas.Admin .

From a view:

ViewContext.RouteData.DataTokens["area"]

From a controller:

ControllerContext.RouteData.DataTokens["area"]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM