Rob
Rob

Reputation: 11788

Get controller and action name from within controller?

For our web application I need to save the order of the fetched and displayed items depending on the view - or to be precise - the controller and action that generated the view (and the user id of course, but that's not the point here).

Instead of just giving an identifier myself in each controller action (in order to use it for some view-dependant sorting of DB outputs), I thought that it would be safer and easier to create this identifier automatically from the controller and action method it gets called from.

How can I get the name of the controller and action from within the action method in a controller? Or do I need reflection for that?

Upvotes: 215

Views: 281542

Answers (14)

Erick Velasco
Erick Velasco

Reputation: 124

I know this is an old question, but maybe this can help to someone. For add to the John B answer, this is a solution for .NET 6.0 or higher.

namespace Microsoft.AspNetCore.Mvc.Rendering
    {
    public static class HtmlRequestHelper
    {
        public static string Id(this IHtmlHelper htmlHelper)
        {
            var routeValues = htmlHelper.ViewContext.RouteData.Values;

            if (routeValues.ContainsKey("id"))
                return (string)routeValues["id"];
            else if (htmlHelper.ViewContext.RouteData.Values["id"] != null)
                return htmlHelper.ViewContext.RouteData.Values["id"].ToString();

            return string.Empty;
        }

        public static string Controller(this IHtmlHelper htmlHelper)
        {
            var routeValues = htmlHelper.ViewContext.RouteData.Values;

            if (routeValues.ContainsKey("controller"))
                return (string)routeValues["controller"];

            return string.Empty;
        }

        public static string Action(this IHtmlHelper htmlHelper)
        {
            var routeValues = htmlHelper.ViewContext.RouteData.Values;

            if (routeValues.ContainsKey("action"))
                return (string)routeValues["action"];

            return string.Empty;
        }
    }
}

Upvotes: 1

Chris Ballance
Chris Ballance

Reputation: 34337

var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;
if (routeValues != null) 
{
    if (routeValues.ContainsKey("action"))
    {
        var actionName = routeValues["action"].ToString();
    }
    if (routeValues.ContainsKey("controller"))
    {
        var controllerName = routeValues["controller"].ToString();
    }
}

Upvotes: 14

John B
John B

Reputation: 20350

Here are some extension methods for getting that information (it also includes the ID):

public static class HtmlRequestHelper
{
    public static string Id(this HtmlHelper htmlHelper)
    {
        var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;

        if (routeValues.ContainsKey("id"))
            return (string)routeValues["id"];
        else if (HttpContext.Current.Request.QueryString.AllKeys.Contains("id"))
            return HttpContext.Current.Request.QueryString["id"];

        return string.Empty;
    }

    public static string Controller(this HtmlHelper htmlHelper)
    {
        var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;

        if (routeValues.ContainsKey("controller"))
            return (string)routeValues["controller"];

        return string.Empty;
    }

    public static string Action(this HtmlHelper htmlHelper)
    {
        var routeValues = HttpContext.Current.Request.RequestContext.RouteData.Values;

        if (routeValues.ContainsKey("action"))
            return (string)routeValues["action"];

        return string.Empty;
    }
}

Usage:

@Html.Controller();
@Html.Action();
@Html.Id();

Upvotes: 76

Mohamed Husama
Mohamed Husama

Reputation: 11

Try this code

add this override method to controller

protected override void OnActionExecuting(ActionExecutingContext actionExecutingContext)
{
   var actionName = actionExecutingContext.ActionDescriptor.ActionName;
   var controllerName = actionExecutingContext.ActionDescriptor.ControllerDescriptor.ControllerName;
   base.OnActionExecuting(actionExecutingContext);
}

Upvotes: 1

Matheus Miranda
Matheus Miranda

Reputation: 1805

Here is the simplest and most practical answer to getting a name:

var actionName = RouteData.Values["action"];
var controllerName = RouteData.Values["controller"];

Or

string actionName = RouteData.Values["action"].ToString();
string controllerName = RouteData.Values["controller"].ToString();

Code above tests with asp.net mvc 5.

Upvotes: 5

Hossein Hajizadeh
Hossein Hajizadeh

Reputation: 1485

 @this.ViewContext.RouteData.Values["controller"].ToString();

Upvotes: 6

Kurkula
Kurkula

Reputation: 6762

Add this to your base controller inside GetDefaults() method

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
         GetDefaults();
         base.OnActionExecuting(filterContext);
    }

    private void GetDefaults()
    {
    var actionName = filterContext.ActionDescriptor.ActionName;
    var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
    }

