【问题标题】:Proper way to route to controllers in Umbraco ASP.NET / IApplicationEventHander vs ApplicationEventHandler vs RouteConfig.cs, RenderMvcController etc在 Umbraco ASP.NET / IApplicationEventHander vs ApplicationEventHandler vs RouteConfig.cs,RenderMvcController 等中路由到控制器的正确方法
【发布时间】:2017-02-22 16:31:33
【问题描述】:

我有一个这样的解决方案结构:

MyApp.Core
--Properties
--References
--bin
--Events
  |EventHandlers.cs
--Directory
  --Controllers
    |DirectoryController.cs
  --Helpers
    |ContextHelpers.cs
  --Models
    |DirectoryModel.cs
--AnotherSite
  --Controllers
  --Helpers
  --Models
  --Services
--Shared
  --Controllers
    |HomePageController.cs
  --Helpers
    |Extensions.cs
|app.config
|packages.config

MyApp.Umbraco
--Properties
--References
--bin
etc........
--Views
  --Directory
    --Partials
      |DirectoryFilters.cshtml
    |DirectoryBase.cshtml
    |DirectoryHome.cshtml
    |FDirectory.cshtml
    |SDirectory.cshtml
  --Partials
  --Shared
  |Base.cshtml
  |Web.config
etc........

我的 Umbraco 实例使用我的“核心”项目中的模型和控制器。存在嵌套的目录结构,因为一个安装中有多个网站,在“Core”中,以及在 Umbraco 实例的“Views”目录中。

我对 .NET MVC 还是很陌生,而且我了解路由劫持,但 Umbraco 路由的文档很少。我有以下内容:

EventHandlers.cs

namespace MyApp.Core.Events
{
    /// <summary>
    /// Registers site specific Umbraco application event handlers
    /// </summary>
    public class MyAppStartupHandler : IApplicationEventHandler
    {
        public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {

        }

        public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {
            RegisterCustomRoutes();
        }

        public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
        {

        }

        private static void RegisterCustomRoutes()
        {
            // Custom Routes
            RouteTable.Routes.MapUmbracoRoute(
                "FDirectory",
                "fdirectory/{id}",
                new
                {
                    controller = "Directory",
                    action = "FDirectory",
                    id = UrlParameter.Optional
                },
                new PublishedPageRouteHandler(1000));

            RouteTable.Routes.MapUmbracoRoute(
                "SDirectory",
                "sdirectory/{id}",
                new
                {
                    controller = "Directory",
                    action = "SDirectory",
                    id = UrlParameter.Optional
                },
                new PublishedPageRouteHandler(1001));

            RouteTable.Routes.MapUmbracoRoute(
                "HomePage",
                "",
                new
                {
                    controller = "HomePage",
                    action = "Index",
                    id = UrlParameter.Optional
                },
                new PublishedPageRouteHandler(1002));
        }
    }

    public class PublishedPageRouteHandler : UmbracoVirtualNodeRouteHandler
    {
        private readonly int _pageId;

        public PublishedPageRouteHandler(int pageId)
        {
            _pageId = pageId;
        }

        protected override IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext)
        {
            if (umbracoContext != null)
            {
                umbracoContext = ContextHelpers.EnsureUmbracoContext();
            }

            var helper = new UmbracoHelper(UmbracoContext.Current);

            return helper.TypedContent(_pageId);
        }
    }
}

DirectoryController.cs

namespace MyApp.Core.Directory.Controllers
{
    public class DirectoryController : RenderMvcController
    {
        public DirectoryController() : this(UmbracoContext.Current) { }
        public DirectoryController(UmbracoContext umbracoContext) : base(umbracoContext) { }

        public ActionResult FDirectory(RenderModel model)
        {
            return CurrentTemplate(new DirectoryModel(model.Content));
        }

        public ActionResult SDirectory(RenderModel model)
        {
            return CurrentTemplate(new DirectoryModel(model.Content));
        }
    }
}

所以 Umbraco 没有安装 App_Start 文件夹。我想知道多站点安装 Umbraco 以注册到控制器的路由的最佳方法是什么。我的实现有效,但似乎我不应该为我将在站点中的每个页面、每个控制器中创建操作。我知道 Umbraco 有自己的路由,所以使用 Umbraco 概念、ASP.NET MVC 概念以及任何其他可用的方法,实现这种解决方案结构的最佳方法是什么?我是否应该担心使用 RouteConfig.cs 并创建 App_Start 目录?还是我正在做的最好的方法?我应该使用 IApplicationEventHandler 还是 ApplicationEventHandler?

另外,我必须对节点 ID 进行硬编码。我读过有一种动态的方法?这样的例子会很棒。

