将控制器操作渲染为字符串(使用虚拟路径,无操作/控制器名称)ASP.NET MVC 3

时间:2011-11-23 09:02:34

标签: c# asp.net-mvc

好的,我正在开发一个像网站一样的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())

我发现这种方法更容易维护,因为如果控制器名称更改,我只需要更改一个类。

这适用于任何链接,控制器重定向(返回重定向(...))以及接受由

返回的虚拟路径的任何内容
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?

1 个答案:

答案 0 :(得分:0)

在CMS中,你可能不需要整个基于约定的视图渲染,你(迟早)会想要渲染自定义模板“to string”并通过你的(最可能是动态/可配置的)规则合并结果布局。看看 RazorEngine 项目。

http://razorengine.codeplex.com/