Implement your controllers to Basecontroller

Add a partial view _Breadcrumb.cshtml and add it in all required pages with @Html.Partial("_Breadcrumb")

_Breadcrumb.cshtml

<span>
    <a href="../@ViewData["controllerName"]">
        @ViewData["controllerName"]
    </a> > @ViewData["actionName"]
</span>

Upvotes: 2

Vadim Ovchinnikov
Vadim Ovchinnikov

Reputation: 14002

To remove need for ToString() call use

string actionName = ControllerContext.RouteData.GetRequiredString("action");
string controllerName = ControllerContext.RouteData.GetRequiredString("controller");

Upvotes: 1

adie wong
adie wong

Reputation: 51

Why not having something simpler?

Just call Request.Path, it will return a String Separated by the "/"

and then you can use .Split('/')[1] to get the Controller Name.

enter image description here

Upvotes: -8

bsb_coffee
bsb_coffee

Reputation: 7051

This seems to work nicely for me (so far), also works if you are using attribute routing.

public class BaseController : Controller
{
    protected string CurrentAction { get; private set; }
    protected string CurrentController { get; private set; }

    protected override void Initialize(RequestContext requestContext)
    {
        this.PopulateControllerActionInfo(requestContext);
    }

    private void PopulateControllerActionInfo(RequestContext requestContext)
    {
        RouteData routedata = requestContext.RouteData;

        object routes;

        if (routedata.Values.TryGetValue("MS_DirectRouteMatches", out routes))
        {
            routedata = (routes as List<RouteData>)?.FirstOrDefault();
        }

        if (routedata == null)
            return;

        Func<string, string> getValue = (s) =>
        {
            object o;
            return routedata.Values.TryGetValue(s, out o) ? o.ToString() : String.Empty;
        };

        this.CurrentAction = getValue("action");
        this.CurrentController = getValue("controller");
    }
}

Upvotes: 2

user3563149
user3563149

Reputation: 51

This is what I have so far:

var actionName = filterContext.ActionDescriptor.ActionName;
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;

Upvotes: 5

Mustafa ASAN
Mustafa ASAN

Reputation: 3825

You can get controller name or action name from action like any variable. They are just special (controller and action) and already defined so you do not need to do anything special to get them except telling you need them.

public string Index(string controller,string action)
   {
     var names=string.Format("Controller : {0}, Action: {1}",controller,action);
     return names;
   }

Or you can include controller , action in your models to get two of them and your custom data.

public class DtoModel
    {
        public string Action { get; set; }
        public string Controller { get; set; }
        public string Name { get; set; }
    }

public string Index(DtoModel baseModel)
    {
        var names=string.Format("Controller : {0}, Action: {1}",baseModel.Controller,baseModel.Action);
        return names;
    }

Upvotes: 2

sonjz
sonjz

Reputation: 5090

Might be useful. I needed the action in the constructor of the controller, and it appears at this point of the MVC lifecycle, this hasn't initialized, and ControllerContext = null. Instead of delving into the MVC lifecycle and finding the appropriate function name to override, I just found the action in the RequestContext.RouteData.

But in order to do so, as with any HttpContext related uses in the constructor, you have to specify the full namespace, because this.HttpContext also hasn't been initialized. Luckily, it appears System.Web.HttpContext.Current is static.

// controller constructor
public MyController() {
    // grab action from RequestContext
    string action = System.Web.HttpContext.Current.Request.RequestContext.RouteData.GetRequiredString("action");

    // grab session (another example of using System.Web.HttpContext static reference)
    string sessionTest = System.Web.HttpContext.Current.Session["test"] as string
}

NOTE: likely not the most supported way to access all properties in HttpContext, but for RequestContext and Session it appears to work fine in my application.

Upvotes: 24

Andrei
Andrei

Reputation: 56688

string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();

Upvotes: 404

Related Questions