Copied to clipboard

Flag this post as spam?

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


  • Martin Rud 261 posts 1022 karma points c-trib
    May 06, 2024 @ 10:04
    Martin Rud
    0

    How to get content from block list elements before node save and insert/save to a node property?

    How to get content from block list elements before node save and insert/save to a node property?

    On my page nodes I have a property 'ribbons' of type Umbraco.BlockList. I also have a text property 'browserTitle'.

    When an editor saves the document I want to traverse the ribbons and look for the first ribbon element where property 'healine' is not empty and put that value into the node's 'browserTitleResult' property just before the node is saved.

    (use case is that if 'browserTitle' is empty I can use 'browserTitleResult' for page title instead)

    I have tried using examples from https://docs.umbraco.com/umbraco-cms/fundamentals/code/umbraco-services#access-in-a-custom-class-via-dependency-injection but I cant figure it out.

    Umbraco 13.3.0

  • Sergey 6 posts 77 karma points
    May 06, 2024 @ 13:11
    Sergey
    0

    Hi, Martin!

    I believe that you have to implement custom ContentSaving notification handler. It will be triggered before content saved and you can modify properties of your page in a way you want (parse existing and fill-in empty).

    Documentation: https://docs.umbraco.com/umbraco-cms/reference/notifications/contentservice-notifications

  • Martin Rud 261 posts 1022 karma points c-trib
    May 06, 2024 @ 13:26
    Martin Rud
    0

    I have made this PoC now:

    using Umbraco.Cms.Core.Events;
    using Umbraco.Cms.Core.Notifications;
    
    namespace MartinRud.ContentService;
    public class SeoAutomations : INotificationHandler<ContentPublishingNotification>
    {
        public void Handle(ContentPublishingNotification notification)
        {
            foreach (var node in notification.PublishedEntities)
            {
    
                if (node.ContentType.Alias.Contains("page"))
                {
                    Console.WriteLine("Test for node " + node.Name);
                    node.SetValue("browserTitleResult", "Testing...");
                }    
    
            }
        }
    }
    

    The Console.WriteLine() shows up fine in the terminal, but in Umbraco backend I get:

    > Received an error from the server An error occurred Variation
    > "<null>,<null>" is not supported by the property type. Exception
    > Details System.NotSupportedException, System.Private.CoreLib,
    > Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e:
    > Variation "<null>,<null>" is not supported by the property type.
    > Stacktrace at Umbraco.Cms.Core.Models.Property.SetValue(Object value,
    > String culture, String segment) at
    > Umbraco.Cms.Core.Models.ContentBase.SetValue(String propertyTypeAlias,
    > Object value, String culture, String segment) at
    > MartinRud.ContentService.SeoAutomations.Handle(ContentPublishingNotification
    > notification) in
    > C:\MartinRud-CloudRoot\Firma\Code\Dev.Baseline\Umbraco.Baseline\Umbraco.Baseline.Cms\App_MartinRud\MartinRud.ContentService
    > .cs:line 16 at
    > Umbraco.Cms.Core.Events.INotificationHandler`1.Handle(IEnumerable`1
    > notifications) at
    > Umbraco.Cms.Core.Events.NotificationHandlerWrapperImpl`1.<>c__DisplayClass0_0`2.<Handle>b__2(IEnumerable`1
    > handlerNotifications) at
    > Umbraco.Cms.Core.Events.EventAggregator.PublishCore[TNotification](IEnumerable`1
    > allHandlers, IEnumerable`1 notifications) at
    > Umbraco.Cms.Core.Events.NotificationHandlerWrapperImpl`1.Handle[TNotification,TNotificationHandler](IEnumerable`1
    > notifications, ServiceFactory serviceFactory, Action`2 publish) at
    > Umbraco.Cms.Core.Events.EventAggregator.PublishNotifications[TNotification,TNotificationHandler](IEnumerable`1
    > notifications) at
    > Umbraco.Cms.Core.Events.EventAggregator.Publish[TNotification,TNotificationHandler](IEnumerable`1
    > notifications) at
    > Umbraco.Cms.Core.Events.EventAggregator.Publish[TNotification](TNotification
    > notification) at
    > Umbraco.Cms.Core.Events.ScopedNotificationPublisher`1.PublishCancelable(ICancelableNotification
    > notification) at
    > Umbraco.Cms.Core.Services.ContentService.StrategyCanPublish(ICoreScope
    > scope, IContent content, Boolean checkPath, IReadOnlyList`1
    > culturesPublishing, IReadOnlyCollection`1 culturesUnpublishing,
    > EventMessages evtMsgs, IReadOnlyCollection`1 allLangs, IDictionary`2
    > notificationState) at
    > Umbraco.Cms.Core.Services.ContentService.CommitDocumentChangesInternal(ICoreScope
    > scope, IContent content, EventMessages eventMessages,
    > IReadOnlyCollection`1 allLangs, IDictionary`2 notificationState, Int32
    > userId, Boolean branchOne, Boolean branchRoot) at
    > Umbraco.Cms.Core.Services.ContentService.SaveAndPublish(IContent
    > content, String[] cultures, Int32 userId) at
    > Umbraco.Cms.Web.BackOffice.Controllers.ContentController.PublishInternal(ContentItemSave
    > contentItem, String defaultCulture, String cultureForInvariantErrors,
    > Boolean& wasCancelled, String[]& successfulCultures) at
    > Umbraco.Cms.Web.BackOffice.Controllers.ContentController.PostSaveInternal[TVariant](ContentItemSave
    > contentItem, Func`3 saveMethod, Func`2 mapToDisplay) at
    > Umbraco.Cms.Web.BackOffice.Controllers.ContentController.PostSave(ContentItemSave
    > contentItem) at lambda_method976(Closure, Object) at
    > Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext
    > actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor
    > executor, Object controller, Object[] arguments) at
    > Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker
    > invoker, ValueTask`1 actionResultValueTask) at
    > Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker
    > invoker, Task lastTask, State next, Scope scope, Object state, Boolean
    > isCompleted) at
    > Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed
    > context) at
    > Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State&
    > next, Scope& scope, Object& state, Boolean& isCompleted) at
    > Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
    > --- End of stack trace from previous location --- at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker
    > invoker, Task lastTask, State next, Scope scope, Object state, Boolean
    > isCompleted)
    
  • Sergey 6 posts 77 karma points
    May 06, 2024 @ 13:44
    Sergey
    0

    Martin,

    You used ContentPublishingNotification so, your handler will be triggered right before content will be published. I believe you want to make a change on content saving:

    public class SavingAutomationAction : INotificationHandler<ContentSavingNotification>
    {
        private readonly IContentService _contentService;
        private readonly ISqlContext _sqlContext;
    
        public SavingAutomationAction (IContentService contentService, ISqlContext sqlContext)
        {
            _contentService = contentService;
            _sqlContext = sqlContext;
        }
    
        public void Handle(ContentSavingNotification notification)
        {
            foreach (var node in notification.SavedEntities)
            {
                if (node.HasIdentity is false)  // When entity is newly created
                {
                    foreach (var property in node.Properties)   // Iterate all props
                    {
                        var currentProp = node.GetValue(property.Alias);
                        node.SetValue(property.Alias, currentProp  + "TEST");
                    }
                }
            }
        }
    }
    
  • Martin Rud 261 posts 1022 karma points c-trib
    May 06, 2024 @ 14:17
    Martin Rud
    0

    I have tried this:

    public class SavingAutomationAction : INotificationHandler

    public SavingAutomationAction (IContentService contentService, ISqlContext sqlContext)
    {
        _contentService = contentService;
        _sqlContext = sqlContext;
    }
    
    public void Handle(ContentSavingNotification notification)
    {   
        Console.WriteLine("SavingAutomationAction");
        foreach (var node in notification.SavedEntities)
        {
            foreach (var property in node.Properties)   // Iterate all props
            {
                var currentProp = node.GetValue(property.Alias);
                Console.WriteLine("Property: " + property.Alias);
                Console.WriteLine("Value: " + currentProp);
                //node.SetValue(property.Alias, currentProp?.ToString() + "TEST");
            }
        }
    }
    

    }

    In the terminal I get empty values only (even though some of them are NOT empty):

    SavingAutomationAction
    Property: headline
    Value:
    Property: pageAbstract
    Value:
    Property: ribbons
    Value:
    Property: text
    Value:
    Property: image
    Value:
    Property: browserTitle
    

    If I uncomment this line:

    //node.SetValue(property.Alias, currentProp?.ToString() + "TEST");
    

    I get:

    Received an error from the server
    An error occurred
    Variation "<null>,<null>" is not supported by the property type.
    
    Exception Details
    System.NotSupportedException, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e: Variation "<null>,<null>" is not supported by the property type.
    Stacktrace
    at Umbraco.Cms.Core.Models.Property.SetValue(Object value, String culture, String segment)
       at Umbraco.Cms.Core.Models.ContentBase.SetValue(String propertyTypeAlias, Object value, String culture, String segment)
       at MartinRud.ContentService.SavingAutomationAction.Handle(ContentSavingNotification notification) in C:\MartinRud-CloudRoot\Firma\Code\Dev.Baseline\Umbraco.Baseline\Umbraco.Baseline.Cms\App_MartinRud\MartinRud.ContentService .cs:line 29
       at Umbraco.Cms.Core.Events.INotificationHandler`1.Handle(IEnumerable`1 notifications)
       at Umbraco.Cms.Core.Events.NotificationHandlerWrapperImpl`1.<>c__DisplayClass0_0`2.<Handle>b__2(IEnumerable`1 handlerNotifications)
       at Umbraco.Cms.Core.Events.EventAggregator.PublishCore[TNotification](IEnumerable`1 allHandlers, IEnumerable`1 notifications)
       at Umbraco.Cms.Core.Events.NotificationHandlerWrapperImpl`1.Handle[TNotification,TNotificationHandler](IEnumerable`1 notifications, ServiceFactory serviceFactory, Action`2 publish)
       at Umbraco.Cms.Core.Events.EventAggregator.PublishNotifications[TNotification,TNotificationHandler](IEnumerable`1 notifications)
       at Umbraco.Cms.Core.Events.EventAggregator.Publish[TNotification,TNotificationHandler](IEnumerable`1 notifications)
       at Umbraco.Cms.Core.Events.EventAggregator.Publish[TNotification](TNotification notification)
       at Umbraco.Cms.Core.Events.ScopedNotificationPublisher`1.PublishCancelable(ICancelableNotification notification)
       at Umbraco.Cms.Core.Services.ContentService.SaveAndPublish(IContent content, String[] cultures, Int32 userId)
       at Umbraco.Cms.Web.BackOffice.Controllers.ContentController.PublishInternal(ContentItemSave contentItem, String defaultCulture, String cultureForInvariantErrors, Boolean& wasCancelled, String[]& successfulCultures)
       at Umbraco.Cms.Web.BackOffice.Controllers.ContentController.PostSaveInternal[TVariant](ContentItemSave contentItem, Func`3 saveMethod, Func`2 mapToDisplay)
       at Umbraco.Cms.Web.BackOffice.Controllers.ContentController.PostSave(ContentItemSave contentItem)
       at lambda_method53(Closure, Object)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
       at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
    --- End of stack trace from previous location ---
       at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
    
  • Sergey 6 posts 77 karma points
    May 06, 2024 @ 14:46
    Sergey
    0

    Not sure why you're getting empty values - just tested on U13 site - works like a charm. Maybe try to set breakpoint at the beginning of Handle method and debug.

    P.S> assuming that you added following line to umbraco builder somewhere between .AddComposers() and .Build() at Program.cs (or Startup.cs):

    .AddNotificationHandler<ContentSavingNotification, SavingAutomationAction>()
    
Please Sign in or register to post replies

Write your reply to:

Draft