From 49603a51513c1d466b7fcb05a032b88737fcf32d Mon Sep 17 00:00:00 2001 From: David Brendel Date: Tue, 1 Aug 2017 10:47:48 +0200 Subject: [PATCH] Added dynamic route handling Added tags property to blog posts Added dynamic url handling with UmbracoVirtualNodeByIdRouteHandler to show all tags and all content related to a tag --- .../App_Data/Models/all.dll.path | 2 +- .../App_Data/Models/all.generated.cs | 11 ++++- .../App_Data/Models/models.generated.cs | 11 ++++- .../App_Data/Models/models.hash | 2 +- src/UmbracoUrlHandling/App_Data/Umbraco.sdf | Bin 2228224 -> 2359296 bytes .../BlogPostRepositoryController.cs | 42 ++++++++++++++++++ .../Models/CategoryContentViewModel.cs | 37 +++++++++++++++ .../Models/TagsOverviewViewModel.cs | 29 ++++++++++++ .../BlogRepositoryRouteHandler.cs | 19 ++++++++ src/UmbracoUrlHandling/Startup.cs | 34 +++++++++++++- .../UmbracoUrlHandling.csproj | 6 +++ .../Views/RelatedContentForCategory.cshtml | 14 ++++++ .../Views/TagsOverview.cshtml | 13 ++++++ 13 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 src/UmbracoUrlHandling/Controller/BlogPostRepositoryController.cs create mode 100644 src/UmbracoUrlHandling/Models/CategoryContentViewModel.cs create mode 100644 src/UmbracoUrlHandling/Models/TagsOverviewViewModel.cs create mode 100644 src/UmbracoUrlHandling/RouteHandler/BlogRepositoryRouteHandler.cs create mode 100644 src/UmbracoUrlHandling/Views/RelatedContentForCategory.cshtml create mode 100644 src/UmbracoUrlHandling/Views/TagsOverview.cshtml diff --git a/src/UmbracoUrlHandling/App_Data/Models/all.dll.path b/src/UmbracoUrlHandling/App_Data/Models/all.dll.path index 68bc0fd..8ced112 100644 --- a/src/UmbracoUrlHandling/App_Data/Models/all.dll.path +++ b/src/UmbracoUrlHandling/App_Data/Models/all.dll.path @@ -1 +1 @@ -C:\Users\mantu\AppData\Local\Temp\Temporary ASP.NET Files\vs\027ab051\822a0174\App_Web_all.generated.cs.8f9494c4.oibqrept.dll \ No newline at end of file +C:\Users\brendeld\AppData\Local\Temp\Temporary ASP.NET Files\vs\db0e3ea5\41b4334d\App_Web_all.generated.cs.8f9494c4.feq1txiv.dll \ No newline at end of file diff --git a/src/UmbracoUrlHandling/App_Data/Models/all.generated.cs b/src/UmbracoUrlHandling/App_Data/Models/all.generated.cs index 115b903..460dc58 100644 --- a/src/UmbracoUrlHandling/App_Data/Models/all.generated.cs +++ b/src/UmbracoUrlHandling/App_Data/Models/all.generated.cs @@ -8,7 +8,7 @@ using Umbraco.ModelsBuilder; using Umbraco.ModelsBuilder.Umbraco; [assembly: PureLiveAssembly] -[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = "e4d2aa0bdb7a3315")] +[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = "4ad86b1aa0722510")] [assembly:System.Reflection.AssemblyVersion("0.0.0.1")] @@ -83,6 +83,15 @@ public string Introduction get { return this.GetPropertyValue("introduction"); } } + /// + /// Tags: Tags related to this blog post + /// + [ImplementPropertyType("tags")] + public IEnumerable Tags + { + get { return this.GetPropertyValue>("tags"); } + } + /// /// Url Name: The url name which should be used /// diff --git a/src/UmbracoUrlHandling/App_Data/Models/models.generated.cs b/src/UmbracoUrlHandling/App_Data/Models/models.generated.cs index 29a3196..1bb92fb 100644 --- a/src/UmbracoUrlHandling/App_Data/Models/models.generated.cs +++ b/src/UmbracoUrlHandling/App_Data/Models/models.generated.cs @@ -19,7 +19,7 @@ using Umbraco.ModelsBuilder.Umbraco; [assembly: PureLiveAssembly] -[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = "e4d2aa0bdb7a3315")] +[assembly:ModelsBuilderAssembly(PureLive = true, SourceHash = "4ad86b1aa0722510")] [assembly:System.Reflection.AssemblyVersion("0.0.0.2")] namespace Umbraco.Web.PublishedContentModels @@ -67,6 +67,15 @@ public string Introduction get { return this.GetPropertyValue("introduction"); } } + /// + /// Tags: Tags related to this blog post + /// + [ImplementPropertyType("tags")] + public IEnumerable Tags + { + get { return this.GetPropertyValue>("tags"); } + } + /// /// Url Name: The url name which should be used /// diff --git a/src/UmbracoUrlHandling/App_Data/Models/models.hash b/src/UmbracoUrlHandling/App_Data/Models/models.hash index 4061f08..c9c743b 100644 --- a/src/UmbracoUrlHandling/App_Data/Models/models.hash +++ b/src/UmbracoUrlHandling/App_Data/Models/models.hash @@ -1 +1 @@ -e4d2aa0bdb7a3315 \ No newline at end of file +4ad86b1aa0722510 \ No newline at end of file diff --git a/src/UmbracoUrlHandling/App_Data/Umbraco.sdf b/src/UmbracoUrlHandling/App_Data/Umbraco.sdf index 01d94a4c8c306efa520858cdeba47769da21d285..91bec567ac52d7aa5fe00b5c502191fd1f8f467c 100644 GIT binary patch delta 17867 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 GhW;P5G#qpQ delta 8392 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 + /// Route hijacking using controller to handle custom model building for templates + /// + /// + public class BlogPostRepositoryController : RenderMvcController + { + /// + /// Method to show tags overview template. + /// + /// The model. + /// + public ActionResult Categories(RenderModel model) + { + var tags = Services.TagService.GetAllContentTags().ToList(); + var viewModel = new TagsOverviewViewModel(model.Content) {Tags = tags}; + return View("TagsOverview", viewModel); + } + + /// + /// Shows all content that was tagged with a specific category. + /// + /// The model. + /// The category. + /// + public ActionResult Category(RenderModel model, string category) + { + var tagsService = Services.TagService; + var relatedContentTaggedEntities = tagsService.GetTaggedContentByTag(category); + var relatedContent = Umbraco.TypedContent(relatedContentTaggedEntities.Select(x => x.EntityId)); + var viewModel = new CategoryContentViewModel(model.Content) { Category = category, RelatedContentForCategory = relatedContent}; + return View("RelatedContentForCategory", viewModel); + } + } +} \ No newline at end of file diff --git a/src/UmbracoUrlHandling/Models/CategoryContentViewModel.cs b/src/UmbracoUrlHandling/Models/CategoryContentViewModel.cs new file mode 100644 index 0000000..ae1d02a --- /dev/null +++ b/src/UmbracoUrlHandling/Models/CategoryContentViewModel.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; + +namespace UmbracoUrlHandling.Models +{ + /// + /// ViewModel to render all content for aspecific category + /// + /// + public class CategoryContentViewModel : PublishedContentWrapped + { + /// + /// Initializes a new instance of the class. + /// + /// The content to wrap and extend. + public CategoryContentViewModel(IPublishedContent content) : base(content) + { + } + + /// + /// Gets or sets the category. + /// + /// + /// The category. + /// + public string Category { get; set; } + + /// + /// Gets or sets the related content for category. + /// + /// + /// The related content for category. + /// + public IEnumerable RelatedContentForCategory { get; set; } + } +} \ No newline at end of file diff --git a/src/UmbracoUrlHandling/Models/TagsOverviewViewModel.cs b/src/UmbracoUrlHandling/Models/TagsOverviewViewModel.cs new file mode 100644 index 0000000..05ebf0b --- /dev/null +++ b/src/UmbracoUrlHandling/Models/TagsOverviewViewModel.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using Umbraco.Core.Models; +using Umbraco.Core.Models.PublishedContent; + +namespace UmbracoUrlHandling.Models +{ + /// + /// View model for tags overview of blog posts + /// + /// + public class TagsOverviewViewModel : PublishedContentWrapped + { + /// + /// Initializes a new instance of the class. + /// + /// The content to wrap and extend. + public TagsOverviewViewModel(IPublishedContent content) : base(content) + { + } + + /// + /// Gets or sets the tags. + /// + /// + /// The tags. + /// + public IEnumerable Tags { get; set; } + } +} \ No newline at end of file diff --git a/src/UmbracoUrlHandling/RouteHandler/BlogRepositoryRouteHandler.cs b/src/UmbracoUrlHandling/RouteHandler/BlogRepositoryRouteHandler.cs new file mode 100644 index 0000000..49d95db --- /dev/null +++ b/src/UmbracoUrlHandling/RouteHandler/BlogRepositoryRouteHandler.cs @@ -0,0 +1,19 @@ +using Umbraco.Web.Mvc; + +namespace UmbracoUrlHandling.RouteHandler +{ + /// + /// BlogPostRepositoryrouteHandler to handle routes to BlogPostRepository + /// + /// + public class BlogRepositoryRouteHandler : UmbracoVirtualNodeByIdRouteHandler + { + /// + /// Initializes a new instance of the class. + /// + /// The real node identifier. + public BlogRepositoryRouteHandler(int realNodeId) : base(realNodeId) + { + } + } +} \ No newline at end of file diff --git a/src/UmbracoUrlHandling/Startup.cs b/src/UmbracoUrlHandling/Startup.cs index 5eb6997..2a552ec 100644 --- a/src/UmbracoUrlHandling/Startup.cs +++ b/src/UmbracoUrlHandling/Startup.cs @@ -1,4 +1,5 @@ -using System.Web; +using System.Linq; +using System.Web; using System.Web.Mvc; using System.Web.Routing; using Umbraco.Core; @@ -27,6 +28,7 @@ public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, App ContentFinderResolver.Current.InsertTypeBefore(); + //Make a route based on a node Id RouteTable.Routes.MapUmbracoRoute( "ProductRoute", "Products/{sku}", @@ -43,6 +45,36 @@ public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, App public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext) { ContentService.Published += (sender, args) => HttpContext.Current.Cache.Remove("CachedBlogPostNodes"); + + //Dynamic routes based on node type and node urls + var blogRepositoryNodes = UmbracoContext.Current.ContentCache.GetByXPath("//BlogPostRepository").ToArray(); + + foreach (var repository in blogRepositoryNodes) + { + var uri = repository.Url().TrimStart("/"); + var hash = uri.GetHashCode(); + + RouteTable.Routes.MapUmbracoRoute( + $"blog_repository_categories_{hash}", + $"{uri.EnsureEndsWith('/')}categories/", + new + { + controller = "BlogPostRepository", + action = "Categories" + }, + new BlogRepositoryRouteHandler(repository.Id)); + + RouteTable.Routes.MapUmbracoRoute( + $"blog_repository_category_{hash}", + $"{uri.EnsureEndsWith('/')}category/{{category}}", + new + { + controller = "BlogPostRepository", + action = "Category", + category = UrlParameter.Optional + }, + new BlogRepositoryRouteHandler(repository.Id)); + } } } } \ No newline at end of file diff --git a/src/UmbracoUrlHandling/UmbracoUrlHandling.csproj b/src/UmbracoUrlHandling/UmbracoUrlHandling.csproj index 811722a..ce23b8a 100644 --- a/src/UmbracoUrlHandling/UmbracoUrlHandling.csproj +++ b/src/UmbracoUrlHandling/UmbracoUrlHandling.csproj @@ -294,6 +294,8 @@ + + Web.config @@ -331,7 +333,11 @@ + + + + diff --git a/src/UmbracoUrlHandling/Views/RelatedContentForCategory.cshtml b/src/UmbracoUrlHandling/Views/RelatedContentForCategory.cshtml new file mode 100644 index 0000000..4f77a71 --- /dev/null +++ b/src/UmbracoUrlHandling/Views/RelatedContentForCategory.cshtml @@ -0,0 +1,14 @@ +@inherits UmbracoViewPage +@{ + Layout = "Master.cshtml"; +} + +

Pages related to category "@Model.Category":

+
    + @foreach (var content in Model.RelatedContentForCategory) + { +
  • + @content.Name +
  • + } +
\ No newline at end of file diff --git a/src/UmbracoUrlHandling/Views/TagsOverview.cshtml b/src/UmbracoUrlHandling/Views/TagsOverview.cshtml new file mode 100644 index 0000000..e81645d --- /dev/null +++ b/src/UmbracoUrlHandling/Views/TagsOverview.cshtml @@ -0,0 +1,13 @@ +@inherits UmbracoViewPage +@{ + Layout = "Master.cshtml"; +} + +

All tags

+ +
    + @foreach (var tag in Model.Tags) + { +
  • @tag.Text
  • + } +
\ No newline at end of file