Skip to content

Repository files navigation

Renderings Read Me

Build status

PackageVersion
RenderingsNuGet version
Renderings.UmbracoCmsNuGet version

Requires DotNetStarter to run.

The goal of this package is to provide developers a framework for creating view models that support DI (dependency injection) using DotNetStarter. This package will not create document types from code, it will rather wrap IPublishedContent in a POCO for strongly typed view models to use in razor files.

The POCO view models need the following attribute:

[RenderingDocumentAlias("aliasString")]

These models will then get discovered by the startup process and registered to the DotNetStarter container.

Umbraco Getting started

To use this package you need to install the following NuGet packages:

  • Renderings.UmbracoCms
  • DotNetStarter.Extensions.WebApi
  • DotNetStarter.Extensions.Mvc
  • DotNetStarter.DryIoc or DotnetStarter.StructureMap (either one is fine)
    • NOTE The container package dependencies may need to be updated to resolve issues.

Create a custom global.asax class inheriting from Umbraco.Web.UmbracoApplication and in the constructor execute DotNetStarter.ApplicationContext.Startup.

usingDotNetStarter.Abstractions;usingDotNetStarter.Configure;usingSystem.Configuration;namespaceExampleNamespace{publicclassApplication:Umbraco.Web.UmbracoApplication{privatestaticStartupBuilder_startupBuilder;// to avoid trying to start twice/// <summary>/// Executs DotNetStarter.ApplicationContext.Startup, this class is used in the global.asax inherits/// </summary>publicApplication(){if(_startupBuilder!=null)return;_startupBuilder=StartupBuilder.Create().UseEnvironment(newDotNetStarter.StartupEnvironmentWeb(environmentName:ConfigurationManager.AppSettings["UmbracoEnv"])).ConfigureAssemblies(assemblies =>{assemblies.WithDiscoverableAssemblies().WithAssemblyFromType<Umbraco.Web.UmbracoApplication>()// Scan for backoffice controllers// add additional umbraco plugins, which inject controllers//.WithAssemblyFromType<Umbraco.Forms.Web.Controllers.UmbracoFormsController>()//.WithAssemblyFromType<Diplo.TraceLogViewer.Controllers.TraceLogTreeController>().WithAssemblyFromType<Application>();//types in this project}).OverrideDefaults(defaults =>{defaults// note: Only one locator is needed, and each of these implementations may also be passed an already configured DI container instance//.UseLocatorRegistryFactory(new DotNetStarter.Locators.DryIocLocatorFactory())//.UseLocatorRegistryFactory(new DotNetStarter.Locators.StructureMapFactory()).UseLocatorRegistryFactory(newDotNetStarter.Locators.LightInjectLocatorRegistryFactory()).UseLogger(newDotNetStarter.StringLogger(LogLevel.Error,1024000));// clears log after 1MB}).Build();_startupBuilder.Run();}}}

Update the global.asax file's Inherits to use the full namespace of our custom class as noted below:

<%@ ApplicationInherits="Full.Namespace.Of.Class.Application"Language="C#"%>

Then create a custom default controller to create the rendering models

publicclassCustomApplicationBaseController:RenderMvcController{privatereadonlyIRenderingCreatorScoped_RenderingCreator;publicCustomApplicationBaseController(){}publicCustomApplicationBaseController(IRenderingCreatorScopedrenderingCreator){_RenderingCreator=renderingCreator;}publicoverrideActionResultIndex(RenderModelmodel){varrendering=BuildRendering(model.Content,model.CurrentCulture);if(rendering==null){returnCurrentTemplate(model);// Fallback to default behaviour}if(rendering.IsFullPage==false){returnnewHttpNotFoundResult();// don't allow non full page models to return}returnCurrentTemplate(rendering);}privateIUmbracoRenderingBuildRendering(IPublishedContentcontent,CultureInfocultureInfo){varcreator=_RenderingCreator.GetCreator<IPublishedContent>(content.DocumentTypeAlias);varreturnModel=creator.Invoke(content)asIUmbracoRendering;if(returnModelisIUmbracoRenderingWithCulturecultureModel){cultureModel.CurrentCulture=cultureInfo;}returnreturnModel;}}

Finally hijack the default MVC controller for Umbraco page content

/// <summary>/// This class registers the base application controller and setups up error page routing/// </summary>publicclassApplicationSetupMvc:ApplicationEventHandler{protectedoverridevoidApplicationStarting(UmbracoApplicationBaseumbracoApplication,ApplicationContextapplicationContext){base.ApplicationStarting(umbracoApplication,applicationContext);// note: this will set all routes to be hijacked by this base controllerUmbraco.Web.Mvc.DefaultRenderMvcControllerResolver.Current.SetDefaultControllerType(typeof(CustomApplicationBaseController));}}

Also note, razor views will need to use one of the follow instead of @inherits Umbraco.Web.Mvc.TemplatePage

@modelRenderingsExample.Models.ViewModels.Home // where class implements IUmbracoRendering

or

@inheritsUmbraco.Web.Mvc.UmbracoViewPage<T>// where T is class implementing IUmbracoRendering

Rendering Example

Renderings can be as simple or as complex as needed, below is a simple document type used to build hero slides:

[RenderingDocumentAlias("heroSlide")]publicclassHeroSlide:IUmbracoRendering{publicHeroSlide(IPublishedContentcontent){Content=content;}///<summary>/// Mapped property to given IPublishedContent CMS content///</summary>[RenderingPropertyAlias("title")]publicstringTitle{get{returnContent.GetPropertyValue<string>("title");}}[RenderingPropertyAlias("description")]publicstringDescription{get{returnContent.GetPropertyValue<string>("description");}}[RenderingPropertyAlias("link")]publicRelatedLinkLink{get{returnContent.GetPropertyValue<RelatedLinks>("link")?.FirstOrDefault()??newRelatedLink(){Caption="Link not set",Link="#notset"};}}[RenderingPropertyAlias("image")]publicIPublishedContentImage{get{returnContent.GetPropertyValue<IPublishedContent>("image");}}/// <summary>/// Instructs the default controller to throw a HTTP 404 message/// </summary>publicboolIsFullPage=>false;publicIPublishedContentContent{get;}/// <summary>/// Part of the IViewModel interface, which is a simplified template engine,/// allowing view models to decide how to render in partial views./// </summary>/// <param name="renderTag"></param>/// <returns></returns>publicstringGetPartialView(stringrenderTag=null){return"~/Views/Partials/HeroSlide.cshtml";}}

View models can then be referenced using the built-in related links property as shown below on an example homepage document type:

[RenderingDocumentAlias("home")]publicclassHomeViewModel:IUmbracoRendering{publicHomeViewModel(IPublishedContentcontent,IRelatedLinksToRenderingConverterScopedrelatedLinksConverterScoped){Content=content;_RelatedLinksConverter=relatedLinksConverterScoped;}publicboolIsFullPage=>true;publicIPublishedContentContent{get;}privatereadonlyIRelatedLinksToRenderingConverterScoped_RelatedLinksConverter;privateIEnumerable<HeroSlide>_HeroSlides;/// <summary>/// Converts a RelatedLinks property to HeroSlide sequence./// </summary>[RenderingPropertyAlias("heroSlider")]publicIEnumerable<HeroSlide>HeroSlides{get{if(_HeroSlides==null){_HeroSlides=_RelatedLinksConverter.ConvertLinks<HeroSlide>(Content.GetPropertyValue<RelatedLinks>("heroSlider"),newType[]{typeof(HeroSlide)});}return_HeroSlides;}}/// <summary>/// We don't want to reuse homepage, so return "Empty" which corresponds to /Views/Partials/Empty.cshtml/// </summary>/// <param name="renderTag"></param>/// <returns></returns>publicstringGetPartialView(stringrenderTag=null){return"Empty";}}

Using IRenderingAliasResolver to reduce magic strings

The sole purpose of the IRenderingAliasResolver is eliminate retyping document and property aliases throughout the code base. It can return a view model type from a string alias (hint: use IPublishedContent for this) or return a string alias for a given view model type.

For example getting a rendering type from alias:

// where _RenderingliasResolver is injected IRenderingAliasResolverTyperenderingType=_RenderingliasResolver.ResolveAlias(content.DocumentTypeAlias);

Or from type to string alias (useful for searching, filtering, etc)

// returns 'heroSlide' from previous view model examplestringalias=_RenderingliasResolver.ResolveType(typeof(HeroSlide));

Or get a property alias from a view model

// returns 'title' from previous HeroSlide view model examplestringpropertyAlias=_RenderingliasResolver.ResolvePropertyAlias<HeroSlide>(slide =>slide.Title);

About

Framework for create injected models for rendering content

Resources

Stars

1 star

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages