【问题标题】:Render Controller Action To String (Using Virtual Path, No action/controller name) ASP.NET MVC 3将控制器动作渲染为字符串(使用虚拟路径,无动作/控制器名称)ASP.NET MVC 3
【发布时间】: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


【解决方案1】:

在 CMS 中,您可能不需要整个基于约定的视图渲染,您将(迟早)希望将自定义模板渲染为“字符串”并通过您的(很可能是动态/可配置的)规则合并结果布局。看看 RazorEngine 项目。

http://razorengine.codeplex.com/

【讨论】:

  • 是的,我完全同意你的看法。但这是我的第一个 CMS,坦率地说,我没有太多编写此类内容的经验。我也不是 ASP.NET MVC 专家。不过感谢您的提示,我会看看它,如果它适合我​​的需要,我会很乐意使用它。
  • 好的,我想我开始理解这个概念了。基本上,如果您有一些预定义区域的页面,您可以使用某种引擎用任意内容“填充”这些区域?现在我使用自定义标签,如 和 HTML Agility Pack 来解析 HTML、获取 id、从数据库中获取内容并替换我的伪标签。我认为以后可能是性能问题,我什至想将结果存储在一些 NoSQL DB 中以获得更好的性能。但它仍在空中。
  • 我能给你的最佳建议:不要在你刚接触的技术上编写你自己的 CMS。至少花一些时间研究一些现有的 asp.net mvc CMS 系统,并“借用”你喜欢的东西.. 不要从头开始编写,即使对于有经验的程序员来说,以正确的方式设计它也是非常重要的工作
  • 我研究过 Orchard 和 NOP Commerce :) Orchard 并非易事,而 NOP Commerce 的消息来源将我推向了正确的方向。老实说,现在说不已经太晚了,我喜欢建造东西,所以为什么不通过反复试验来尝试。反正我会得到经验的。
猜你喜欢
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 2010-11-17
  • 2014-11-18
  • 1970-01-01
  • 2013-08-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多