2015-07-22 3 views
2

У меня есть сайт, определенный в определениях сайта Sitecore. Путь к нему: /localhost/mysite/home. И это работает.Sitecore, пользовательские контроллеры и маршруты MVC

Мне нужно создать пользовательский контроллер для отправки форм с API в обход Sitecore. Таким образом, у меня есть FormsController (наследующий от контроллера MVC) действие с именем «Тест» без параметров.

Я определил маршрут в инициализации трубопровода, как это:

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" }); 
    } 
} 

маршрут добавляется в таблицу маршрутизации правильно, и это там, когда я его отладки. Теперь, когда я пытаюсь вызвать метод «тест», маршрут не найден, и отладчик не попадает в точку останова в действии.

Я пытаюсь разные маршруты:

  • /localhost/mysite/home/forms/test
  • /localhost/forms/test (веб-сайт по умолчанию)

Но не везло до сих пор.

---- UPDATE ---

Углубляясь в него, я заметил, что там что-то не так с поведением 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); 
    } 
} 

ответ

0

Наконец я получил это работает правильно. Как я писал, TransferRoutedRequest не работал должным образом, поэтому мне пришлось переопределить его. Тем не менее, даже если это сработало, как предполагалось, маршрут не был разрешен. Проблема заключалась в конфигурации трубопровода. Благодаря коллеге я открыла инструмент для конвейера SitecoreRocks, и он показал, что трубопровод был зарегистрирован в позиции слишком далеко от того места, где он должен был быть, поэтому он никогда не попадал (я зарегистрировал его после ItemResolver, как это было в исходной конфигурации) , Я заплатил его до LayoutResolver, и это сделало трюк. Маршрут был разрешен. Тем не менее, Sitecore не смог создать экземпляр типа, как это было в другой сборке. Даже указание пространства имен контроллера не решило проблему. Поэтому мне пришлось внести некоторые изменения и переопределить метод CreateController класса ControllerFactory и переопределить процессор 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 или более пространств имен есть контроллер с тем же именем и действием, необходимо обязательно добавить пространство имен, чтобы идентифицировать их.

0

Вот код, который будет создать маршрут для Вас. В Global.asax.cs вы назовете RegisterRoutes из App_Start обработчика событий:

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 (строка идентификатора), но вы можете не указывать параметр ID

+0

Вы копируете мой (нерабочий) пример с добавлением ** НЕПРАВИЛЬНОЙ практики **: для изменения метода «Application_Start». У меня нет доступа к глобальному асаку, и даже если бы у меня было, я бы не стал его трогать. Правильный способ сделать это через инициализацию конвейера, добавив конфигурацию в папку App_Config/include. Или, в качестве второго варианта, путем украшения вашего собственного класса init с помощью 'assembly: PreApplicationStartMethod' – Hellraiser

+0

Конечно, я понимаю, что лучше избегать модификаций global.asax.cs, по крайней мере для целей обслуживания - http: //sirchicken.blogspot .co.uk/2014/07/leave-globalasax-in-sitecore-untouched.html - Я просто упростил его для понимания. Пример фрагмента - это ** рабочий ** код, поскольку я его заранее проверил –

+0

Вы читали то, что я написал? Это тот же пример, который вы написали, но это не работает для меня. Итак, дело в том, что я знаю, как работает обычная программа, но в моем случае это не работает. Итак, в чем смысл отвечать обычным методом? Кроме того: вы создали новую конфигурацию сайта в sitecore? Если да, проверили ли вы свой метод на новом созданном веб-сайте? Я так не думаю ... – Hellraiser

3

Вот рабочий пример, взятый из одного из моих проектов.

Пользовательские маршрут Регистрация:

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 } 
       ); 
     } 
    } 
} 

Initialize Pipeline Config:

<?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> 
+0

Ссылка: https://kb.sitecore.net/articles/700677 –

Смежные вопросы