Copied to clipboard

Flag this post as spam?

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


  • Rosa 17 posts 121 karma points
    Nov 22, 2022 @ 08:24
    Rosa
    0

    Umbraco 10 Views and Dependency Injection - best practice?

    Can someone explain to me how/why dependency injection is used in Views in Umbraco 10 (and I assume 9)?

    Why are we not able to access the UmbracoHelper by default, for example?

    I am currently doing this to get access to the Umbraco Helper:

    @inject IUmbracoHelperAccessor umbracoHelperAccessor
    @inherits UmbracoViewPage<BlockListItem>
    @{
        var row = (RoleInsightsCarousel)Model.Content;
        var settings = (RoleInsightsCarouselSettings)Model.Settings;
        if (settings != null && settings.DisableComponent) return;
    
        var roleInsightPages = new List<RoleInsightsPage>();
    
        if (umbracoHelperAccessor.TryGetUmbracoHelper(out var umbracoHelper))
        {
            if (umbracoHelper != null)
            {
                roleInsightPages = umbracoHelper.GetRoleInsights(row.RoleTypes);
            }
        }
    }
    

    GetRoleInsights() is an extension method I have created btw.

    In another partial I need the context and could only get it by injecting in the IUmbracoContextAccessor and then calling contextAccessor.TryGetUmbracoContext(out var umbracoContext)

    Is there a better way? Any explaination for how this works would be much appreciated!

  • Jamie Attwood 207 posts 501 karma points c-trib
    Nov 22, 2022 @ 14:41
    Jamie Attwood
    0

    You should not have to use DI in your views to get at UmbracoHelper.

    As long as your page inherits from Umbraco.Cms.Web.Common.Views.UmbracoViewPage you should be able to access it directly by using @Umbraco.

    I am not sure if your entire view header is shown in your code example, but if you are not able to access @Umbraco methods, you can try something like (Umbraco 10):

    @inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<Umbraco.Cms.Core.Models.Blocks.BlockListModel>
    
  • Jamie Attwood 207 posts 501 karma points c-trib
    Nov 22, 2022 @ 14:49
    Jamie Attwood
    0

    Really though, ideally you should be creating a custom controller and view model for each of your views (either based on document type or template name). This was you can simplify or eliminate business logic from your views.

    Have you looked into Umbraco route hijacking? Check out: https://our.umbraco.com/documentation/reference/routing/custom-controllers/

    And make sure you check out "Returning a view with a custom model" that outlines a way you can create a view model that inherits from your modelsbuilder model that will allow you to add view specific properties that may not be available in your modelsbuilder models.

  • Damien Holley 180 posts 541 karma points
    May 08, 2023 @ 06:41
    Damien Holley
    0

    The issue with the above recommendation is that you then introduce multiple points of failure. You now have the view, the controller and the new viewmodel any of which may have an issue in them. Not to mention you are now overriding the routing again, and adding to memory usage by introducing more objects into RAM. I would only do this if the view is very complex.

    Business logic in the view can be handled by extending the partial class of the page model, hitting a custom service or any number of other ways. This also means it can be cached (the controller methods are never cached).

    If the logic is purely for the view, then pop it in the partial.

  • Jamie Attwood 207 posts 501 karma points c-trib
    May 08, 2023 @ 15:05
    Jamie Attwood
    0

    Hi Damien, maybe I am missing something - I'm not sure exactly what you are suggesting here by extending the partial class of the page model - no business logic should exist in the model.

    Logic in the views (while it's very possible) is an MVC antipattern. A popular design pattern with Umbraco involves injecting some sort of custom data retrieval service in the view via DI; however, ideally you would override the Index controller, call your service from there (if desired), or execute custom logic in the controller to manipulate the existing modelsbuilder model or enhance the Umbraco generated models with your own view model that inherits from the generated model exposing not only the models builder model to the view but also custom properties from your own view model.

    This is more work to be sure, but if anything, by putting BL in the views you are setting yourself up for potential runtime errors. The MVC approach at least gives you better separation of concerns, compile time errors and the ability to unit test your code. Any additional memory should be negligible and certainly worth the tradeoff.

    Controllers are fully cacheable using the OutputCache Attribute. Something like:

         public class MyPageController : RenderController
            {
                [OutputCache(Duration = 10)] // cache seconds
                public override IActionResult Index()
                {
                // do stuff
                myCustomProperty = "Test";
                    return View("MyPageView", new MyPageViewModel(CurrentPage!, _publishedValueFallback)
                    {
                   MyCustomProperty = myCustomProperty //assumes you have a custom viewmodel called "MyPageViewModel" with a MyCustomProperty prop.
                    });
                }
            }
    
Please Sign in or register to post replies

Write your reply to:

Draft