实施结构化多站点 Umbraco MVC 解决方案的最佳方法示例是我想的,关于路由控制器,提供一些细节或指向强大示例的链接。我进行了搜索和研究,那里有一些零碎的东西,但并不是我正在使用的一个很好的例子。我将不得不为我此时创建的每个页面创建一个 RouteMap,我不知道这是否是最有效的方法。我什至尝试实现一个 DefaultController,但是当您的解决方案将有多个控制器时,我没有看到这一点。

【问题讨论】:

    标签: c# asp.net-mvc model-view-controller umbraco umbraco7


    【解决方案1】:

    我不完全确定你想用这个实现什么,但我会尝试解释它是如何工作的,也许你可以在之后澄清。

    我假设您已经了解了 Umbraco 的基础知识(创建文档类型 + 基于文档类型的文档)。这就是 Umbraco 通常的使用方式,它会自动为您在站点中创建的每个“内容节点”(文档)进行路由。

    因此,创建一个名为 document1 的文档,它将自动在您的站点中路由到 URL:http://localhost/document1。默认情况下,此文档将通过默认 MVC 控制器提供,并且所有这些都将在幕后进行,您无需执行任何操作。

    路由劫持允许您覆盖此默认行为并“插入”一个控制器,让您干扰请求的处理方式。要使用劫持,您可以使用您的文档类型的别名创建一个RenderMvcController。那可能是HomePageController : RenderMvcController

    这个控制器应该有一个带有以下签名的动作:

    public override ActionResult Index(RenderModel model)
    

    在此操作中,您可以以任何您喜欢的方式修改发送到视图的模型。这可能是 - 获取一些外部数据以添加到模型中或触发一些逻辑或您需要做的任何事情。

    这一切都是通过命名约定自动连接起来的,您无需手动注册任何路由即可。

    您可以创建的另一种 Umbraco MVC 控制器是SurfaceController。这个通常用于处理子动作的渲染和表单提交(HttpPost)。 SurfaceController 也由 Umbraco 自动路由,并将位于“不太漂亮”的 URL 上。然而,由于它通常只用于渲染子操作和提交表单,所以它位于哪个 URL 并不重要。

    除了这些自动路由控制器之外,您当然还可以像在任何标准 MVC 网站中一样注册自己的 MVC 控制器。一个不同之处在于,与普通的 ASP.NET MVC 网站不同,Umbraco 网站没有控制器的自动默认注册,允许在创建新控制器时路由“正常工作”。

    因此,如果您想在 Umbraco 站点中渲染一个普通的旧 MVC 控制器,但它不与 Umbraco 中的文档/节点相关,您必须像在任何其他 MVC 站点中一样为它注册一个路由。最好的方法是使用ApplicationEventHandler 类挂钩并将其添加到路由中。这将在应用程序启动期间自动触发 - 本质上允许您执行您通常在 App_Start 中执行的操作。

    但要明确一点 - 如果您打算使用来自 Umbraco 的数据,则不应使用普通的 MVC 控制器,并且不应要求进行任何手动路由注册。您通常希望在 Umbraco 中创建的文档/节点的上下文中呈现模板/视图(您可以在其中修改文档的数据/属性),然后路由劫持是要走的路。


    从它的外观看来,正确的做法似乎是创建两种文档类型:

    FDirectorySDirectory

    单击以允许在 root 中创建这两个文件,然后创建名为 FDirectorySDirectory 的文档,它们将自动路由到这些 URL。创建一个名为 FDirectoryController : RenderMvcControllerRenderMvcController 将确保在请求该页面时使用它来劫持路由。

    如果您只是想建立一个多站点解决方案,我建议您创建一个Website 文档类型,并在您的 Umbraco 内容树的根目录中为您想要的每个站点创建一个节点。右键单击每个节点并将主机名编辑为您需要的任何内容。这也可以是一些“子 url”,例如 /fdirectory/sdirectory,以防您需要在不使用多个主机名的情况下在 localhost 上进行测试。

    希望这能给您提供所需的指示,否则请尝试解释您正在尝试做什么,我会看看我是否可以改进我的答案!

    【讨论】:

    • ~ 我最关心的是让我的代码像我的问题中的目录示例一样井井有条。有些视图会有自定义控制器,有些则没有。我希望我的所有模型、控制器、助手、服务等都位于这些特定站点下的文件夹中。据我所知,Umbraco 没有找到那些没有路由劫持的模型、助手等。我已经创建了一个网站文档类型。但是如果我将视图放在目录中,Umbraco 就找不到它们。如果我想按站点将视图、控制器、模型放在目录结构中,我该怎么做?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-12
    • 2011-06-05
    • 2013-01-28
    • 2016-11-16
    • 2017-06-10
    • 1970-01-01
    相关资源
    最近更新 更多