【问题标题】:Sitecore, custom MVC controllers and routesSitecore,自定义 MVC 控制器和路由
【发布时间】:2015-10-12 03:08:26
【问题描述】:

我在 Sitecore 的网站定义中定义了一个网站。它的路径是/localhost/mysite/home。它有效。

我需要创建一个自定义控制器来提交带有绕过 Sitecore 的 API 的表单。所以我有 FormsController(从 MVC 控制器继承),其中一个名为“Test”的操作不带任何参数。

我在初始化管道中定义了这样的路由:

public class Initialize
{
    public void Process(PipelineArgs args)
    {
        MapRoutes();
        GlassMapperSc.Start();
    }

    private void MapRoutes()
    {
        RouteTable.Routes.MapRoute(
                "Forms.Test", 
                "forms/test", 
                new
                {
                    controller = "FormsController",
                    action = "Test"
                },
                new[] { "Forms.Controller.Namespace" });
     }
}

路由已正确添加到路由表中,当我调试它时它就在那里。 现在,当我尝试调用方法“test”时,找不到路由,调试器也没有命中操作中的断点。

我正在尝试不同的路线:

  • /localhost/mysite/home/forms/test
  • /localhost/forms/test(默认网站)

但到目前为止还没有运气。

---- 更新 ---

深入研究后,我注意到 Sitecore 的行为有问题。 TransferRoutedRequest 处理器应该中止 httpRequestBegin 管道,将控制权交还给 MVC,以防上下文项为空(简化)。它发生在一些检查之后,其中之一是对 RoutTable 数据的检查。但是对RouteTable.Routes.GetRouteData 的调用总是返回null,这使得处理器在不中止管道的情况下返回。我重写了它以使其正确中止管道,但是即使我调用方法args.AbortPipeline(),管道也没有中止并且路由没有解析。

这就是原来的TransferRoutedRequest 的样子:

public class TransferRoutedRequest : HttpRequestProcessor
{
  public override void Process(HttpRequestArgs args)
  {
    Assert.ArgumentNotNull((object) args, "args");
    RouteData routeData = RouteTable.Routes.GetRouteData((HttpContextBase) new HttpContextWrapper(HttpContext.Current));
    if (routeData == null)
      return;
    RouteValueDictionary routeValueDictionary = ObjectExtensions.ValueOrDefault<Route, RouteValueDictionary>(routeData.Route as Route, (Func<Route, RouteValueDictionary>) (r => r.Defaults));
    if (routeValueDictionary != null && routeValueDictionary.ContainsKey("scIsFallThrough"))
      return;
    args.AbortPipeline();
   }
}

这就是我覆盖它的方式:

public class TransferRoutedRequest : global::Sitecore.Mvc.Pipelines.HttpRequest.TransferRoutedRequest
{
    public override void Process(HttpRequestArgs args)
    {
        if (Context.Item == null || Context.Item.Visualization.Layout == null)
            args.AbortPipeline();
        else
            base.Process(args);
    }
}

