();
28 | mDynamicRouteHelper = new BaseDynamicRouteHelper();
29 | }
30 |
31 | public bool IsReusable
32 | {
33 | get
34 | {
35 | return false;
36 | }
37 | }
38 |
39 | ///
40 | /// Gets the page, and based on the Class of the Page, attempts to get the Dynamic routing information and processes.
41 | ///
42 | ///
43 | public void ProcessRequest(HttpContext context)
44 | {
45 | var node = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: false);
46 |
47 | var routePair = ResolveRouteValues(node);
48 |
49 | RequestRoutingEventArgs RequestArgs = new RequestRoutingEventArgs()
50 | {
51 | Page = node,
52 | Configuration = routePair,
53 | CurrentRequestContext = RequestContext
54 | };
55 |
56 | // Use event to allow users to overwrite the Dynamic Routing Data
57 | using (var RequestRoutingHandler = DynamicRoutingEvents.RequestRouting.StartEvent(RequestArgs))
58 | {
59 | // Check if the OutputCache was disabled or enabled during the event args
60 | if (routePair.ControllerName.Equals("DynamicRouteCached", StringComparison.InvariantCultureIgnoreCase) && !routePair.UseOutputCaching)
61 | {
62 | routePair.ControllerName = "DynamicRoute";
63 | }
64 | else if (routePair.ControllerName.Equals("DynamicRoute", StringComparison.InvariantCultureIgnoreCase) && routePair.UseOutputCaching)
65 | {
66 | routePair.ControllerName = "DynamicRouteCached";
67 | }
68 |
69 | // Handle passing the Include In Output Cache
70 | switch (routePair.ControllerName.ToLower())
71 | {
72 | case "dynamicroute":
73 | case "dynamicroutecached":
74 | case "dynamicroutetemplate":
75 | RequestArgs.CurrentRequestContext.RouteData.Values["IncludeDocumentInOutputCache"] = routePair.IncludeDocumentInOutputCache;
76 | break;
77 | }
78 |
79 | // Setup routing with new values
80 | RequestArgs.CurrentRequestContext.RouteData.Values["Controller"] = routePair.ControllerName;
81 | RequestArgs.CurrentRequestContext.RouteData.Values["Action"] = routePair.ActionName;
82 |
83 | foreach (string Key in routePair.RouteValues.Keys)
84 | {
85 | RequestArgs.CurrentRequestContext.RouteData.Values[Key] = routePair.RouteValues[Key];
86 | }
87 |
88 | // Allow users to adjust the RequestContext further
89 | RequestRoutingHandler.FinishEvent();
90 |
91 | // Pass back context
92 | RequestContext = RequestArgs.CurrentRequestContext;
93 | }
94 |
95 | IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
96 | IController controller = factory.CreateController(RequestContext, routePair.ControllerName);
97 | controller.Execute(RequestContext);
98 |
99 | factory.ReleaseController(controller);
100 | }
101 |
102 | ///
103 | /// Determines where the Controller and Action should be based on the dynamic routing data
104 | ///
105 | ///
106 | ///
107 | private DynamicRouteConfiguration ResolveRouteValues(ITreeNode node)
108 | {
109 | string defaultController = RequestContext.RouteData.Values.ContainsKey("controller")
110 | ? RequestContext.RouteData.Values["controller"].ToString()
111 | : "";
112 |
113 | string defaultAction = RequestContext.RouteData.Values.ContainsKey("action")
114 | ? RequestContext.RouteData.Values["action"].ToString()
115 | : "";
116 |
117 | if (string.IsNullOrWhiteSpace(defaultController))
118 | {
119 | defaultController = "DynamicRoute";
120 | }
121 | if (string.IsNullOrWhiteSpace(defaultAction))
122 | {
123 | defaultAction = "RouteValuesNotFound";
124 | }
125 |
126 | if (node is null)
127 | {
128 | return new DynamicRouteConfiguration(defaultController, defaultAction, null, null, DynamicRouteType.Controller, false, false);
129 | }
130 |
131 | if (PageHasTemplate(node))
132 | {
133 | var PageTemplateRouteConfig = new DynamicRouteConfiguration("DynamicRouteTemplate", "Index", null, null, DynamicRouteType.Controller, DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency(), false);
134 | string PageTemplateControllerName = GetPageTemplateController(node);
135 |
136 | // When the Dynamic Route Template Controller renders the Page Template, the Route Controller needs to match or it won't look in the right spot for the view
137 | if (!string.IsNullOrWhiteSpace(PageTemplateControllerName))
138 | {
139 | PageTemplateRouteConfig.RouteValues.Add("TemplateControllerName", PageTemplateControllerName);
140 | }
141 | return PageTemplateRouteConfig;
142 | }
143 |
144 | if (!DynamicRoutingAnalyzer.TryFindMatch(node.ClassName, out var match))
145 | {
146 | return new DynamicRouteConfiguration(defaultController, defaultAction, null, null, DynamicRouteType.Controller, false, false);
147 | }
148 |
149 | return match;
150 | }
151 |
152 | ///
153 | /// Checks if the current page is using a template or not.
154 | ///
155 | /// The Tree Node
156 | /// If it has a template or not
157 | private bool PageHasTemplate(ITreeNode Page)
158 | {
159 | string TemplateConfiguration = GetTemplateConfiguration(Page);
160 | return !string.IsNullOrWhiteSpace(TemplateConfiguration) && !TemplateConfiguration.ToLower().Contains("\"empty.template\"");
161 | }
162 |
163 | private string GetPageTemplateController(ITreeNode Page)
164 | {
165 | string TemplateConfiguration = GetTemplateConfiguration(Page);
166 | if (!string.IsNullOrWhiteSpace(TemplateConfiguration) && !TemplateConfiguration.ToLower().Contains("\"empty.template\""))
167 | {
168 | var json = JObject.Parse(TemplateConfiguration);
169 | var templateIdentifier = ValidationHelper.GetString(json["identifier"], "");
170 |
171 | // Return the controller name, if it has any
172 | return _pageTemplateDefinitionProvider.GetAll()
173 | .FirstOrDefault(def => def.Identifier.Equals(templateIdentifier, StringComparison.InvariantCultureIgnoreCase))
174 | ?.ControllerName;
175 | }
176 | else
177 | {
178 | // No template
179 | return null;
180 | }
181 | }
182 |
183 | private string GetTemplateConfiguration(ITreeNode Page)
184 | {
185 | string TemplateConfiguration = ValidationHelper.GetString(Page.GetValue("DocumentPageTemplateConfiguration"), "");
186 |
187 | // Check Temp Page builder widgets to detect a switch in template
188 | var InstanceGuid = ValidationHelper.GetGuid(URLHelper.GetQueryValue(HttpContext.Current.Request.Url.AbsoluteUri, "instance"), Guid.Empty);
189 | if (InstanceGuid != Guid.Empty)
190 | {
191 | var Table = ConnectionHelper.ExecuteQuery(String.Format("select PageBuilderTemplateConfiguration from Temp_PageBuilderWidgets where PageBuilderWidgetsGuid = '{0}'", InstanceGuid.ToString()), null, QueryTypeEnum.SQLQuery).Tables[0];
192 | if (Table.Rows.Count > 0)
193 | {
194 | TemplateConfiguration = ValidationHelper.GetString(Table.Rows[0]["PageBuilderTemplateConfiguration"], "");
195 | }
196 | }
197 | return TemplateConfiguration;
198 | }
199 | }
200 | }
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouteCachedController.cs:
--------------------------------------------------------------------------------
1 | using CMS.DataEngine;
2 | using CMS.Helpers;
3 | using CMS.SiteProvider;
4 | using DynamicRouting.Implementations;
5 | using DynamicRouting.Interfaces;
6 | using Kentico.PageBuilder.Web.Mvc;
7 | using Kentico.Web.Mvc;
8 | using System;
9 | using System.Web.Mvc;
10 |
11 | namespace DynamicRouting.Kentico.MVC
12 | {
13 |
14 | public class DynamicRouteCachedController : Controller
15 | {
16 | private IDynamicRouteHelper mDynamicRouteHelper;
17 | public DynamicRouteCachedController()
18 | {
19 | mDynamicRouteHelper = new BaseDynamicRouteHelper();
20 | }
21 |
22 | ///
23 | /// Renders the Dynamic Route View (no model)
24 | ///
25 | ///
26 | [OutputCache(CacheProfile = "DynamicRouteController")]
27 | public ActionResult RenderView(bool? IncludeDocumentInOutputCache = null)
28 | {
29 | if (!IncludeDocumentInOutputCache.HasValue)
30 | {
31 | IncludeDocumentInOutputCache = DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency();
32 | }
33 | // Get default Add Page to Output Dependency
34 | var node = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: IncludeDocumentInOutputCache.Value);
35 | var routeConfig = mDynamicRouteHelper.GetRouteConfiguration(node);
36 | HttpContext.Kentico().PageBuilder().Initialize(node.DocumentID);
37 |
38 | return View(routeConfig.ViewName);
39 | }
40 |
41 | ///
42 | /// Renders the View with either an ITreeNode model or the given Model Type
43 | ///
44 | ///
45 | [OutputCache(CacheProfile = "DynamicRouteController")]
46 | public ActionResult RenderViewWithModel(bool? IncludeDocumentInOutputCache = null)
47 | {
48 | if (!IncludeDocumentInOutputCache.HasValue)
49 | {
50 | IncludeDocumentInOutputCache = DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency();
51 | }
52 | var node = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: IncludeDocumentInOutputCache.Value);
53 | var routeConfig = mDynamicRouteHelper.GetRouteConfiguration(node);
54 | HttpContext.Kentico().PageBuilder().Initialize(node.DocumentID);
55 |
56 | // Convert type
57 | if (routeConfig.ModelType != null)
58 | {
59 | try {
60 | return View(routeConfig.ViewName, Convert.ChangeType(node, routeConfig.ModelType));
61 | } catch(InvalidCastException ex)
62 | {
63 | throw new InvalidCastException(ex.Message + ", this may be caused by the generated PageType class not being found in the project, or if it's located in an assembly that does not have [assembly: AssemblyDiscoverable] in it's AssemblyInfo.cs. The found page is of type "+(node == null ? "Null" : node.GetType().FullName), ex);
64 | }
65 | }
66 | else
67 | {
68 | return View(routeConfig.ViewName, node);
69 | }
70 | }
71 |
72 |
73 | ///
74 | /// Returns an error message when the page is found but no DynamicRouting assembly tags were configured.
75 | ///
76 | ///
77 | public ActionResult RouteValuesNotFound()
78 | {
79 | var node = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency());
80 | return Content($"No Route Value Found
No DynamicRouting assembly tag was found for the class {node.ClassName}, could not route page {node.NodeAliasPath}
");
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouteConstraint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Web;
3 | using System.Web.Routing;
4 | using CMS.Helpers;
5 | using DynamicRouting.Implementations;
6 | using DynamicRouting.Interfaces;
7 |
8 | namespace DynamicRouting.Kentico.MVC
9 | {
10 | public class DynamicRouteConstraint : IRouteConstraint
11 | {
12 |
13 | private IDynamicRouteHelper mDynamicRouteHelper;
14 | public DynamicRouteConstraint()
15 | {
16 | mDynamicRouteHelper = new BaseDynamicRouteHelper();
17 | }
18 |
19 | ///
20 | /// Returns true if a Page is found using the Dynamic Routing
21 | ///
22 | ///
23 | ///
24 | ///
25 | ///
26 | ///
27 | ///
28 | public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
29 | {
30 | // Never match on URL generation, this is called with the Url.Action and HtmlLink and shouldn't ever be used.
31 | if(routeDirection == RouteDirection.UrlGeneration)
32 | {
33 | return false;
34 | }
35 |
36 | string controllerName = values.ContainsKey("controller")
37 | ? ValidationHelper.GetString(values["controller"], "")
38 | : "";
39 |
40 | if (controllerName.Equals("KenticoFormWidget", StringComparison.InvariantCultureIgnoreCase))
41 | {
42 | return false;
43 | }
44 |
45 | var page = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: false);
46 | return page != null && !DynamicRouteInternalHelper.UrlSlugExcludedClassNames().Contains(page.ClassName.ToLower());
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouteController.cs:
--------------------------------------------------------------------------------
1 | using CMS.DataEngine;
2 | using CMS.Helpers;
3 | using CMS.SiteProvider;
4 | using DynamicRouting.Implementations;
5 | using DynamicRouting.Interfaces;
6 | using Kentico.PageBuilder.Web.Mvc;
7 | using Kentico.Web.Mvc;
8 | using System;
9 | using System.Web.Mvc;
10 |
11 | namespace DynamicRouting.Kentico.MVC
12 | {
13 | public class DynamicRouteController : Controller
14 | {
15 |
16 | private IDynamicRouteHelper mDynamicRouteHelper;
17 |
18 | public DynamicRouteController()
19 | {
20 | mDynamicRouteHelper = new BaseDynamicRouteHelper();
21 | }
22 |
23 | ///
24 | /// Renders the Dynamic Route View (no model)
25 | ///
26 | ///
27 | public ActionResult RenderView(bool? IncludeDocumentInOutputCache = null)
28 | {
29 | if (!IncludeDocumentInOutputCache.HasValue)
30 | {
31 | IncludeDocumentInOutputCache = DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency();
32 | }
33 | // Get default Add Page to Output Dependency
34 | var node = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: IncludeDocumentInOutputCache.Value);
35 | var routeConfig = mDynamicRouteHelper.GetRouteConfiguration(node);
36 | HttpContext.Kentico().PageBuilder().Initialize(node.DocumentID);
37 |
38 | return View(routeConfig.ViewName);
39 | }
40 |
41 | ///
42 | /// Renders the View with either an ITreeNode model or the given Model Type
43 | ///
44 | ///
45 | public ActionResult RenderViewWithModel(bool? IncludeDocumentInOutputCache = null)
46 | {
47 | if (!IncludeDocumentInOutputCache.HasValue)
48 | {
49 | IncludeDocumentInOutputCache = DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency();
50 | }
51 | var node = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: IncludeDocumentInOutputCache.Value);
52 | var routeConfig = mDynamicRouteHelper.GetRouteConfiguration(node);
53 | HttpContext.Kentico().PageBuilder().Initialize(node.DocumentID);
54 |
55 | // Convert type
56 | if (routeConfig.ModelType != null)
57 | {
58 | try {
59 | return View(routeConfig.ViewName, Convert.ChangeType(node, routeConfig.ModelType));
60 | } catch(InvalidCastException ex)
61 | {
62 | throw new InvalidCastException(ex.Message + ", this may be caused by the generated PageType class not being found in the project, or if it's located in an assembly that does not have [assembly: AssemblyDiscoverable] in it's AssemblyInfo.cs. The found page is of type "+(node == null ? "Null" : node.GetType().FullName), ex);
63 | }
64 | }
65 | else
66 | {
67 | return View(routeConfig.ViewName, node);
68 | }
69 | }
70 |
71 |
72 | ///
73 | /// Returns an error message when the page is found but no DynamicRouting assembly tags were configured.
74 | ///
75 | ///
76 | public ActionResult RouteValuesNotFound()
77 | {
78 | var node = mDynamicRouteHelper.GetPage(AddPageToCacheDependency: DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency());
79 | return Content($"No Route Value Found
No DynamicRouting assembly tag was found for the class {node.ClassName}, could not route page {node.NodeAliasPath}
");
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouteHandler.cs:
--------------------------------------------------------------------------------
1 | using System.Web;
2 | using System.Web.Routing;
3 |
4 | namespace DynamicRouting.Kentico.MVC
5 | {
6 | public class DynamicRouteHandler : IRouteHandler
7 | {
8 | public IHttpHandler GetHttpHandler(RequestContext requestContext)
9 | {
10 | return new DynamicHttpHandler(requestContext);
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouteHelper.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using DynamicRouting.Implementations;
3 | using DynamicRouting.Kentico.MVC;
4 | using System;
5 | using System.Collections.Generic;
6 |
7 | namespace DynamicRouting
8 | {
9 | [Obsolete("It is recommended you use the IDynamicRouteHelper interface on your constructor instead. You may need to add to your AutoFac ContainerBuilder 'builder.RegisterType(typeof(BaseDynamicRouteHelper)).As(typeof(IDynamicRouteHelper));'")]
10 | public class DynamicRouteHelper
11 | {
12 | public DynamicRouteHelper()
13 | {
14 | }
15 |
16 | ///
17 | /// Gets the CMS Page using Dynamic Routing, returning the culture variation that either matches the given culture or the Slug's culture, or the default site culture if not found.
18 | ///
19 | /// The Url (part after the domain), if empty will use the Current Request
20 | /// The Culture, not needed if the Url contains the culture that the UrlSlug has as part of it's generation.
21 | /// The Site Name, defaults to current site.
22 | /// List of columns you wish to include in the data returned.
23 | /// If true, the found page will have it's DocumentID added to the request's Output Cache Dependency
24 | /// The Page that matches the Url Slug, for the given or matching culture (or default culture if one isn't found).
25 | public static ITreeNode GetPage(string Url = "", string Culture = "", string SiteName = "", IEnumerable Columns = null, bool AddPageToCacheDependency = true)
26 | {
27 | return new BaseDynamicRouteHelper().GetPage(Url, Culture, SiteName, Columns, AddPageToCacheDependency);
28 | }
29 |
30 | ///
31 | /// Gets the CMS Page using Dynamic Routing, returning the culture variation that either matches the given culture or the Slug's culture, or the default site culture if not found.
32 | ///
33 | /// The Url (part after the domain), if empty will use the Current Request
34 | /// The Culture, not needed if the Url contains the culture that the UrlSlug has as part of it's generation.
35 | /// The Site Name, defaults to current site.
36 | /// List of columns you wish to include in the data returned.
37 | /// If true, the found page will have it's DocumentID added to the request's Output Cache Dependency
38 | /// The Page that matches the Url Slug, for the given or matching culture (or default culture if one isn't found).
39 | public static T GetPage(string Url = "", string Culture = "", string SiteName = "", IEnumerable Columns = null, bool AddPageToCacheDependency = true) where T : ITreeNode
40 | {
41 | return new BaseDynamicRouteHelper().GetPage(Url, Culture, SiteName, Columns, AddPageToCacheDependency);
42 | }
43 |
44 | ///
45 | /// Gets the Page's Url Slug based on the given DocumentID and it's Culture.
46 | ///
47 | /// The Document ID
48 | ///
49 | public static string GetPageUrl(int DocumentID)
50 | {
51 | return new BaseDynamicRouteHelper().GetPageUrl(DocumentID);
52 | }
53 |
54 | ///
55 | /// Gets the Page's Url Slug based on the given DocumentGuid and it's Culture.
56 | ///
57 | /// The Document Guid
58 | /// The UrlSlug (with ~ prepended) or Null if page not found.
59 | public static string GetPageUrl(Guid DocumentGuid)
60 | {
61 | return new BaseDynamicRouteHelper().GetPageUrl(DocumentGuid);
62 | }
63 |
64 | ///
65 | /// Gets the Page's Url Slug based on the given NodeAliasPath, Culture and SiteName. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
66 | ///
67 | /// The Node alias path you wish to select
68 | /// The Document Culture, if not provided will use default Site's Culture.
69 | /// The Site Name, if not provided then the Current Site's name is used.
70 | /// The UrlSlug (with ~ prepended) or Null if page not found.
71 | public static string GetPageUrl(string NodeAliasPath, string DocumentCulture = null, string SiteName = null)
72 | {
73 | return new BaseDynamicRouteHelper().GetPageUrl(NodeAliasPath, DocumentCulture, SiteName);
74 | }
75 |
76 | ///
77 | /// Gets the Page's Url Slug based on the given NodeGuid and Culture. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
78 | ///
79 | /// The Node to find the Url Slug
80 | /// The Document Culture, if not provided will use default Site's Culture.
81 | /// The UrlSlug (with ~ prepended) or Null if page not found.
82 | public static string GetPageUrl(Guid NodeGuid, string DocumentCulture = null)
83 | {
84 | return new BaseDynamicRouteHelper().GetPageUrl(NodeGuid, DocumentCulture);
85 | }
86 |
87 | ///
88 | /// Gets the Page's Url Slug based on the given NodeID and Culture. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
89 | ///
90 | /// The NodeID
91 | /// The Document Culture, if not provided will use default Site's Culture.
92 | /// The Site Name, if not provided then will query the NodeID to find it's site.
93 | /// The UrlSlug (with ~ prepended) or Null if page not found.
94 | public static string GetPageUrl(int NodeID, string DocumentCulture = null, string SiteName = null)
95 | {
96 | return new BaseDynamicRouteHelper().GetPageUrl(NodeID, DocumentCulture, SiteName);
97 | }
98 |
99 | ///
100 | /// Gets the Route Configuration based on The node's Class Name.
101 | ///
102 | /// The ITreeNode object
103 | /// The Route Configuration, empty DynamicRouteconfiguration if not found
104 | public static DynamicRouteConfiguration GetRouteConfiguration(ITreeNode node)
105 | {
106 | return new BaseDynamicRouteHelper().GetRouteConfiguration(node);
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouteInitializationModule_MVC.cs:
--------------------------------------------------------------------------------
1 | using CMS;
2 | using CMS.DataEngine;
3 | using DynamicRouting.Kentico.MVC;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | [assembly: RegisterModule(typeof(DynamicRouteInitializationModule_MVC))]
11 |
12 | namespace DynamicRouting.Kentico.MVC
13 | {
14 | public class DynamicRouteInitializationModule_MVC : Module
15 | {
16 | public DynamicRouteInitializationModule_MVC() : base("DynamicRouteInitializationModule_MVC")
17 | {
18 |
19 | }
20 |
21 | protected override void OnInit()
22 | {
23 | base.OnInit();
24 |
25 | // Call OnInit of the Base
26 | var BaseInitializationModule = new DynamicRouteInitializationModule_Base();
27 | BaseInitializationModule.Init();
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouteTemplateController.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using CMS.DocumentEngine;
3 | using DynamicRouting.Implementations;
4 | using DynamicRouting.Interfaces;
5 | using Kentico.PageBuilder.Web.Mvc;
6 | using Kentico.PageBuilder.Web.Mvc.PageTemplates;
7 | using Kentico.Web.Mvc;
8 | using System.Web.Mvc;
9 |
10 |
11 | namespace DynamicRouting.Kentico.MVC
12 | {
13 | public class DynamicRouteTemplateController : PageTemplateController
14 | {
15 | private IDynamicRouteHelper mDynamicRouteHelper;
16 |
17 | public DynamicRouteTemplateController()
18 | {
19 | this.mDynamicRouteHelper = new BaseDynamicRouteHelper();
20 | }
21 |
22 | ///
23 | /// Gets the node based on the current request url and then renders the template result.
24 | ///
25 | public ActionResult Index(string TemplateControllerName = null, bool? IncludeDocumentInOutputCache = null)
26 | {
27 | if (!IncludeDocumentInOutputCache.HasValue)
28 | {
29 | IncludeDocumentInOutputCache = DynamicRouteInternalHelper.GetDefaultAddPageToCacheDependency();
30 | }
31 | ITreeNode FoundNode = mDynamicRouteHelper.GetPage(Columns: new string[] { "DocumentID" }, AddPageToCacheDependency: IncludeDocumentInOutputCache.Value);
32 | if (FoundNode != null)
33 | {
34 | HttpContext.Kentico().PageBuilder().Initialize(FoundNode.DocumentID);
35 | if (!string.IsNullOrWhiteSpace(TemplateControllerName))
36 | {
37 | // Adjust the route data to point to the template's controller if it has one.
38 | HttpContext.Request.RequestContext.RouteData.Values["Controller"] = TemplateControllerName;
39 | }
40 | return new TemplateResult(FoundNode.DocumentID);
41 | }
42 | else
43 | {
44 | return new HttpNotFoundResult();
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRouting.Kentico.MVC.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | Kentico Community
8 | Kentico Community
9 | https://github.com/KenticoDevTrev/DynamicRouting
10 | http://www.kentico.com/favicon.ico
11 | false
12 | $description$
13 | Fixed bug in the LocalizationContext using the CultureName vs. CultureCode
14 | Copyright 2019 Kentico Community
15 | Dynamic Routing, Kentico, MVC
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRoutingAnalyzer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 |
6 | namespace DynamicRouting.Kentico.MVC
7 | {
8 | public static class DynamicRoutingAnalyzer
9 | {
10 | private static readonly Dictionary classNameLookup =
11 | new Dictionary();
12 |
13 | static DynamicRoutingAnalyzer()
14 | {
15 | var attributes = AppDomain
16 | .CurrentDomain
17 | .GetAssemblies()
18 | .Where(a => !a.FullName.StartsWith("CMS.") && !a.FullName.StartsWith("Kentico."))
19 | .SelectMany(a => a.GetCustomAttributes());
20 |
21 | foreach (var attribute in attributes)
22 | {
23 | if (attribute == null)
24 | {
25 | continue;
26 | }
27 | foreach (string pageClassName in attribute.PageClassNames)
28 | {
29 | string pageClassNameLookup = pageClassName.ToLowerInvariant();
30 | if (classNameLookup.TryGetValue(pageClassNameLookup, out var pair))
31 | {
32 | throw new Exception(
33 | "Duplicate Annotation: " +
34 | $"{pair.ControllerName}Controller.{pair.ActionName} already registered for NodeClassName {pageClassNameLookup}. " +
35 | $"Cannot be registered for {attribute.ControllerName}.{attribute.ActionMethodName}"
36 | );
37 | }
38 |
39 | classNameLookup.Add(pageClassNameLookup, new DynamicRouteConfiguration(
40 | controllerName: attribute.ControllerName,
41 | actionName: attribute.ActionMethodName,
42 | viewName: attribute.ViewName,
43 | modelType: attribute.ModelType,
44 | routeType: attribute.RouteType,
45 | includeDocumentInOutputCache: attribute.IncludeDocumentInOutputCache,
46 | useOutputCaching: attribute.UseOutputCaching
47 | ));
48 | }
49 | }
50 | }
51 |
52 | public static bool TryFindMatch(string nodeClassName, out DynamicRouteConfiguration match)
53 | {
54 | return classNameLookup.TryGetValue(nodeClassName.ToLowerInvariant(), out match);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/DynamicRoutingAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | namespace DynamicRouting.Kentico.MVC
5 | {
6 | ///
7 | /// Marks the given as the handler for HTTP requests
8 | /// for the specified matching
9 | /// for custom Page Types.
10 | ///
11 | [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
12 | public class DynamicRoutingAttribute : Attribute
13 | {
14 | ///
15 | /// Marks the given as the handler for HTTP requests
16 | /// for the specified matching
17 | /// for custom Page Types.
18 | ///
19 | /// The Controller Type
20 | /// The Page Class Names
21 | /// The Optional Action Method in the Controller to handle this request.
22 | public DynamicRoutingAttribute(Type controllerType, string[] pageClassNames, string actionMethodName = null)
23 | {
24 | if (controllerType is null)
25 | {
26 | throw new ArgumentNullException(nameof(controllerType));
27 | }
28 |
29 | if (pageClassNames is null)
30 | {
31 | throw new ArgumentNullException(nameof(pageClassNames));
32 | }
33 |
34 | ControllerName = controllerType.ControllerNamePrefix();
35 |
36 | if (!string.IsNullOrWhiteSpace(actionMethodName)) {
37 | ActionMethodName = actionMethodName;
38 | } else
39 | {
40 | ActionMethodName = "Index";
41 | }
42 |
43 | PageClassNames = pageClassNames
44 | .Select(n => n.ToLowerInvariant())
45 | .ToArray();
46 | RouteType = DynamicRouteType.Controller;
47 | UseOutputCaching = false;
48 | }
49 |
50 | ///
51 | /// Pages with the given Class Name will be routed to this View with the given Type (inheriting from ITreeNode)
52 | ///
53 | /// The View name that should be rendered.
54 | /// The Model that inherits
55 | /// The Class Name that this Dynamic Route applies to.
56 | /// If true, will add the Document ID to the repsonse's Cache Dependencies
57 | /// If true, will use an Output Cached Controller to render this.
58 |
59 | public DynamicRoutingAttribute(string viewName, Type modelType, string pageClassName, bool includeDocumentInOutputCache = true, bool useOutputCaching = false)
60 | {
61 | if (string.IsNullOrWhiteSpace(viewName))
62 | {
63 | throw new ArgumentNullException(nameof(viewName));
64 | }
65 |
66 | if (modelType is null)
67 | {
68 | throw new ArgumentNullException(nameof(modelType));
69 | }
70 |
71 | if (string.IsNullOrWhiteSpace(pageClassName))
72 | {
73 | throw new ArgumentNullException(nameof(pageClassName));
74 | }
75 |
76 | ViewName = viewName;
77 | ModelType = modelType;
78 | PageClassNames = new string[] { pageClassName };
79 | RouteType = DynamicRouteType.ViewWithModel;
80 | UseOutputCaching = useOutputCaching;
81 | IncludeDocumentInOutputCache = includeDocumentInOutputCache;
82 | }
83 |
84 | ///
85 | /// Pages with the given Class Names will be routed to this View.
86 | ///
87 | /// The View name that should be rendered.
88 | /// The Class Names that this Dynamic Route applies to.
89 | /// Will pass the page as the model for this view. If false, will not pass a model.
90 | /// If true, will add the Document ID to the repsonse's Cache Dependencies
91 | /// If true, will use an Output Cached Controller to render this.
92 | public DynamicRoutingAttribute(string viewName, string[] pageClassNames, bool IncludePageModel = true, bool includeDocumentInOutputCache = true, bool useOutputCaching = false)
93 | {
94 | if (string.IsNullOrWhiteSpace(viewName))
95 | {
96 | throw new ArgumentNullException(nameof(viewName));
97 | }
98 |
99 | if (pageClassNames is null)
100 | {
101 | throw new ArgumentNullException(nameof(pageClassNames));
102 | }
103 |
104 | ViewName = viewName;
105 | PageClassNames = pageClassNames
106 | .Select(n => n.ToLowerInvariant())
107 | .ToArray();
108 |
109 | if(IncludePageModel)
110 | {
111 | RouteType = DynamicRouteType.ViewWithModel;
112 | } else
113 | {
114 | RouteType = DynamicRouteType.View;
115 | }
116 | UseOutputCaching = useOutputCaching;
117 | IncludeDocumentInOutputCache = includeDocumentInOutputCache;
118 | }
119 |
120 | ///
121 | /// The name of the that
122 | /// handles requests for routes for the given
123 | ///
124 | public string ControllerName { get; }
125 |
126 | ///
127 | /// values.
128 | ///
129 | public string[] PageClassNames { get; }
130 |
131 | ///
132 | /// The name of the action method that will handle the request
133 | ///
134 | public string ActionMethodName { get; }
135 |
136 | public Type ModelType { get; }
137 |
138 | public string ViewName { get; }
139 |
140 | public bool UseOutputCaching { get; }
141 |
142 | public bool IncludeDocumentInOutputCache { get; }
143 |
144 | public DynamicRouteType RouteType { get; }
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/EmptyPageTemplate.cs:
--------------------------------------------------------------------------------
1 | using Kentico.PageBuilder.Web.Mvc.PageTemplates;
2 |
3 | // This is used as a trigger for the given page to ignore Page Templates, as Kentico by default requires a page template if one is selectable.
4 | [assembly: RegisterPageTemplate("Empty.Template", "No Template", customViewName: "", Description = "No Template (Use standard Routing)", IconClass = "icon-modal-close")]
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/EmptyPageTemplateFilter.cs:
--------------------------------------------------------------------------------
1 | using Kentico.PageBuilder.Web.Mvc.PageTemplates;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DynamicRouting.Kentico.MVC
9 | {
10 | ///
11 | /// This is to prevent a template from automatically being assigned. If there is at least 1 non-empty template that is available, this will add the "Empty" template as an option so the user can select.
12 | ///
13 | public class EmptyPageTemplateFilter : IPageTemplateFilter
14 | {
15 | public IEnumerable Filter(IEnumerable pageTemplates, PageTemplateFilterContext context)
16 | {
17 | // only add empty option if there is 1 non empty template remaining, so user has to choose.
18 | var NonEmptyTemplates = pageTemplates.Where(t => !GetTemplates().Contains(t.Identifier));
19 | if (NonEmptyTemplates.Count() > 0)
20 | {
21 | return pageTemplates;
22 | }
23 | else
24 | {
25 | // Remove the empty template as an option
26 | return pageTemplates.Where(t => !GetTemplates().Contains(t.Identifier));
27 | }
28 | }
29 |
30 | // Gets all page templates that are allowed for landing pages
31 | public IEnumerable GetTemplates() => new string[] { "Empty.Template" };
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Events/DynamicUrlEvents.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 | using System.Text;
4 | using System.Threading.Tasks;
5 |
6 | namespace DynamicRouting
7 | {
8 |
9 | public static class DynamicRoutingEvents
10 | {
11 | ///
12 | /// Overwrites the handling of finding a page based on the request.
13 | ///
14 | public static GetPageEventHandler GetPage;
15 |
16 | ///
17 | /// Allows overwrite of how to get the current culture
18 | ///
19 | public static GetCultureEventHandler GetCulture;
20 |
21 | ///
22 | /// Allows you to adjust the MVC Routing by modifying the Request Context
23 | ///
24 | public static RequestRoutingEventHandler RequestRouting;
25 |
26 | static DynamicRoutingEvents()
27 | {
28 | GetPage = new GetPageEventHandler()
29 | {
30 | Name = "DynamicRoutingEvents.GetPage"
31 | };
32 |
33 | GetCulture = new GetCultureEventHandler()
34 | {
35 | Name = "DynamicRoutingEvents.GetCulture"
36 | };
37 |
38 | RequestRouting = new RequestRoutingEventHandler()
39 | {
40 | Name = "DynamicRoutingEvents.RequestRouting"
41 | };
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Events/GetCultureEventArgs.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using CMS.DocumentEngine;
3 | using System;
4 | using System.Web;
5 |
6 | namespace DynamicRouting
7 | {
8 | public class GetCultureEventArgs : CMSEventArgs
9 | {
10 | ///
11 | /// The Culture, this is what you should set when determining the culture
12 | ///
13 | public string Culture { get; set; }
14 |
15 | ///
16 | /// The Site's Default culture, based on the Current Site
17 | ///
18 | public string DefaultCulture { get; set; }
19 |
20 | ///
21 | /// The Site Code Name of the current site
22 | ///
23 | public string SiteName { get; set; }
24 |
25 | ///
26 | /// The HttpRequest
27 | ///
28 | public HttpRequest Request { get; set; }
29 |
30 | ///
31 | /// True if Kentico's Preview is enable, if true the culture will be set by the PreviewEnabled after the "Before" event.
32 | ///
33 | public bool PreviewEnabled { get; set; }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Events/GetCultureEventHandler.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using DynamicRouting;
3 |
4 | namespace DynamicRouting
5 | {
6 | public class GetCultureEventHandler : AdvancedHandler
7 | {
8 | public GetCultureEventHandler()
9 | {
10 |
11 | }
12 |
13 | public GetCultureEventHandler StartEvent(GetCultureEventArgs CultureArgs)
14 | {
15 | return base.StartEvent(CultureArgs);
16 | }
17 |
18 | public void FinishEvent()
19 | {
20 | base.Finish();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Events/GetPageEventArgs.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using CMS.DocumentEngine;
3 | using System;
4 | using System.Web;
5 |
6 | namespace DynamicRouting
7 | {
8 | public class GetPageEventArgs : CMSEventArgs
9 | {
10 | ///
11 | /// The Page that is found, this is what will be returned from the GetPage function, set this.
12 | ///
13 | public ITreeNode FoundPage { get; set; }
14 |
15 | ///
16 | /// The Request's Relative Url (no query strings), cleaned to be proper lookup format
17 | ///
18 | public string RelativeUrl { get; set; }
19 |
20 | ///
21 | /// The Request's Culture
22 | ///
23 | public string Culture { get; set; }
24 |
25 | ///
26 | /// The Site's default culture
27 | ///
28 | public string DefaultCulture { get; set; }
29 |
30 | ///
31 | /// The current SiteName
32 | ///
33 | public string SiteName { get; set; }
34 |
35 | ///
36 | /// If Kentico's Preview mode is active (Preview/Edit)
37 | ///
38 | public bool PreviewEnabled { get; set; }
39 |
40 | ///
41 | /// The User's requested Columns to return with the page data
42 | ///
43 | public string ColumnsVal { get; set; }
44 |
45 | ///
46 | /// The full HttpRequest object
47 | ///
48 | public HttpRequest Request { get; set; }
49 |
50 | ///
51 | /// If an exception occurred between the Before and After (while looking up), this is the exception. Can be used for custom logging.
52 | ///
53 | public Exception ExceptionOnLookup { get; set; }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Events/GetPageEventHandler.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using DynamicRouting;
3 |
4 | namespace DynamicRouting
5 | {
6 | public class GetPageEventHandler : AdvancedHandler
7 | {
8 | public GetPageEventHandler()
9 | {
10 |
11 | }
12 |
13 | public GetPageEventHandler StartEvent(GetPageEventArgs PageArgs)
14 | {
15 | return base.StartEvent(PageArgs);
16 | }
17 |
18 | public void FinishEvent()
19 | {
20 | base.Finish();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Events/RequestRoutingEventArgs.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using CMS.DocumentEngine;
3 | using DynamicRouting.Kentico.MVC;
4 | using System;
5 | using System.Web;
6 | using System.Web.Routing;
7 |
8 | namespace DynamicRouting
9 | {
10 | public class RequestRoutingEventArgs : CMSEventArgs
11 | {
12 | ///
13 | /// The Page found by the Dynamic Routing
14 | ///
15 | public ITreeNode Page { get; set; }
16 |
17 | ///
18 | /// The Route Configuration that was determined by the MVC DynamicRouting attributes.
19 | /// The RouteData's Controller and Action values are automatically set to the Configuration.ControllerName and Configuration.ActionName
20 | /// UseOutputCaching only applies to the DynamicRoute Controller, and IncludeDocumentInOutputCache applies to Template and DynamicRoute Controllers
21 | ///
22 | ///
23 | public DynamicRouteConfiguration Configuration { get; set; }
24 |
25 | ///
26 | /// The Request Context, you can adjust the Route values through RequestContext.RouteData.Values.
27 | /// Configuration.ControllerName = "Blog";
28 | /// Configuration.ActionName = "Listing";
29 | /// CurrentRequestContext.RouteData.Values["SomeProperty"] = "Hello";
30 | /// This would route to the BlogController.Listing(string SomePropertyName) with SomePropertyName equalling Hello
31 | ///
32 | public RequestContext CurrentRequestContext { get; set; }
33 |
34 | public RequestRoutingEventArgs()
35 | {
36 |
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Events/RequestRoutingEventHandler.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using DynamicRouting;
3 |
4 | namespace DynamicRouting
5 | {
6 | public class RequestRoutingEventHandler : AdvancedHandler
7 | {
8 | public RequestRoutingEventHandler()
9 | {
10 |
11 | }
12 |
13 | public RequestRoutingEventHandler StartEvent(RequestRoutingEventArgs RequestArgs)
14 | {
15 | return base.StartEvent(RequestArgs);
16 | }
17 |
18 | public void FinishEvent()
19 | {
20 | base.Finish();
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Interfaces/IDynamicRouteHelper.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using DynamicRouting.Kentico.MVC;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace DynamicRouting.Interfaces
10 | {
11 | public interface IDynamicRouteHelper
12 | {
13 | ///
14 | /// Gets the CMS Page using Dynamic Routing, returning the culture variation that either matches the given culture or the Slug's culture, or the default site culture if not found.
15 | ///
16 | /// The Url (part after the domain), if empty will use the Current Request
17 | /// The Culture, not needed if the Url contains the culture that the UrlSlug has as part of it's generation.
18 | /// The Site Name, defaults to current site.
19 | /// List of columns you wish to include in the data returned.
20 | /// If true, the found page will have it's DocumentID added to the request's Output Cache Dependency
21 | /// The Page that matches the Url Slug, for the given or matching culture (or default culture if one isn't found).
22 | ITreeNode GetPage(string Url = "", string Culture = "", string SiteName = "", IEnumerable Columns = null, bool AddPageToCacheDependency = true);
23 |
24 | ///
25 | /// Gets the CMS Page using Dynamic Routing, returning the culture variation that either matches the given culture or the Slug's culture, or the default site culture if not found.
26 | ///
27 | /// The Url (part after the domain), if empty will use the Current Request
28 | /// The Culture, not needed if the Url contains the culture that the UrlSlug has as part of it's generation.
29 | /// The Site Name, defaults to current site.
30 | /// List of columns you wish to include in the data returned.
31 | /// If true, the found page will have it's DocumentID added to the request's Output Cache Dependency
32 | /// The Page that matches the Url Slug, for the given or matching culture (or default culture if one isn't found).
33 | T GetPage(string Url = "", string Culture = "", string SiteName = "", IEnumerable Columns = null, bool AddPageToCacheDependency = true) where T : ITreeNode;
34 |
35 |
36 | ///
37 | /// Gets the Page's Url Slug based on the given DocumentID and it's Culture.
38 | ///
39 | /// The Document ID
40 | ///
41 | string GetPageUrl(int DocumentID);
42 |
43 |
44 | ///
45 | /// Gets the Page's Url Slug based on the given DocumentGuid and it's Culture.
46 | ///
47 | /// The Document Guid
48 | /// The UrlSlug (with ~ prepended) or Null if page not found.
49 | string GetPageUrl(Guid DocumentGuid);
50 |
51 |
52 | ///
53 | /// Gets the Page's Url Slug based on the given NodeAliasPath, Culture and SiteName. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
54 | ///
55 | /// The Node alias path you wish to select
56 | /// The Document Culture, if not provided will use default Site's Culture.
57 | /// The Site Name, if not provided then the Current Site's name is used.
58 | /// The UrlSlug (with ~ prepended) or Null if page not found.
59 | string GetPageUrl(string NodeAliasPath, string DocumentCulture = null, string SiteName = null);
60 |
61 |
62 | ///
63 | /// Gets the Page's Url Slug based on the given NodeGuid and Culture. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
64 | ///
65 | /// The Node to find the Url Slug
66 | /// The Document Culture, if not provided will use default Site's Culture.
67 | /// The UrlSlug (with ~ prepended) or Null if page not found.
68 | string GetPageUrl(Guid NodeGuid, string DocumentCulture = null);
69 |
70 |
71 | ///
72 | /// Gets the Page's Url Slug based on the given NodeID and Culture. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
73 | ///
74 | /// The NodeID
75 | /// The Document Culture, if not provided will use default Site's Culture.
76 | /// The Site Name, if not provided then will query the NodeID to find it's site.
77 | /// The UrlSlug (with ~ prepended) or Null if page not found.
78 | string GetPageUrl(int NodeID, string DocumentCulture = null, string SiteName = null);
79 |
80 |
81 | ///
82 | /// Gets the Route Configuration based on The node's Class Name.
83 | ///
84 | /// The ITreeNode object
85 | /// The Route Configuration, empty DynamicRouteconfiguration if not found
86 | DynamicRouteConfiguration GetRouteConfiguration(ITreeNode node);
87 |
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/NoEmptyPageTemplateFilter.cs:
--------------------------------------------------------------------------------
1 | using Kentico.PageBuilder.Web.Mvc.PageTemplates;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 |
5 | namespace DynamicRouting.Kentico.MVC
6 | {
7 | ///
8 | /// Removes the Empty.Template always from the options, thus disabling it.
9 | ///
10 | public class NoEmptyPageTemplateFilter : IPageTemplateFilter
11 | {
12 | public IEnumerable Filter(IEnumerable pageTemplates, PageTemplateFilterContext context)
13 | {
14 | // Remove Empty.Template always
15 | return pageTemplates.Where(t => !GetTemplates().Contains(t.Identifier));
16 | }
17 |
18 | // Gets all page templates that are allowed for landing pages
19 | public IEnumerable GetTemplates() => new string[] { "Empty.Template" };
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using CMS;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("DynamicRouting.Kentico.MVC")]
10 | [assembly: AssemblyDescription("Allows for automatic detection of pages based on URL and routing based on refractoring. For the MVC Site only.")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("")]
13 | [assembly: AssemblyProduct("DynamicRouting.Kentico.MVC")]
14 | [assembly: AssemblyCopyright("2019 Kentico Community")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 | [assembly: AssemblyDiscoverable()]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | [assembly: Guid("8a9f8e7f-c18a-4d90-924a-27b50f5e51ff")]
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | // [assembly: AssemblyVersion("1.0.*")]
37 | [assembly: AssemblyVersion("12.29.20.0")]
38 | [assembly: AssemblyFileVersion("12.29.20.0")]
39 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/StaticRoutePriorityAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DynamicRouting.Kentico.MVC
4 | {
5 | ///
6 | /// This attribute indicates that Routes that map to this Controller should be enforced even if a page is found via Dynamic Routing.
7 | /// Example: If the Controller is ApiController and a request comes through as /api/GetItems, without this attribute if someone creates
8 | /// a page that has a UrlSlug of /api/GetItems then the request would be dynamically routed. With this attribute, the request would
9 | /// properly go to your ApiController class.
10 | ///
11 | [AttributeUsage(AttributeTargets.Class)]
12 | public class StaticRoutePriorityAttribute : Attribute
13 | {
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/StaticRoutePriorityConstraint.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Web;
7 | using System.Web.Mvc;
8 | using System.Web.Routing;
9 | using CacheHelper = CMS.Helpers.CacheHelper;
10 | using CacheSettings = CMS.Helpers.CacheSettings;
11 |
12 | namespace DynamicRouting.Kentico.MVC
13 | {
14 | ///
15 | /// Checks if the Controller the route is mapping to has the StaticRoutePriorityAttribute
16 | ///
17 | public class StaticRoutePriorityConstraint : IRouteConstraint
18 | {
19 | public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
20 | {
21 | // Check if the controller is found and has the KMVCRouteOverPathPriority attribute.
22 | string ControllerName = (values.ContainsKey("controller") ? values["controller"].ToString() : "");
23 | return CacheHelper.Cache(cs =>
24 | {
25 | // Check if the Route that it found has the override
26 | IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
27 | try
28 | {
29 | var Controller = factory.CreateController(new RequestContext(httpContext, new RouteData(route, null)), ControllerName);
30 | return Attribute.GetCustomAttribute(Controller.GetType(), typeof(StaticRoutePriorityAttribute)) != null;
31 | }
32 | catch (Exception)
33 | {
34 | return false;
35 | }
36 | }, new CacheSettings(1440, "StaticRoutePriorityConstraint", ControllerName));
37 | }
38 | }
39 |
40 |
41 | }
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.MVC/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/App_Data/Global/Resources/Kentico.Builder.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | The builder got into invalid state when changing sections. Please reload the builder.
122 |
123 |
124 | The custom element '{0}' has been already registered.
125 |
126 |
127 | An error has occurred. If the problem persists, contact your system administrator.
128 |
129 |
130 | Please select an option
131 |
132 |
133 | The inline editor '{0}' has been already registered.
134 |
135 |
136 | Expected property editor identifier of type string when registering an inline editor.
137 |
138 |
139 | The inline editor '{0}' is missing init function.
140 |
141 |
142 | Expected a function argument when registering an inline editor '{0}'
143 |
144 |
145 | The inline editor '{0}' is missing a property name data attribute or its value is empty.
146 |
147 |
148 | Registration of the inline editor '{0}' failed.
149 |
150 |
151 | The handlers of inline editor '{0}' are not of type object.
152 |
153 |
154 | Message received from forbidden origin: {0}.
155 |
156 |
157 | Loading
158 |
159 |
160 | Apply
161 |
162 |
163 | Cancel
164 |
165 |
166 | Close
167 |
168 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/App_Data/Global/Resources/Kentico.Components.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Select media file
122 |
123 |
124 | Select
125 |
126 |
127 | Media file selector
128 |
129 |
130 | The media library was not found.
131 |
132 |
133 | You are not authorized to view the media library content.
134 |
135 |
136 | This folder is empty
137 |
138 |
139 | The selected file(s) are not valid.
140 |
141 |
142 | Collapse
143 |
144 |
145 | Expand
146 |
147 |
148 | clear the selection
149 |
150 |
151 | or
152 |
153 |
154 | Select different file
155 |
156 |
157 | {0} out of {1} files selected
158 |
159 |
160 | Library:
161 |
162 |
163 | Drop file here or click to browse
164 |
165 |
166 | Select media files
167 |
168 |
169 | Filter the folder
170 |
171 |
172 | No items match your filter.<br />Perhaps they hide in a different folder.
173 |
174 |
175 | Show all
176 |
177 |
178 | An error occurred while uploading the file '{0}'. Contact your system administrator.
179 |
180 |
181 | Change file
182 |
183 |
184 | Remove file
185 |
186 |
187 | Clear all
188 |
189 |
190 | No items selected.
191 |
192 |
193 | Page selector
194 |
195 |
196 | Select page
197 |
198 |
199 | Selected page
200 |
201 |
202 | Select
203 |
204 |
205 | Clear
206 |
207 |
208 | No page selected
209 |
210 |
211 | Invalid page
212 |
213 |
214 | The selected page has been deleted or you don't have permissions to select it.
215 |
216 |
217 | The selected page has been deleted or you don't have permissions to select it. Please select a different page.
218 |
219 |
220 | {0} files selected
221 |
222 |
223 | Media files could not be loaded. Contact your system administrator.
224 |
225 |
226 | Type of the file '{0}' is not allowed.
227 |
228 |
229 | All files were successfully uploaded.
230 |
231 |
232 | Preconfigured root page '{0}' was not found.
233 |
234 |
235 | Close
236 |
237 |
238 | Error
239 |
240 |
241 | Success
242 |
243 |
244 | Upload of the file '{0}' timed out.
245 |
246 |
247 | Missing file
248 |
249 |
250 | File error
251 |
252 |
253 | Type of the selected media file is not allowed or you don't have permissions to see the file.
254 |
255 |
256 | Selected media file has been deleted.
257 |
258 |
259 | Path selector
260 |
261 |
262 | Select
263 |
264 |
265 | Select
266 |
267 |
268 | You are not authorized to view child pages of '{0}' page.
269 |
270 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/App_Data/Global/Resources/Kentico.PageBuilder.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Some widgets are not allowed here!
122 |
123 |
124 | This widget is not allowed here!
125 |
126 |
127 | The Page builder is initialized with missing page identifier.
128 |
129 |
130 | Add section
131 |
132 |
133 | Delete section
134 |
135 |
136 | Move section
137 |
138 |
139 | Sections
140 |
141 |
142 | Sections with the following identifiers are not registered in the system: {0}. Saving the page will result in lost data.
143 |
144 |
145 | Are you sure you want to remove the section?
146 |
147 |
148 | Change section type
149 |
150 |
151 | Add widget
152 |
153 |
154 | Delete widget
155 |
156 |
157 | Move widget
158 |
159 |
160 | Widgets
161 |
162 |
163 | Widgets with the following identifiers are not registered in the system: {0}. Saving the page will result in lost data.
164 |
165 |
166 | Personalize
167 |
168 |
169 | Are you sure you want to remove the selected widget?
170 |
171 |
172 | Display variant
173 |
174 |
175 | Condition types
176 |
177 |
178 | Personalize content based on:
179 |
180 |
181 | No widgets found.
182 |
183 |
184 | Some widgets cannot be displayed, because sections with the following identifiers do not contain enough widget zones: {0}. Saving the page will result in lost widget data.
185 |
186 |
187 | Condition types with the following identifiers are not registered in the system: {0}. Saving the page will result in lost data.
188 |
189 |
190 | Original
191 |
192 |
193 | Apply
194 |
195 |
196 | Back
197 |
198 |
199 | Delete variant
200 |
201 |
202 | Are you sure you want to remove the variant?
203 |
204 |
205 | Sections with the following section identifiers do not contain any widget zones: {0}. Sections without widget zones are not supported.
206 |
207 |
208 | Add variant
209 |
210 |
211 | Add new personalization variant
212 |
213 |
214 | Partial view of the condition type configuration must contain a form.
215 |
216 |
217 | Invalid format of response of the configuration form POST message. Expected is one of: application/json OR text/html.
218 |
219 |
220 | Areas with the following identifiers are missing from page markup: {0}. Saving the page will result in lost data.
221 |
222 |
223 | Configure widget
224 |
225 |
226 | Configure section
227 |
228 |
229 | Configure template
230 |
231 |
232 | Edit variant
233 |
234 |
235 | Display one of the variants:
236 |
237 |
238 | {0} properties
239 |
240 |
241 | Are you sure you want to close the dialog?
242 |
243 | You have unsaved changes.
244 |
245 | Press OK to continue or Cancel to stay on the current page.
246 |
247 |
248 | Apply variant changes
249 |
250 |
251 | Apply
252 |
253 |
254 | Apply properties
255 |
256 |
257 | Variant name
258 |
259 |
260 | Please provide variant name.
261 |
262 |
263 | Cancel
264 |
265 |
266 | Variant name wasn't found in form POST data.
267 |
268 |
269 | Change priority
270 |
271 |
272 | Default
273 |
274 |
275 | Page builder built-in section.
276 |
277 |
278 | Change template
279 |
280 |
281 | Change template
282 |
283 |
284 | You can now select a new template for your page. Note that changing the template may result in loss of your widget data.<br>
285 | <a href="{0}" target="_blank">Read more about page templates in our documentation</a>
286 |
287 |
288 | Are you sure you want to change the page template?
289 |
290 | All page content, i.e. widgets and sections with their data and properties, will be lost.
291 |
292 | Press OK to continue or Cancel to keep this template.
293 |
294 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/BuildPackage.bat:
--------------------------------------------------------------------------------
1 | nuget pack DynamicRouting.csproj -Prop Configuration=Release
2 | @echo off
3 | set /p DUMMY="Hit ENTER to exit..."
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/DynamicRouteMacroMethods.cs:
--------------------------------------------------------------------------------
1 | using CMS;
2 | using CMS.Helpers;
3 | using CMS.MacroEngine;
4 | using CMS.SiteProvider;
5 | using DynamicRouting.Kentico;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | [assembly: RegisterExtension(typeof(DynamicRouteMacroMethods), typeof(UtilNamespace))]
13 |
14 | namespace DynamicRouting.Kentico
15 | {
16 | public class DynamicRouteMacroMethods : MacroMethodContainer
17 | {
18 | [MacroMethod(typeof(string), "Retrieves the Parent's Url Slug", 0)]
19 | public static object ParentUrl(EvaluationContext context, params object[] parameters)
20 | {
21 | // Based on the Macro Resolver which has the TreeNode Data, return the ParentUrl
22 | int NodeID = ValidationHelper.GetInteger(context.Resolver.ResolveMacros("{% NodeID %}"), 0);
23 | int NodeParentID = ValidationHelper.GetInteger(context.Resolver.ResolveMacros("{% NodeParentID %}"), 0);
24 | string Culture = ValidationHelper.GetString(context.Resolver.ResolveMacros("{% DocumentCulture %}"), "en-US");
25 | string DefaultCulture = DynamicRouteInternalHelper.SiteContextSafe().DefaultVisitorCulture;
26 | return CacheHelper.Cache(cs =>
27 | {
28 | UrlSlugInfo Slug = UrlSlugInfoProvider.GetUrlSlugs()
29 | .WhereEquals("UrlSlugNodeID", NodeParentID)
30 | .OrderBy($"case when UrlSlugCultureCode = '{Culture}' then 0 else 1 end, case when UrlSlugCultureCode = '{DefaultCulture}' then 0 else 1 end")
31 | .Columns("UrlSlug")
32 | .FirstOrDefault();
33 | if(cs.Cached)
34 | {
35 | cs.CacheDependency = CacheHelper.GetCacheDependency("dynamicrouting.urlslug|all");
36 | }
37 | return Slug != null ? Slug.UrlSlug : "";
38 | }, new CacheSettings(1440, "GetUrlSlug", NodeParentID, Culture, DefaultCulture));
39 |
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/DynamicRouting.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | $author$
8 | $author$
9 | https://github.com/KenticoDevTrev/DynamicRouting
10 | https://raw.githubusercontent.com/Kentico/devnet.kentico.com/master/marketplace/assets/generic-integration.png
11 | false
12 | $description$
13 |
14 | 2019 Kentico Community
15 | Dynamic Routing Kentico
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/Helpers/DynamicRouteHelper.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using CMS.DataEngine;
3 | using CMS.DocumentEngine;
4 | using CMS.Helpers;
5 | using CMS.Localization;
6 | using CMS.PortalEngine;
7 | using CMS.SiteProvider;
8 | using DynamicRouting.Helpers;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Data;
12 | using System.Linq;
13 | using System.Web;
14 |
15 | namespace DynamicRouting.Kentico
16 | {
17 | public static class DynamicRouteHelper
18 | {
19 | ///
20 | /// Gets the CMS Page using the given Url Slug.
21 | ///
22 | /// The UrlSlug to look up (part after the domain)
23 | /// The Culture, not needed if the Url contains the culture that the UrlSlug has as part of it's generation.
24 | /// The Site Name, defaults to current site.
25 | /// List of columns you wish to include in the data returned.
26 | /// The Page that matches the Url Slug, for the given or matching culture (or default culture if one isn't found).
27 | public static ITreeNode GetPage(string UrlSlug = "", string Culture = "", string SiteName = "", IEnumerable Columns = null)
28 | {
29 | // Load defaults
30 | SiteName = (!string.IsNullOrWhiteSpace(SiteName) ? SiteName : DynamicRouteInternalHelper.SiteContextSafe().SiteName);
31 | string DefaultCulture = DynamicRouteInternalHelper.SiteContextSafe().DefaultVisitorCulture;
32 |
33 | // Handle Preview, during Route Config the Preview isn't available and isn't really needed, so ignore the thrown exception
34 | bool PreviewEnabled = false;
35 | try
36 | {
37 | PreviewEnabled = PortalContext.ViewMode != ViewModeEnum.LiveSite;
38 | }
39 | catch (InvalidOperationException) { }
40 |
41 | // set the culture
42 | if(string.IsNullOrWhiteSpace(Culture)) {
43 | Culture = LocalizationContext.CurrentCulture.CultureName;
44 | }
45 |
46 | // Convert Columns to
47 | string ColumnsVal = Columns != null ? string.Join(",", Columns.Distinct()) : "*";
48 |
49 | // Run any GetPage Event hooks which allow the users to set the Found Page
50 | ITreeNode FoundPage = null;
51 |
52 | try
53 | {
54 | // Get Page based on Url
55 | FoundPage = CacheHelper.Cache(cs =>
56 | {
57 | // Using custom query as Kentico's API was not properly handling a Join and where.
58 | DataTable NodeTable = ConnectionHelper.ExecuteQuery("DynamicRouting.UrlSlug.GetDocumentsByUrlSlug", new QueryDataParameters()
59 | {
60 | {"@Url", UrlSlug },
61 | {"@Culture", Culture },
62 | {"@DefaultCulture", DefaultCulture },
63 | {"@SiteName", SiteName },
64 | {"@PreviewEnabled", PreviewEnabled }
65 | }, topN: 1, columns: "DocumentID, ClassName").Tables[0];
66 | if (NodeTable.Rows.Count > 0)
67 | {
68 | int DocumentID = ValidationHelper.GetInteger(NodeTable.Rows[0]["DocumentID"], 0);
69 | string ClassName = ValidationHelper.GetString(NodeTable.Rows[0]["ClassName"], "");
70 |
71 | DocumentQuery Query = DocumentHelper.GetDocuments(ClassName)
72 | .WhereEquals("DocumentID", DocumentID);
73 |
74 | // Handle Columns
75 | if (!string.IsNullOrWhiteSpace(ColumnsVal))
76 | {
77 | Query.Columns(ColumnsVal);
78 | }
79 |
80 | // Handle Preview
81 | if (PreviewEnabled)
82 | {
83 | Query.LatestVersion(true)
84 | .Published(false);
85 | }
86 | else
87 | {
88 | Query.PublishedVersion(true);
89 | }
90 |
91 | TreeNode Page = Query.FirstOrDefault();
92 |
93 | // Cache dependencies on the Url Slugs and also the DocumentID if available.
94 | if (cs.Cached)
95 | {
96 | if (Page != null)
97 | {
98 | cs.CacheDependency = CacheHelper.GetCacheDependency(new string[] {
99 | "dynamicrouting.urlslug|all",
100 | "dynamicrouting.versionhistoryurlslug|all",
101 | "dynamicrouting.versionhistoryurlslug|bydocumentid|"+Page.DocumentID,
102 | "documentid|" + Page.DocumentID, });
103 | }
104 | else
105 | {
106 | cs.CacheDependency = CacheHelper.GetCacheDependency(new string[] { "dynamicrouting.urlslug|all", "dynamicrouting.versionhistoryurlslug|all" });
107 | }
108 |
109 | }
110 |
111 | // Return Page Data
112 | return Query.FirstOrDefault();
113 | }
114 | else
115 | {
116 | return null;
117 | }
118 | }, new CacheSettings(1440, "DynamicRoutine.GetPageMother", UrlSlug, Culture, DefaultCulture, SiteName, PreviewEnabled, ColumnsVal));
119 | }
120 | catch (Exception ex)
121 | {
122 | }
123 | return FoundPage;
124 | }
125 |
126 | ///
127 | /// Gets the CMS Page using Dynamic Routing, returning the culture variation that either matches the given culture or the Slug's culture, or the default site culture if not found.
128 | ///
129 | /// The Url (part after the domain), if empty will use the Current Request
130 | /// The Culture, not needed if the Url contains the culture that the UrlSlug has as part of it's generation.
131 | /// The Site Name, defaults to current site.
132 | /// List of columns you wish to include in the data returned.
133 | /// The Page that matches the Url Slug, for the given or matching culture (or default culture if one isn't found).
134 | public static T GetPage(string Url = "", string Culture = "", string SiteName = "", IEnumerable Columns = null) where T : ITreeNode
135 | {
136 | return (T)GetPage(Url, Culture, SiteName, Columns);
137 | }
138 |
139 | ///
140 | /// Gets the Page's Url Slug based on the given DocumentID and it's Culture.
141 | ///
142 | /// The Document ID
143 | ///
144 | public static string GetPageUrl(int DocumentID)
145 | {
146 | return DynamicRouteInternalHelper.GetPageUrl(DocumentID);
147 | }
148 |
149 | ///
150 | /// Gets the Page's Url Slug based on the given DocumentGuid and it's Culture.
151 | ///
152 | /// The Document Guid
153 | /// The UrlSlug (with ~ prepended) or Null if page not found.
154 | public static string GetPageUrl(Guid DocumentGuid)
155 | {
156 | return DynamicRouteInternalHelper.GetPageUrl(DocumentGuid);
157 | }
158 |
159 | ///
160 | /// Gets the Page's Url Slug based on the given NodeAliasPath, Culture and SiteName. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
161 | ///
162 | /// The Node alias path you wish to select
163 | /// The Document Culture, if not provided will use default Site's Culture.
164 | /// The Site Name, if not provided then the Current Site's name is used.
165 | /// The UrlSlug (with ~ prepended) or Null if page not found.
166 | public static string GetPageUrl(string NodeAliasPath, string DocumentCulture = null, string SiteName = null)
167 | {
168 | return DynamicRouteInternalHelper.GetPageUrl(NodeAliasPath, DocumentCulture, SiteName);
169 | }
170 |
171 | ///
172 | /// Gets the Page's Url Slug based on the given NodeGuid and Culture. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
173 | ///
174 | /// The Node to find the Url Slug
175 | /// The Document Culture, if not provided will use default Site's Culture.
176 | /// The UrlSlug (with ~ prepended) or Null if page not found.
177 | public static string GetPageUrl(Guid NodeGuid, string DocumentCulture = null)
178 | {
179 | return DynamicRouteInternalHelper.GetPageUrl(NodeGuid, DocumentCulture);
180 | }
181 |
182 | ///
183 | /// Gets the Page's Url Slug based on the given NodeID and Culture. If Culture not found, then will prioritize the Site's Default Culture, then Cultures by alphabetical order.
184 | ///
185 | /// The NodeID
186 | /// The Document Culture, if not provided will use default Site's Culture.
187 | /// The Site Name, if not provided then will query the NodeID to find it's site.
188 | /// The UrlSlug (with ~ prepended) or Null if page not found.
189 | public static string GetPageUrl(int NodeID, string DocumentCulture = null, string SiteName = null)
190 | {
191 | return DynamicRouteInternalHelper.GetPageUrl(NodeID, DocumentCulture, SiteName);
192 | }
193 |
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/Helpers/DynamicRouteInitializationModule_Mother.cs:
--------------------------------------------------------------------------------
1 | using CMS;
2 | using CMS.DataEngine;
3 | using CMS.Modules;
4 | using DynamicRouting.Kentico.Mother;
5 |
6 | [assembly: RegisterModule(typeof(DynamicRouteInitializationModule_Mother))]
7 |
8 | namespace DynamicRouting.Kentico.Mother
9 | {
10 | public class DynamicRouteInitializationModule_Mother : Module
11 | {
12 | public DynamicRouteInitializationModule_Mother() : base("DynamicRouteInitializationModule_Mother")
13 | {
14 |
15 | }
16 |
17 | protected override void OnInit()
18 | {
19 | base.OnInit();
20 |
21 | // Call OnInit of the Base
22 | var BaseInitializationModule = new DynamicRouteInitializationModule_Base();
23 | BaseInitializationModule.Init();
24 |
25 | // Nuget Manifest Build
26 | ModulePackagingEvents.Instance.BuildNuSpecManifest.After += BuildNuSpecManifest_After;
27 | }
28 |
29 | private void BuildNuSpecManifest_After(object sender, BuildNuSpecManifestEventArgs e)
30 | {
31 | if (e.ResourceName.Equals("DynamicRouting.Kentico", System.StringComparison.InvariantCultureIgnoreCase))
32 | {
33 | e.Manifest.Metadata.Owners = "Kentico Community";
34 | e.Manifest.Metadata.ProjectUrl = "https://github.com/KenticoDevTrev/DynamicRouting";
35 | e.Manifest.Metadata.IconUrl = "http://www.kentico.com/favicon.ico";
36 | e.Manifest.Metadata.Copyright = "Copyright 2019 Kentico Community";
37 | e.Manifest.Metadata.Title = "Dynamic Routing for Kentico v12 SP";
38 | e.Manifest.Metadata.ReleaseNotes = "Added Security (Read permissioN) to Quick Operations, fixed Culture bug.";
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/Helpers/DynamicRouteScheduledTasks.cs:
--------------------------------------------------------------------------------
1 | using CMS.Scheduler;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace DynamicRouting.Kentico
9 | {
10 | public class DynamicRouteScheduledTasks : ITask
11 | {
12 | public string Execute(TaskInfo task)
13 | {
14 | string Result = "";
15 | switch (task.TaskName.ToLower())
16 | {
17 | case "checkurlslugqueue":
18 | DynamicRouteInternalHelper.CheckUrlSlugGenerationQueue();
19 | break;
20 | }
21 | return Result;
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/Helpers/SlugGenerationQueueUnigridExtension.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base.Web.UI;
2 | using CMS.Helpers;
3 | using CMS.UIControls;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace DynamicRouting.Kentico
11 | {
12 | public class SlugGenerationQueueUnigridExtension : ControlExtender
13 | {
14 | public override void OnInit()
15 | {
16 | Control.OnAction += Control_OnAction;
17 | Control.OnExternalDataBound += Control_OnExternalDataBound;
18 | }
19 |
20 | private object Control_OnExternalDataBound(object sender, string sourceName, object parameter)
21 | {
22 | switch(sourceName.ToLower())
23 | {
24 | case "haserrors":
25 | return string.IsNullOrWhiteSpace(ValidationHelper.GetString(parameter, "")) ? "No" : "Yes";
26 | default:
27 | return parameter;
28 | }
29 | }
30 |
31 | private void Control_OnAction(string actionName, object actionArgument)
32 | {
33 | switch (actionName.ToLower())
34 | {
35 | case "run":
36 | int SlugQueueID = ValidationHelper.GetInteger(actionArgument, 0);
37 | if(SlugQueueID > 0)
38 | {
39 | DynamicRouteInternalHelper.RunSlugGenerationQueueItem(SlugQueueID);
40 | }
41 | break;
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/MacroMethodForDynamicRoutingMacroPageType.txt:
--------------------------------------------------------------------------------
1 | using CMS;
2 | using CMS.Helpers;
3 | using CMS.MacroEngine;
4 | using CMS.SiteProvider;
5 | using CMSApp.Old_App_Code;
6 | using System;
7 | using System.Linq;
8 |
9 | [assembly: RegisterExtension(typeof(ToolsMVCMacroMethods), typeof(UtilNamespace))]
10 | [assembly: RegisterExtension(typeof(ToolsMVCMacroMethods), typeof(bool))]
11 |
12 | namespace CMSApp.Old_App_Code
13 | {
14 | public class ToolsMVCMacroMethods : MacroMethodContainer
15 | {
16 | [MacroMethod(typeof(string), "Gets the Proper Url Pattern Title based on the settings of the DynamicRouting.Macro fields", 3)]
17 | [MacroMethodParam(0, "IncludeSubTitle", typeof(bool), "If the Sub Title should be appended to the title for the URL")]
18 | [MacroMethodParam(1, "Title", typeof(string), "The Title")]
19 | [MacroMethodParam(2, "SubTitle", typeof(string), "The Sub Title.")]
20 | public static object SubTitleAddition(EvaluationContext context, params object[] parameters)
21 | {
22 | // Based on the Macro Resolver which has the TreeNode Data, return the ParentUrl
23 | if(parameters.Length < 3)
24 | {
25 | throw new NotSupportedException();
26 | }
27 | bool IncludeSubTitle = ValidationHelper.GetBoolean(parameters[0], false);
28 | string Title = ValidationHelper.GetString(parameters[1], "");
29 | string SubTitle = ValidationHelper.GetString(parameters[2], "");
30 |
31 | if(IncludeSubTitle && !string.IsNullOrWhiteSpace(SubTitle))
32 | {
33 | return Title + " " + SubTitle;
34 | } else
35 | {
36 | return Title;
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using CMS;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("Dynamic Routing for Kentico MVC")]
10 | [assembly: AssemblyDescription("Allows for automatic detection of pages based on URL and routing based on refractoring. For the Mother application only.")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("Mixed")]
13 | [assembly: AssemblyProduct("Dynamic Routing for Kentico")]
14 | [assembly: AssemblyCopyright("2019 Kentico Community")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 | [assembly: AssemblyDiscoverable]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | // The following GUID is for the ID of the typelib if this project is exposed to COM
25 | [assembly: Guid("8e010e77-58f7-4cad-98ac-81804edd4a68")]
26 |
27 | // Version information for an assembly consists of the following four values:
28 | //
29 | // Major Version
30 | // Minor Version
31 | // Build Number
32 | // Revision
33 | //
34 | // You can specify all the values or you can default the Build and Revision Numbers
35 | // by using the '*' as shown below:
36 | [assembly: AssemblyVersion("12.29.20.0")]
37 | [assembly: AssemblyFileVersion("12.29.20.0")]
38 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/ShareableComponentBoilerplate.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $id$
5 | $version$
6 | $title$
7 | $author$
8 | $author$
9 | http://www.github.com/YourAccount/YourProject
10 | http://www.kentico.com/favicon.ico
11 | false
12 | $description$
13 |
14 | Copyright 2019 Kentico Community
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/Testing/QuickOperations.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | //
5 | // Changes to this file may cause incorrect behavior and will be lost if
6 | // the code is regenerated.
7 | //
8 | //------------------------------------------------------------------------------
9 |
10 | namespace CMSApp.CMSModules.DynamicRouting
11 | {
12 |
13 |
14 | public partial class QuickOperations
15 | {
16 |
17 | ///
18 | /// form1 control.
19 | ///
20 | ///
21 | /// Auto-generated field.
22 | /// To modify move field declaration from designer file to code-behind file.
23 | ///
24 | protected global::System.Web.UI.HtmlControls.HtmlForm form1;
25 |
26 | ///
27 | /// btnRebuildSite control.
28 | ///
29 | ///
30 | /// Auto-generated field.
31 | /// To modify move field declaration from designer file to code-behind file.
32 | ///
33 | protected global::System.Web.UI.WebControls.Button btnRebuildSite;
34 |
35 | ///
36 | /// tbxPath control.
37 | ///
38 | ///
39 | /// Auto-generated field.
40 | /// To modify move field declaration from designer file to code-behind file.
41 | ///
42 | protected global::CMS.FormEngine.Web.UI.FormControl tbxPath;
43 |
44 | ///
45 | /// btnRebuildSubTree control.
46 | ///
47 | ///
48 | /// Auto-generated field.
49 | /// To modify move field declaration from designer file to code-behind file.
50 | ///
51 | protected global::System.Web.UI.WebControls.Button btnRebuildSubTree;
52 |
53 | ///
54 | /// btnRunQueue control.
55 | ///
56 | ///
57 | /// Auto-generated field.
58 | /// To modify move field declaration from designer file to code-behind file.
59 | ///
60 | protected global::System.Web.UI.WebControls.Button btnRunQueue;
61 |
62 | ///
63 | /// tbxRouteToTest control.
64 | ///
65 | ///
66 | /// Auto-generated field.
67 | /// To modify move field declaration from designer file to code-behind file.
68 | ///
69 | protected global::System.Web.UI.WebControls.TextBox tbxRouteToTest;
70 |
71 | ///
72 | /// btnCheckUrl control.
73 | ///
74 | ///
75 | /// Auto-generated field.
76 | /// To modify move field declaration from designer file to code-behind file.
77 | ///
78 | protected global::System.Web.UI.WebControls.Button btnCheckUrl;
79 |
80 | ///
81 | /// btnCheckUrl control.
82 | ///
83 | ///
84 | /// Auto-generated field.
85 | /// To modify move field declaration from designer file to code-behind file.
86 | ///
87 | protected global::System.Web.UI.WebControls.Button btnCleanWipe;
88 |
89 | ///
90 | /// ltrPageFound control.
91 | ///
92 | ///
93 | /// Auto-generated field.
94 | /// To modify move field declaration from designer file to code-behind file.
95 | ///
96 | protected global::System.Web.UI.WebControls.Literal ltrPageFound;
97 |
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/Testing/QuickOperations.cs:
--------------------------------------------------------------------------------
1 | using CMS.Base;
2 | using CMS.DataEngine;
3 | using CMS.DocumentEngine;
4 | using CMS.EventLog;
5 | using CMS.Membership;
6 | using CMS.SiteProvider;
7 | using CMS.UIControls;
8 | using DynamicRouting;
9 | using DynamicRouting.Kentico;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Linq;
13 |
14 | namespace CMSApp.CMSModules.DynamicRouting
15 | {
16 | public partial class QuickOperations : CMSPage
17 | {
18 | protected override void OnPreInit(EventArgs e)
19 | {
20 | CurrentUserInfo currentUser = MembershipContext.AuthenticatedUser;
21 |
22 | // Ensure access
23 | if (!currentUser.IsAuthorizedPerResource("DynamicRouting.Kentico", "Read"))
24 | {
25 | RedirectToAccessDenied("DynamicRouting.Kentico", "Read");
26 | }
27 |
28 | base.OnPreInit(e);
29 | }
30 |
31 | protected void Page_Load(object sender, EventArgs e)
32 | {
33 |
34 | }
35 |
36 | protected void btnRebuildSite_Click(object sender, EventArgs e)
37 | {
38 | DynamicRouteInternalHelper.RebuildRoutesBySite(DynamicRouteInternalHelper.SiteContextSafe().SiteName);
39 | }
40 |
41 | protected void btnRebuildSubTree_Click(object sender, EventArgs e)
42 | {
43 | TreeNode Page = DocumentHelper.GetDocuments().Path("/"+tbxPath.Value.ToString().Trim('%').Trim('/')).FirstOrDefault();
44 |
45 | if (Page != null)
46 | {
47 | DynamicRouteInternalHelper.RebuildSubtreeRoutesByNode(Page.NodeID);
48 | }
49 | }
50 |
51 | protected void btnCheckUrl_Click(object sender, EventArgs e)
52 | {
53 | ITreeNode Node = DynamicRouteHelper.GetPage(tbxRouteToTest.Text);
54 | if (Node != null)
55 | {
56 | ltrPageFound.Text = $"FOUND! {Node.NodeAliasPath} {Node.ClassName} {Node.DocumentCulture}";
57 | }
58 | else
59 | {
60 | ltrPageFound.Text = "No Node Found";
61 | }
62 | }
63 |
64 | protected void btnCleanWipe_Click(object sender, EventArgs e)
65 | {
66 | // clear out
67 | ConnectionHelper.ExecuteNonQuery("truncate table DynamicRouting_SlugGenerationQueue", null, QueryTypeEnum.SQLQuery, true);
68 | ConnectionHelper.ExecuteNonQuery("truncate table DynamicRouting_UrlSlug", null, QueryTypeEnum.SQLQuery, true);
69 | ConnectionHelper.ExecuteNonQuery("truncate table DynamicRouting_UrlSlugStagingTaskIgnore", null, QueryTypeEnum.SQLQuery, true);
70 | foreach(SiteInfo Site in SiteInfoProvider.GetSites()) {
71 | DynamicRouteInternalHelper.RebuildRoutesBySite(Site.SiteName);
72 | }
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/DynamicRouting.Kentico.Mother/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/DynamicRouting.sln:
--------------------------------------------------------------------------------
1 | Microsoft Visual Studio Solution File, Format Version 12.00
2 | # Visual Studio Version 16
3 | VisualStudioVersion = 16.0.29424.173
4 | MinimumVisualStudioVersion = 10.0.40219.1
5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicRouting.Kentico.Base", "DynamicRouting.Kentico.Base\DynamicRouting.Kentico.Base.csproj", "{66553B70-EF4A-40BA-B077-F5B88826EB82}"
6 | EndProject
7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicRouting.Kentico.MVC", "DynamicRouting.Kentico.MVC\DynamicRouting.Kentico.MVC.csproj", "{8A9F8E7F-C18A-4D90-924A-27B50F5E51FF}"
8 | EndProject
9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DynamicRouting.Kentico", "DynamicRouting.Kentico.Mother\DynamicRouting.Kentico.csproj", "{60D45549-BB62-4999-8F29-987B58B33127}"
10 | EndProject
11 | Global
12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
13 | Debug|Any CPU = Debug|Any CPU
14 | Release|Any CPU = Release|Any CPU
15 | EndGlobalSection
16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
17 | {66553B70-EF4A-40BA-B077-F5B88826EB82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
18 | {66553B70-EF4A-40BA-B077-F5B88826EB82}.Debug|Any CPU.Build.0 = Debug|Any CPU
19 | {66553B70-EF4A-40BA-B077-F5B88826EB82}.Release|Any CPU.ActiveCfg = Release|Any CPU
20 | {66553B70-EF4A-40BA-B077-F5B88826EB82}.Release|Any CPU.Build.0 = Release|Any CPU
21 | {8A9F8E7F-C18A-4D90-924A-27B50F5E51FF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
22 | {8A9F8E7F-C18A-4D90-924A-27B50F5E51FF}.Debug|Any CPU.Build.0 = Debug|Any CPU
23 | {8A9F8E7F-C18A-4D90-924A-27B50F5E51FF}.Release|Any CPU.ActiveCfg = Release|Any CPU
24 | {8A9F8E7F-C18A-4D90-924A-27B50F5E51FF}.Release|Any CPU.Build.0 = Release|Any CPU
25 | {60D45549-BB62-4999-8F29-987B58B33127}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26 | {60D45549-BB62-4999-8F29-987B58B33127}.Debug|Any CPU.Build.0 = Debug|Any CPU
27 | {60D45549-BB62-4999-8F29-987B58B33127}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {60D45549-BB62-4999-8F29-987B58B33127}.Release|Any CPU.Build.0 = Release|Any CPU
29 | EndGlobalSection
30 | GlobalSection(SolutionProperties) = preSolution
31 | HideSolutionNode = FALSE
32 | EndGlobalSection
33 | GlobalSection(ExtensibilityGlobals) = postSolution
34 | SolutionGuid = {7DBE6E9A-E9DA-49A3-AD90-5CC16067A619}
35 | EndGlobalSection
36 | EndGlobal
37 |
--------------------------------------------------------------------------------
/DynamicRoutingStarterSite.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KenticoDevTrev/DynamicRouting/b352bee0ccd67a3d28e5de6dbcced522657664c4/DynamicRoutingStarterSite.zip
--------------------------------------------------------------------------------
/RenameProject.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | echo --INSTRUCTIONS--
3 | echo Do not use any of these characters: " ' @ $ # `, if you wish to use any of these you must do so manually after this script is done.
4 | set /p ToolName="Enter ToolName (a-Z_): "
5 | set /p Prefix="Enter Assembly Prefix (a-Z_.), usually Company (ex 'HBS.'): "
6 | set /p PostFix="Enter Assembly Postfix (a-Z_.) (ex '.Kentico.MVC'): "
7 | set /p GitHubUrl="Enter GitHub Url: "
8 | set /p Tags="Enter NuGet Tags (space separated): "
9 | set /p AssemblyTitle="Enter Assembly Title: "
10 | set /p AssemblyDescription="Enter Assembly Description: "
11 | set /p AssemblyCompany="Enter Assembly Company: "
12 | set /p AssemblyProduct="Enter Assembly Product Name: "
13 | set /p AssemblyCopyright="Enter Assembly Copyright: "
14 |
15 | cd ShareableComponentBoilerplate.Views
16 | cd Views
17 | cd Shared
18 | cd Widgets
19 | powershell -Command "(gc _ShareableComponentBoilerplate.cshtml) -replace 'CompanyName.ShareableComponentBoilerplate.Kentico.MVC', '%Prefix%%ToolName%%PostFix%' | Out-File -encoding ASCII _ShareableComponentBoilerplate.cshtml"
20 | powershell -Command "(gc _ShareableComponentBoilerplate.cshtml) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII _ShareableComponentBoilerplate.cshtml"
21 | rename _ShareableComponentBoilerplate.cshtml _%ToolName%.cshtml
22 | cd..
23 | cd..
24 | cd..
25 |
26 | cd Properties
27 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyTitleHere', '%AssemblyTitle%' | Out-File -encoding ASCII AssemblyInfo.cs"
28 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyDescriptionHere', '%AssemblyDescription%' | Out-File -encoding ASCII AssemblyInfo.cs"
29 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyCompanyHere', '%AssemblyCompany%' | Out-File -encoding ASCII AssemblyInfo.cs"
30 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyProductHere', '%AssemblyProduct%' | Out-File -encoding ASCII AssemblyInfo.cs"
31 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyCopyrightHere', '%AssemblyCopyright%' | Out-File -encoding ASCII AssemblyInfo.cs"
32 | powershell -Command "(gc AssemblyInfo.cs) -replace '3703e296-cd7c-47ff-9ab5-19b621c80b15', [GUID]::NewGuid() | Out-File -encoding ASCII AssemblyInfo.cs"
33 | cd..
34 |
35 | powershell -Command "(gc ShareableComponentBoilerplate.Views.csproj) -replace 'CompanyName.ShareableComponentBoilerplate.Kentico.MVC', '%Prefix%%ToolName%%PostFix%' | Out-File -encoding ASCII ShareableComponentBoilerplate.Views.csproj"
36 | powershell -Command "(gc ShareableComponentBoilerplate.Views.csproj) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII ShareableComponentBoilerplate.Views.csproj"
37 |
38 | rename ShareableComponentBoilerplate.Views.csproj %ToolName%.Views.csproj
39 | cd..
40 |
41 | rename ShareableComponentBoilerplate.Views %ToolName%.Views
42 |
43 | cd ShareableComponentBoilerplate
44 | powershell -Command "(gc BuildPackage.bat) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII BuildPackage.bat"
45 |
46 | powershell -Command "(gc ShareableComponentBoilerplateWidget.cs) -replace 'CompanyName.ShareableComponentBoilerplate.Kentico.MVC', '%Prefix%%ToolName%%PostFix%' | Out-File -encoding ASCII ShareableComponentBoilerplateWidget.cs"
47 | powershell -Command "(gc ShareableComponentBoilerplateWidget.cs) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII ShareableComponentBoilerplateWidget.cs"
48 | powershell -Command "(gc ShareableComponentBoilerplateWidget.cs) -replace 'CompanyName.', '%Prefix%' | Out-File -encoding ASCII ShareableComponentBoilerplateWidget.cs"
49 | rename ShareableComponentBoilerplateWidget.cs %ToolName%Widget.cs
50 |
51 | powershell -Command "(gc ShareableComponentBoilerplateWidgetModel.cs) -replace 'CompanyName.ShareableComponentBoilerplate.Kentico.MVC', '%Prefix%%ToolName%%PostFix%' | Out-File -encoding ASCII ShareableComponentBoilerplateWidgetModel.cs"
52 | powershell -Command "(gc ShareableComponentBoilerplateWidgetModel.cs) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII ShareableComponentBoilerplateWidgetModel.cs"
53 | rename ShareableComponentBoilerplateWidgetModel.cs %ToolName%WidgetModel.cs
54 |
55 | powershell -Command "(gc ShareableComponentBoilerplate.csproj) -replace 'CompanyName.ShareableComponentBoilerplate.Kentico.MVC', '%Prefix%%ToolName%%PostFix%' | Out-File -encoding ASCII ShareableComponentBoilerplate.csproj"
56 | powershell -Command "(gc ShareableComponentBoilerplate.csproj) -replace 'CompanyName.', '%Prefix%' | Out-File -encoding ASCII ShareableComponentBoilerplate.csproj"
57 | powershell -Command "(gc ShareableComponentBoilerplate.csproj) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII ShareableComponentBoilerplate.csproj"
58 | rename ShareableComponentBoilerplate.csproj %ToolName%.csproj
59 |
60 | powershell -Command "(gc ShareableComponentBoilerplate.nuspec) -replace 'CompanyName.ShareableComponentBoilerplate', '%Prefix%%ToolName%' | Out-File -encoding ASCII ShareableComponentBoilerplate.nuspec"
61 | powershell -Command "(gc ShareableComponentBoilerplate.nuspec) -replace '--TagsHere--', '%Tags%' | Out-File -encoding ASCII ShareableComponentBoilerplate.nuspec"
62 | powershell -Command "(gc ShareableComponentBoilerplate.nuspec) -replace 'http://url', '%GitHubUrl%' | Out-File -encoding ASCII ShareableComponentBoilerplate.nuspec"
63 | powershell -Command "(gc ShareableComponentBoilerplate.nuspec) -replace '--CopyrightHere--', '%AssemblyCopyright%' | Out-File -encoding ASCII ShareableComponentBoilerplate.nuspec"
64 | rename ShareableComponentBoilerplate.nuspec %ToolName%.nuspec
65 |
66 | cd Properties
67 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyTitleHere', '%AssemblyTitle%' | Out-File -encoding ASCII AssemblyInfo.cs"
68 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyDescriptionHere', '%AssemblyDescription%' | Out-File -encoding ASCII AssemblyInfo.cs"
69 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyCompanyHere', '%AssemblyCompany%' | Out-File -encoding ASCII AssemblyInfo.cs"
70 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyProductHere', '%AssemblyProduct%' | Out-File -encoding ASCII AssemblyInfo.cs"
71 | powershell -Command "(gc AssemblyInfo.cs) -replace 'AssemblyCopyrightHere', '%AssemblyCopyright%' | Out-File -encoding ASCII AssemblyInfo.cs"
72 | powershell -Command "(gc AssemblyInfo.cs) -replace '60d45549-bb62-4999-8f29-987b58b33127', [GUID]::NewGuid() | Out-File -encoding ASCII AssemblyInfo.cs"
73 | cd..
74 |
75 | cd..
76 |
77 | rename ShareableComponentBoilerplate %ToolName%
78 |
79 | powershell -Command "(gc ShareableComponentBoilerplate.sln) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII ShareableComponentBoilerplate.sln"
80 | rename ShareableComponentBoilerplate.sln %ToolName%.sln
81 |
82 | cd targets
83 | powershell -Command "(gc Kentico.EmbeddedViews.targets) -replace 'ShareableComponentBoilerplate', '%ToolName%' | Out-File -encoding ASCII Kentico.EmbeddedViews.targets"
84 | cd..
85 | pause
--------------------------------------------------------------------------------
/Targets/Kentico.EmbeddedViews.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | [assembly: Kentico.Web.Mvc.EmbeddedViewAssembly(%40"@(ViewFiles->'%(relativedir)%(filename)%(extension)','",
10 | %40"')")]
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Targets/Kentico.Resources.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
--------------------------------------------------------------------------------
/URLGenerator.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KenticoDevTrev/DynamicRouting/b352bee0ccd67a3d28e5de6dbcced522657664c4/URLGenerator.zip
--------------------------------------------------------------------------------