How do I get the Controller and Action names from the Referrer Uri?
Asked Answered
C

9

34

There's a lot of information for building Uris from Controller and Action names, but how can I do this the other way around?

Basically, all I'm trying to achieve is to get the Controller and Action names from the referring page (i.e. Request.UrlReferrer). Is there an easy way to achieve this?

Cyclo answered 12/1, 2012 at 4:17 Comment(1)
#7088163Heartache
G
56

I think this should do the trick:

// Split the url to url + query string
var fullUrl = Request.UrlReferrer.ToString();
var questionMarkIndex = fullUrl.IndexOf('?');
string queryString = null;
string url = fullUrl;
if (questionMarkIndex != -1) // There is a QueryString
{    
    url = fullUrl.Substring(0, questionMarkIndex); 
    queryString = fullUrl.Substring(questionMarkIndex + 1);
}   

// Arranges
var request = new HttpRequest(null, url, queryString);
var response = new HttpResponse(new StringWriter());
var httpContext = new HttpContext(request, response)

var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

// Extract the data    
var values = routeData.Values;
var controllerName = values["controller"];
var actionName = values["action"];
var areaName = values["area"];

My Visual Studio is currently down so I could not test it, but it should work as expected.

Grant answered 12/1, 2012 at 16:24 Comment(8)
You might wanna edit this code a little. If your referrer doesn't have a querystring, you'll end up trying to call fullUrl.Substring(0, -1).Hydrazine
For me I couldn't get the area name in the way you describe from routeData.Values, Instead I used routeData.DataTokens["area"].Sovran
Might want to consider wrapping from // Arranges down in: using (StringWriter sw = new StringWriter(CultureInfo.InvariantCulture)) { } and changing to var response = new HttpResponse(sw); to avoid VS code analysis complaining that StringWriter should be disposed.Acquaint
everything is populating apart from areaName, this is always null, any ideas?Fideicommissum
@Fideicommissum I'm no longer use asp.net 4.x (only core), but you should check what the value are in values.Grant
The StringWriter needs to be disposed. Wrap it in a using block.Wriggler
routeData.Values is always emptyFootmark
You need a check on your first line if Request.UrlReferrer == null before doing .ToString() on it !Liquefy
W
5

To expand on gdoron's answer, the Uri class has methods for grabbing the left and right parts of the URL without having to do string parsing:

url = Request.UrlReferrer.GetLeftPart(UriPartial.Path);
querystring = Request.UrlReferrer.Query.Length > 0 ? uri.Query.Substring(1) : string.Empty;

// Arranges
var request = new HttpRequest(null, url, queryString);
var response = new HttpResponse(new StringWriter());
var httpContext = new HttpContext(request, response)

var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

// Extract the data    
var values = routeData.Values;
var controllerName = values["controller"];
var actionName = values["action"];
var areaName = values["area"];
Woozy answered 30/6, 2017 at 15:37 Comment(3)
use querystring = Request.UrlReferre.GetComponents(UriComponents.Query,UriFormat.UriEscaped); for the querystring instead.Wriggler
querystring = Request.UrlReferrer.GetComponents(UriComponents.Query,UriFormat.UriEscaped);Footmark
You need a check on your first line if Request.UrlReferrer == null before calling any methods on it !Liquefy
I
2

To add to gdoran's accepted answer, I found that the action doesn't get populated if a custom route attribute is used. The following works for me:

public static void SetUpReferrerRouteVariables(HttpRequestBase httpRequestBase, ref string previousAreaName, ref string previousControllerName, ref string previousActionName)
{
    // No referrer found, perhaps page accessed directly, just return.
    if (httpRequestBase.UrlReferrer == null) return;

    // Split the url to url + QueryString.
    var fullUrl = httpRequestBase.UrlReferrer.ToString();
    var questionMarkIndex = fullUrl.IndexOf('?');
    string queryString = null;
    var url = fullUrl;
    if (questionMarkIndex != -1) // There is a QueryString
    {
        url = fullUrl.Substring(0, questionMarkIndex);
        queryString = fullUrl.Substring(questionMarkIndex + 1);
    }

    // Arrange.
    var request = new HttpRequest(null, url, queryString);
    var response = new HttpResponse(new StringWriter());
    var httpContext = new HttpContext(request, response);

    var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));
    if (routeData == null) throw new AuthenticationRedirectToReferrerDataNotFoundException();

    // Extract the data.
    var previousValues = routeData.Values;
    previousAreaName = previousValues["area"] == null ? string.Empty : previousValues["area"].ToString();
    previousControllerName = previousValues["controller"] == null ? string.Empty : previousValues["controller"].ToString();
    previousActionName = previousValues["action"] == null ? string.Empty : previousValues["action"].ToString();
    if (previousActionName != string.Empty) return;
    var routeDataAsListFromMsDirectRouteMatches = (List<RouteData>)previousValues["MS_DirectRouteMatches"];
    var routeValueDictionaryFromMsDirectRouteMatches = routeDataAsListFromMsDirectRouteMatches.FirstOrDefault();
    if (routeValueDictionaryFromMsDirectRouteMatches == null) return;
    previousActionName = routeValueDictionaryFromMsDirectRouteMatches.Values["action"].ToString();
    if (previousActionName == "") previousActionName = "Index";
}
Illconsidered answered 20/11, 2014 at 14:48 Comment(1)
Well done on your first line, you are checking for null in Request.UrlReferrer == null , which the other answers didn't do !Liquefy
W
2

Here is a lightweight way to do this without creating response objects.

var values = RouteDataContext.RouteValuesFromUri(Request.UrlReferrer);

var controllerName = values["controller"];
var actionName = values["action"];

Uses this custom HttpContextBase class

public class RouteDataContext : HttpContextBase {
    public override HttpRequestBase Request { get; }

    private RouteDataContext(Uri uri) {
        var url = uri.GetLeftPart(UriPartial.Path);
        var qs = uri.GetComponents(UriComponents.Query,UriFormat.UriEscaped);

        Request = new HttpRequestWrapper(new HttpRequest(null,url,qs));
    }

    public static RouteValueDictionary RouteValuesFromUri(Uri uri) {
        return RouteTable.Routes.GetRouteData(new RouteDataContext(uri)).Values;
    }
}
Wriggler answered 25/7, 2017 at 23:11 Comment(0)
P
1

@gordon's solution works, but you need to use

 return RedirectToAction(actionName.ToString(), controllerName.ToString(),values);

if you want to go to previous action

Parenteau answered 19/10, 2015 at 6:39 Comment(0)
C
0

The RouteData object can access this info:

 var controller = RouteData.Values["controller"].ToString();
 var action = RouteData.Values["action"].ToString();
Calia answered 12/1, 2012 at 4:25 Comment(1)
That will give you the current data, not the previous data.Grant
D
0

This is a method I made to extract url simplified from referrer because I had token (finished with "))/") in my URL so you can extract easily controller and action from this:

private static string GetURLSimplified(string url)
    {
        string separator = "))/";
        string callerURL = "";

        if (url.Length > 3)
        {
            int index = url.IndexOf(separator);
            callerURL = url.Substring(index + separator.Length);
        }
        return callerURL;
    }
Doublequick answered 2/10, 2013 at 8:8 Comment(0)
M
-1

I don't believe there is any built-in way to retrieve the previous Controller/Action method call. What you could always do is wrap the controllers and action methods so that they are recorded in a persistent data store, and then when you require the last Controller/Action method, just retrieve it from the database (or whatever you so choose).

Martres answered 12/1, 2012 at 4:48 Comment(0)
G
-1

Why would you need to construct ActionLink from a url ? The purpose of ActionLink is just the opposite to make a url from some data. So in your page just do:

var fullUrl = Request.UrlReferrer.ToString();
<a href="@fullUrl">Back</a>
Guddle answered 25/12, 2013 at 20:12 Comment(1)
OP never says they want a link to the previous page or even an ActionLink at all. They want to know how to know the controller and action of the referrer.Walking

© 2022 - 2024 — McMap. All rights reserved.