【问题讨论】:

    标签: c# routing asp.net-mvc-5 sitecore sitecore7


    【解决方案1】:

    这是我的一个项目中的一个工作示例。

    自定义路由注册:

    namespace Test.Project.Pipelines.Initialize
    {
        public class InitRoutes : Sitecore.Mvc.Pipelines.Loader.InitializeRoutes
        {
            public override void Process(PipelineArgs args)
            {
                RegisterRoutes(RouteTable.Routes);
            }
    
            protected virtual void RegisterRoutes(RouteCollection routes)
            {
                routes.MapRoute(
                    "Test", // Route name
                    "api/test/{controller}/{action}/{id}", // URL with parameters
                     new { id = UrlParameter.Optional }
                    );
            }
        }
    }
    

    初始化管道配置:

    <?xml version="1.0" encoding="utf-8"?>
    <configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
      <sitecore>
         <pipelines>
             <initialize>
                <processor type="Test.Project.Pipelines.Initialize.InitRoutes, Test.Project"
             patch:after="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeRoutes, Sitecore.Mvc']" />
            </initialize>
         </pipelines>
      </sitecore>
    </configuration>
    

    【讨论】:

      【解决方案2】:

      这是为您创建路线的代码。在 global.asax.cs 中,您将从 App_Start 事件处理程序中调用 RegisterRoutes:

          protected void Application_Start()
          {
              RouteConfig.RegisterRoutes(RouteTable.Routes);
          }
      

      然后您将路线指定为:

          public static void RegisterRoutes(RouteCollection routes)
          {
              routes.MapRoute(
                   name: "test",
                   url: "mvc/Forms/{action}/{id}",
                   defaults: new { controller = "Forms", action = "Test", id = UrlParameter.Optional }
                 );
          }
      

      在这种情况下,您将拥有 /mvc/ 前缀,它将处理您指定控制器的路由,因此您将其称为:

      /mvc/Forms/Test/{you_may_pass_some_optional_GUID_here}
      

      这将路由到 FormsController 类操作方法 Test(string id) 但您可以省略 id 参数

      【讨论】:

      • 您正在复制我的(不工作的)示例,并添加了 错误做法:修改 Application_Start 方法。我无法访问全局 asax,即使有,我也不会碰它。正确的做法是通过初始化管道,将配置添加到 App_Config/include 文件夹。或者,作为第二种选择,通过使用 assembly: PreApplicationStartMethod 装饰您自己的 init 类
      • 我当然意识到最好避免修改 global.asax.cs 至少为了维护目的 - sirchicken.blogspot.co.uk/2014/07/… - 我只是为了理解而简化了它。 sn-p 的示例是一个 working 代码,因为我已经提前测试过
      • 你读过我写的吗?这是你写的同一个例子,但它对我不起作用。所以重点是:我知道通常的技术是如何工作的,但在我的情况下它不起作用。那么用通常的方法回答有什么意义呢?此外:您是否在 sitecore 中创建了新的网站配置?如果是,您是否在新创建的网站中测试了您的方法?我不这么认为......
      • 亲爱的 Hellraiser,@MartinMiles 试图帮助你,但你并不友善。如果我是你,我不会指望其他人会尝试提供帮助
      • 亲爱的马雷克和马丁。我很抱歉。我不是故意粗鲁的。但是只有当我遇到真正的问题时,我才会在这里发布消息。正如我已经指定的那样,我完全知道这应该如何工作。但是,由于某种未知的原因,它没有。此外,StackOverflow 的目标应该不仅仅是解决问题,而是教人们如何以正确的方式去做。我注意到马丁写了一个错误的练习,我让他知道了。有时在这里很难理解某人的意图和心情。所以如果我冒犯了某人,我道歉。这不是我的本意。
      【解决方案3】:

      我终于让它正常工作了。正如我所写的,TransferRoutedRequest 没有按预期工作,所以我不得不重写它。尽管如此,即使它按预期工作,路线也没有得到解决。问题出在管道配置中。感谢一位同事,我打开了 SitecoreRocks 管道工具,它显示管道注册的位置离它应该在的位置太远,所以它从来没有被击中(我在ItemResolver 之后注册了它,因为它是在原来的配置)。我在LayoutResolver 之前对其进行了修补,就成功了。路线已解决。 尽管如此,Sitecore 还是无法创建该类型的实例,因为它在另一个程序集中。即使指定控制器的命名空间也不能解决问题。所以我不得不做一些修改并覆盖 ControllerFactory 类的 CreateController 方法并覆盖 InitializeControllerFactory 处理器(我已经修改了它以便能够使用 DI 容器),编写一个新的ControllerFactory 和一个新的SitecoreControllerFactory。

      最终代码如下所示:

      public override IController CreateController(RequestContext requestContext, string controllerName)
          {
              var controller = SC.Context.Item == null || SC.Context.Item.Visualization.Layout == null
                              ? base.GetControllerType(requestContext, controllerName)
                              : TypeHelper.GetType(controllerName);
      
              return GetControllerInstance(requestContext, controller);
          }
      

      如果我正在处理 Sitecore 项目,我使用 TypeHelper 从控制器渲染或布局返回当前控制器类型。否则我使用DefaultControllerFactory.GetControllerType 来解析自定义路由。

      唯一需要注意的是:如果 2 个或多个命名空间具有相同名称和操作的控制器,则必须添加命名空间以识别它们。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-02-20
        • 2014-03-07
        • 2016-04-05
        • 2013-09-30
        • 2018-09-14
        • 2011-11-24
        • 1970-01-01
        相关资源
        最近更新 更多