6

I have a ASP.NET MVC Web application that runs in a virtual directory on IIS. In the application, I have an Action which takes a parameter named Id.

public class MyController : MyBaseController 
{
    public ActionResult MyAction(int id)
    {
        return View(id);
    }
}

When I call the Action with the parameter 123 the resulting URL is like this:

http://mywebsite.net/MyProject/MyController/MyAction/123

In the base controller, how do I elegantly find the URL of the Action without any parameters? The string I'm trying to get is: /MyProject/MyController/MyAction

There are other questions asked about this but they do not cover these cases. For example Request.Url.GetLeftPart still gives me the Id.

2
  • try getting the Path then removing the Authority, see msdn.microsoft.com/en-us/library/… Commented Jul 18, 2016 at 2:04
  • That gives me /MyProject/MyController/MyAction/123 which is not what I want. Commented Jul 21, 2016 at 14:10

4 Answers 4

2

@trashr0x's answer solves the biggest part of the problem, but misses the MyProject part and there is no need for a dictionary to construct the asked string. here is a simple solution:

var result = string.Join("/", new []{ 
    Request.ApplicationPath, 
    RouteData.Values["controller"], 
    RouteData.Values["action"] 
});
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. This gives the exact result.
Looks like I've missed the MyProject requirement too. Much simpler and elegant.
2

Have you tried the following:

string actionName = HttpContext.Request.RequestContext.RouteData.Values["Action"].ToString();
string controllerName = HttpContext.Request.RequestContext.RouteData.Values["Controller"].ToString();
var urlAction = Url.Action(actionName, controllerName, new { id = "" });

6 Comments

urlAction is "/MyProject/MyController/MyAction/123"
You're right, I was not aware of this. Edited my answer, it should work now.
Now, urlAction is correct, but this will not work for action that don't have id as parameter. Since I'm using this code in the base controller, the code will be run for all actions.
What other parameters do you pass to your Actions besides id? If you pass other parameters, e.g., Name, it should be passed as /MyProject/MyController/MyAction?Name=something and in this case, the first solution I had would work. If you don't care about the REST-like URLs to your MVC actions, just drop the "/{id}" from your Default route and the IDs should be passed as /MyController/MyAction?id=1. You won't have a problem anymore.
If you don't want to drop it and leave you Default route as is, you only have to worry about the parameter called id, which is the only one that will have the REST-like behaviour on the URL. All other parameters will be passed as ?param1=x&param2=y. Hence, the solution in my answer will work. If you decide to go rewrite your routes so that all parameters are passed in a REST-like manner: /MyProject/MyController/MyAction/123/param1Value/param2Value, then you won't be able to have an elegant solution to your problem because you will always be dependent on how many parameters are received.
|
2

Have you specified that id is set to optional (UrlParameter.Optional) in your default routing?

routes.MapRoute(
    // route name
    "Default",
    // url with parameters
    "{controller}/{action}/{id}",
    // default parameters 
    new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

Update #1: Below are two solutions, one for when id is a query string (?id={id}) and one when it's part of the Uri (/{id}/):

var localPath = Request.Url.LocalPath;
// works with ?id=123
Debug.WriteLine("Request.Url.LocalPath: " + localPath);
// works with /123/
Debug.WriteLine("Remove with LastIndexOf: " + localPath.Remove(localPath.LastIndexOf('/') + 1));

Update #2: Okay so here's another go at it. It works with all scenarios (?id=, ?id=123, /, /123/) and I've changed Id in the action signature to be an int? rather than an int (refactoring needed):

var mvcUrlPartsDict = new Dictionary<string, string>();
var routeValues = HttpContext.Request.RequestContext.RouteData.Values;

if (routeValues.ContainsKey("controller"))
{
    if (!mvcUrlPartsDict.ContainsKey("controller"))
    {
        mvcUrlPartsDict.Add("controller", string.IsNullOrEmpty(routeValues["controller"].ToString()) ? string.Empty : routeValues["controller"].ToString());
    }
}

if (routeValues.ContainsKey("action"))
{
    if (!mvcUrlPartsDict.ContainsKey("action"))
    {
        mvcUrlPartsDict.Add("action", string.IsNullOrEmpty(routeValues["action"].ToString()) ? string.Empty : routeValues["action"].ToString());
    }
}

if (routeValues.ContainsKey("id"))
{
    if (!mvcUrlPartsDict.ContainsKey("id"))
    {
        mvcUrlPartsDict.Add("id", string.IsNullOrEmpty(routeValues["id"].ToString()) ? string.Empty : routeValues["id"].ToString());
    }
}

var uri = string.Format("/{0}/{1}/", mvcUrlPartsDict["controller"], mvcUrlPartsDict["action"]);
Debug.WriteLine(uri);

4 Comments

Yes, the parameter id is optional but does it have anything to do with this?
It would be a good idea to add in your OP the method signatures of the actions you are showing in your example, as well as how you call them in your code.
In your second solution, if the id parameter is omitted (since it is optional) the address will be: /MyProject/MyController/. I'll be missing the action name.
Updated my answer, have a look.
1

Try this:

Request.Url.AbsoluteUri.Replace(Request.Url.Query, String.Empty);

but this will give an error if there's no Query string

So, you can also try directly:

Request.Url.AbsoluteUri

1 Comment

The first line throws ArgumentException because Request.Url.Query is empty. The Id parameter is part of the Uri not a query parameter in this case. The second gives mywebsite.net/MyProject/MyController/MyAction/123

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.