【发布时间】:2011-11-23 09:02:34
【问题描述】:
好的,我正在开发一个类似 MVC CMS 的网站,并且在声明路由时我使用了以下模式。我将动作名称和控制器名称封装到这样的类中
public class UrlUtilsUnhandledErrorsExtensions
{
private readonly UrlHelper _urlHelper;
public UrlUtilsUnhandledErrorsExtensions(UrlHelper urlHelper)
{
_urlHelper = urlHelper;
}
public String GetLatestErrors()
{
return _urlHelper.Action("GetLatestErrors", "UnhandledErrors");
}
}
那就不用写了
@Url.Action("GetLatestErrors", "UnhandledErrors")
我写
@Url.Action(Url.Utils().UnhandledErrors().GetLatestErrors())
我发现这种方法更容易维护,因为如果控制器名称更改,我只需更改一个类。
这适用于任何链接、控制器重定向(返回 Redirect(...))以及任何接受由返回的虚拟路径的任何东西
public String GetLatestErrors()
{
return _urlHelper.Action("GetLatestErrors", "UnhandledErrors");
}
但问题来了:我不能在这种方法中使用 Html.Action()。它需要控制器名称和动作名称,但我希望它使用虚拟路径。 在四处挖掘和研究 MVC 源代码后,我意识到我需要编写自己的 Html.Action 扩展方法,它只接受虚拟路径。
这是我的解决方案
public void ActionFromUrl(this HtmlHelper htmlHelper, String url)
{
RouteValueDictionary rvd = null;
rvd = new RouteValueDictionary();
String action = String.Empty;
String controller = String.Empty;
foreach (Route route in htmlHelper.RouteCollection)
{
if (route.Url == url.Substring(1)) // url starts with / for some reason
{
action = route.Defaults["action"] as String;
controller = route.Defaults["controller"] as String;
break;
}
}
RequestContext rc = ((MvcHandler)HttpContext.Current.CurrentHandler).RequestContext;
rc.RouteData.Values["action"] = action;
rc.RouteData.Values["controller"] = controller;
IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
IController controllerImpl = factory.CreateController(rc, controller);
controllerImpl.Execute(rc);
}
它可以工作,但由于它基于 Html.RenderAction 方法,它只是直接写入输出,所以在我看来,当我编写以下代码时
@{ Html.ActionFromUrl(Url.Utils().UnhandledErrors().GetLatestErrors()); }
它首先呈现我的部分,最重要的是,然后是 html 的其余部分。 这不是我想要的结果,所以我必须像 Html.Action 那样找出将结果呈现为字符串的方法。我已经用 dotPeek 查看了源代码,但不知道如何完全混合它。
我的问题是:我做错了吗?或者我如何编写 Html.Action 重载以便它接受虚拟路径并返回 MvcHtmlString ?
【问题讨论】:
-
为了避免大规模替换控制器名称更改,我使用了一个包含字符串常量的静态类。在 ActionLink 中,我只使用 ClassName.ConstantName。
标签: c# asp.net-mvc