Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Tim Anderson 20 posts 83 karma points
    Jun 06, 2014 @ 17:12
    Tim Anderson
    0

    Your opinions please: Custom Controllers, Models and possible improvements

    In our current Umbraco 6 development I’ve been doing a lot of playing around with custom controllers to return custom models and do some route hijacking to integrate data from a set of external databases.

    My starting point of reference for this has been here on the Our Umbraco site and of course Shannon Deminick's blog for implementing custom routing for the external database stuff.

    In order to use my custom models the Views have had to inherit from Umbraco.Web.Mvc.UmbracoViewPage<T>, where T is a custom model inherited from RenderModel which has meant that @CurrentPage is not available in these views.

    This has caused a lot of problems for our designers getting to grips with Umbraco as they make use of existing samples that use @CurrentPage and they struggle with the strongly typed @Model object and converting between.

    To that end I looked at the Umbraco source code to see if there was a way to get @CurrentPage into my views with a custom model and started looking at the code for Umbraco.Web.Mvc.UmbracoTemplatePage. It was there that I noticed that this class inherits Umbraco.Web.Mvc.UmbracoViewPage<RenderModel> and inserts the @CurrentPage object in its code.

    By borrowing that code I was able to create a base template page class that reinstated the CurrentPage property into the view like so.

    namespace MyUmbraco.Mvc
    {
        public abstract class UmbracoTemplatePageBase<T> : UmbracoViewPage<T> where T : RenderModel
        {
            protected override void InitializePage()
            {
                base.InitializePage();
                //set the model to the current node if it is not set, this is generally not the case
                if (Model != null)
                {
                    ////this.ViewData.Model = Model;
                    //var backingItem = new DynamicBackingItem(Model.CurrentNode);
                    var dynamicNode = new DynamicPublishedContent(Model.Content);
                    CurrentPage = dynamicNode.AsDynamic();
                }
            }
    
            protected override void SetViewData(System.Web.Mvc.ViewDataDictionary viewData)
            {
                //Here we're going to check if the viewData's model is of IPublishedContent, this is basically just a helper for
                //syntax on the front-end so we can just pass in an IPublishedContent object to partial views that inherit from
                //UmbracoTemplatePage. Then we're going to manually contruct a RenderViewModel to pass back in to SetViewData           
                if (viewData.Model is IPublishedContent)
                {
                    //change the model to a RenderModel and auto set the culture
                    viewData.Model = new RenderModel((IPublishedContent)viewData.Model, UmbracoContext.PublishedContentRequest.Culture);
                }
    
                base.SetViewData(viewData);
            }
    
            /// <summary>
            /// Returns the a DynamicPublishedContent object
            /// </summary>
            public dynamic CurrentPage { get; private set; }
    
            private UmbracoHelper _helper;
    
            /// <summary>
            /// Gets an UmbracoHelper
            /// </summary>
            /// <remarks>
            /// This ensures that the UmbracoHelper is constructed with the content model of this view
            /// </remarks>
            public override UmbracoHelper Umbraco
            {
                get
                {
                    return _helper ?? (_helper = Model == null
                                                     ? new UmbracoHelper(UmbracoContext)
                                                     : new UmbracoHelper(UmbracoContext, Model.Content));
                }
            }
        }
    }
    

    Now that I had this base class, I could then create additional TemplatePages that used my Custom Models, which were inherited from RenderModel like so.

    namespace MyUmbraco.Mvc
    {
        public abstract class UmbracoCustomTemplatePage : UmbracoTemplatePageBase<MyCustomModel>
        { }
    }
    

    In my Controller I could then provide my custom model to the view which is inheriting from RenderModel like so

    public class HomeController : RenderMvcController
    {
        public override ActionResult Index(RenderModel model)
        {
            MyCustomModel customModel = new MyCustomModel(model.Content, model.CurrentCulture);
            //Set any custom properties on your Custom Model
            //Return the new Model
            return base.Index(locationModel);
        }
    }
    

    Now all I had to do was inherit my view from MyUmbraco.Mvc.UmbracoCustomTemplatePage and I now had access to both the dynamic node @CurrentPage property as well as the strongly typed @Model property again as per the default UmbracoTemplatePage. This meant no more unhappy designers still learning to get to grips with Umbraco as all my custom properties were available through both objects.

    Therefore if Umbraco HQ / community devs don’t see any negative issues with this and would find it helpful in their own projects, would it be possible to implement this into the Umbraco Core for version 6.2.2 onwards? (Or perhaps Version 7 and beyond if the concepts still apply?)

    UmbracoTemplatePage could then be rewritten as

    public abstract class UmbracoTemplatePage : UmbracoTemplatePageBase<RenderModel>
    { }
    

    From my own view, this should theoretically not break anything in Umbraco, that way people would only need to create a new class inheriting from UmbracoTemplatePageBase<T> to get all the properties available in the standard UmbracoTemplatePage. However I wanted to see what the community thought and see if they could see any pitfalls with my approach. I can’t see any as such, but that’s not to say there aren’t any.

    I would also like to add that all this is specific to the Umbraco 6.1.6 release, I have noticed that since Umbraco 6.2.0 has been released the code for UmbracoTemplatePage has been changed, which means I will need to rewrite my code to reflect those changes with the upgrade from 6.1.6 to 6.2.0. Additionally not having started any Umbraco 7 projects I don’t know how relevant this code would be to any Umbraco 7 and beyond project either.

    (Another reason why I would like to personally see it in the Umbraco core if possible, as I could avoid having to check and change this code for each release of Umbraco)

    Thanks for your time reading this and look forward to your views / opinions…

Please Sign in or register to post replies

Write your reply to:

Draft