Umbraco CMS MVC - власний контролер і красиві url

CMS Umbraco я вивчаю кілька місяців. Так вийшло, що основний додаток моїх дослідницьких зусиль спрямовано на останню на сей день 7-ю версію цієї системи, причому в контексті її роботи на MVC-движку, як альтернативі веб-формам колишніх версій.
 
У якийсь момент, розробляючи сайт однієї компанії, мені захотілося винести репозиторій новин цієї компанії в окремий елемент верхнього рівня в content tree. У прикладах і відеоінструкції, розміщених на сайті Umbraco, пропонується найпростіший варіант такої організації — новини зберігаються як дочірні елементи якого-небудь пункту меню (рис.1). Як приклад в розділі «З якого боку підійти до Umbraco» такий підхід виправдовується, але на живому сайті, де новин будуть десятки і сотні, це виглядає досить незграбно. Щоб працювати з новинами, редактору сайту потрібно буде опускатися вглиб по дереву контенту — Главная-Новости-ОтдельнаяНовость . Та й сама концепція такого підходу мене не дуже влаштовує — у розділі пунктів багаторівневого меню раптом з'являється список новин…
 
 
 image
 
Більш кращим виглядає інший варіант, як на рис.2 — вузол, що містить новини, є окремим елементом верхнього рівня дерева контенту.
 
 image
 
Більше того — при організації доступу до новин за посиланням, захотілося, щоб вони мали гарний канонічний вигляд:
 
 
     
/ News — список всіх новин;
 / News/1234 — висновок окремої новини;
 / News/Page12 — перехід на сторінку списку новин.
 
Парадигма MVC для вирішення даної задачі передбачає наявність контролера і подання (модель в даному випадку не використовуємо). Оскільки все виконується «під крилом» Umbraco, ми не можемо взяти і впровадити контролер новин, наслідуючи його від класу Controller — нічого не відбудеться. Документація по Umbraco пропонує успадковуватися від спеціально існуючого в інфраструктурі даної CMS класу SurfaceController . Все б добре, але в такому випадку посилання, за якими викликаються дії контролера, набувають вигляду " / umbraco / surface / _controllername_ / _actionname_ ". Така структура url виглядає досить громіздкою, та й з точки зору пошукової індексації сторінка з подібним url сприймається як глибоко захована в структурі сайту, що, ймовірно, знижує її пошукову значимість.
 
Дослідження даного питання призвело до наступного рішення — успадковуватися потрібно не від класу SurfaceController , а від PluginController . У цьому випадку посилання генеруються за канонами MVC, так, як і потрібно. Однак при цьому необхідно враховувати деякі додаткові обставини. Нижче надано повне рішення даної задачі. Отже:
 
 

Роут

Роут прописуються не в файлі App_Start / RouteConfig.cs , який стандартно викликається як RouteConfig.RegisterRoutes (RouteTable.Routes) в Global.asax . У Umbraco MVC для класів PluginController Роут прописуються у файлі App_Code / Startup.cs . У цьому файлі оголошуємо клас, імплементує інтерфейс IApplicationEventHandler . Виглядає це так:
 
 
public class MyStartupHandler : IApplicationEventHandler
{
	public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
	{
		//Create a custom routes

		// News controller
		RouteTable.Routes.MapRoute(
			"",
			"News",
			new
			{
				controller = "News",
				action = "Index",
				page = 1
			});

		RouteTable.Routes.MapRoute(
			"",
			"News/Index",
			new
			{
				controller = "News",
				action = "Index",
				page = 1
			});

		RouteTable.Routes.MapRoute(
			"",
			"News/Page{page}",
			new
			{
				controller = "News",
				action = "Index",
				page = UrlParameter.Optional
			});

		RouteTable.Routes.MapRoute(
			"",
			"News/{id}",
			new
			{
				controller = "News",
				action = "News",
				id = UrlParameter.Optional
			});
	}

	public void OnApplicationInitialized(
		UmbracoApplicationBase umbracoApplication,
		ApplicationContext applicationContext)
	{
	}

	public void OnApplicationStarting(
		UmbracoApplicationBase umbracoApplication,
		ApplicationContext applicationContext)
	{
	}
}

 
 

Контролер

Контролер створюється звичайним чином у файлі, розташованому в папці Controllers . Як було сказано, клас контролера успадковує клас PluginController . Виглядає це приблизно так:
 
 
public class NewsController : PluginController
{
	public NewsController() : this(UmbracoContext.Current) { }

	public NewsController(UmbracoContext umbracoContext) : base(umbracoContext) { }

	public ActionResult Index(string id)
	{
		/*
			Здесь находится код, осуществляющий поиск и получение узлов новостей 
			для той или иной цели - построение постраничного списка, 
			демонстрация отдельной новости и т.д.
		*/
		
		return View("News", CreateRenderModel(renderModel));
	}

	private RenderModel CreateRenderModel(IPublishedContent content)
	{
		var model = new RenderModel(content, CultureInfo.CurrentUICulture);

		//add an umbraco data token so the umbraco view engine executes
		RouteData.DataTokens["umbraco"] = model;

		return model;
	}
}

Тут потрібне одне уточнення. Код пошуку вузлів з новинами повертає об'єкт типу інтерфейсу IPublishedContent або IEnumerable <IPublishedContent> . Однак Umbraco вимагає, щоб уявлення, що викликаються з PluginController 'a, були строго типізовані і приймали модель типу RenderModel . Для цього в контролері оголошується приватний метод CreateRenderModel , який з IPublishedContent створює об'єкт необхідного типу.
 
 

Подання

Подання створюється за стандартною схемою, ніяких нюансів у плані вирішення даної задачі в ньому немає.
 
 

Сторонній ефект

У використанні даного підходу виявився один сторонній ефект, а саме — неможливість використання макросів в контенті на сторінках, що викликаються подібним чином. Виникає помилка з визначенням "PublishedContentRequest missing ". Як я зрозумів, пов'язана вона з тим, що відображається через такий контролер документ не проходить всі стадії розбору Umbraco, в процесі якого і створюється цей самий PublishedContentRequest , від якого відштовхується код генерації макросів. Втішає думка, що робота з макросами при використанні MVC partial views стає менш затребуваною. До того ж самі творці Umbraco кажуть, що код, який реалізує виклик макросів з Rich-text-контенту, досить заплутаний і несе на собі серйозний відбиток важкого доемвсішного минулого…
 
 

Посилання

 Surface Controllers
 Custom MVC routing in Umbraco

Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.