如何在ASP.NET MVC中获取不带参数的Action URL

6

我有一个在IIS虚拟目录中运行的ASP.NET MVC Web应用程序。在应用程序中,我有一个名为Id的参数的Action。

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

当我调用带有参数123的Action时,生成的URL如下:
http://mywebsite.net/MyProject/MyController/MyAction/123

在基本控制器中,如何优雅地找到没有任何参数的操作的URL?我要获取的字符串是:/MyProject/MyController/MyAction
有关此事的其他问题已经有人提问过,但它们并未涵盖这些情况。例如,Request.Url.GetLeftPart仍然会给我Id。

尝试获取路径,然后删除权限,参见 https://msdn.microsoft.com/zh-cn/library/system.uri.getleftpart(v=vs.110).aspx - monkeyhouse
这给了我/MyProject/MyController/MyAction/123,但这不是我想要的。 - Huseyin Yagli
4个回答

2

您是否在默认路由中指定了id为可选项 (UrlParameter.Optional)?

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

更新 #1: 以下是两种解决方案,一种适用于 id 作为查询字符串 (?id={id}),另一种适用于 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));

更新 #2:好的,这是另一个尝试。它适用于所有情况(?id=?id=123//123/)并且我已经将操作签名中的 Id 改为了 int? 而不是 int(需要重构):

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);

是的,参数id是可选的,但它与此有任何关系吗? - Huseyin Yagli
在你的原帖中加入你展示的操作的方法签名以及你在代码中如何调用它们是一个好主意。 - trashr0x
在您的第二个解决方案中,如果省略了id参数(因为它是可选的),地址将为:/MyProject/MyController/。我会错过操作名称。 - Huseyin Yagli
我更新了我的回答,请看一下。 - trashr0x

2

@trashr0x的回答解决了问题的大部分,但忽略了MyProject部分,并且不需要使用字典来构建所需的字符串。这里提供一个简单的解决方案:

var result = string.Join("/", new []{ 
    Request.ApplicationPath, 
    RouteData.Values["controller"], 
    RouteData.Values["action"] 
});

1
谢谢。这给出了精确的结果。 - Huseyin Yagli
看起来我也错过了MyProject的要求。更简单、更优雅。 - trashr0x

1

试试这个:

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

但是如果没有查询字符串,这样会出错。
因此,您也可以直接尝试:
Request.Url.AbsoluteUri

1
第一行抛出ArgumentException异常,因为Request.Url.Query为空。在这种情况下,Id参数是Uri的一部分,而不是查询参数。第二个给出http://mywebsite.net/MyProject/MyController/MyAction/123。 - Huseyin Yagli

1
你尝试过以下内容吗:
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 = "" });

urlAction 是 "/MyProject/MyController/MyAction/123"。 - Huseyin Yagli
你说得对,我之前没有意识到这个问题。我已经编辑了我的回答,现在应该可以正常工作了。 - Mauricio Ramalho
现在,urlAction是正确的,但对于没有id作为参数的操作将无法工作。由于我在基础控制器中使用此代码,因此该代码将运行所有操作。 - Huseyin Yagli
除了id之外,您还会向操作传递哪些其他参数?如果您传递其他参数,例如Name,则应将其传递为/MyProject/MyController/MyAction?Name=something,在这种情况下,我提供的第一种解决方案将起作用。如果您不关心MVC操作的REST-like URL,只需从默认路由中删除“/{id}”,则ID应传递为/MyController/MyAction?id=1。您将不再有问题。 - Mauricio Ramalho
你说得对,如果我去掉 /id 就不会有问题,但如果可以的话我不想去掉它。 - Huseyin Yagli
1
如果您不想放弃并保留默认路由,那么您只需要关注名为id的参数,它是唯一一个在URL上具有REST-like行为的参数。所有其他参数都将作为?param1=x&param2=y传递。因此,我的答案中的解决方案将起作用。如果您决定重写路由,以便所有参数都以REST-like方式传递:/MyProject/MyController/MyAction/123/param1Value/param2Value,那么您将无法对问题拥有优雅的解决方案,因为您将始终依赖于接收到的参数数量。 - Mauricio Ramalho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接