Copied to clipboard

Flag this post as spam?

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


  • Lee 1130 posts 3088 karma points
    Jan 29, 2014 @ 07:45
    Lee
    0

    Problem With V7.0.2 Events

    I am trying to get two events working. Both at different times in the event cycle but but suffer from the same issue.

    Using both ContentService.Saving and ContentService.Published, but have also tried ContentService.Publishing and ContentService.Saved and get the same problems.

    Task

    • .Publishing = Just populate the umbracoUrlAlias filed with my own string url
    • .Saving = Just pre-populate two fields a date field and textstring field

    Code

    private void ContentServiceOnPublished(IPublishingStrategy sender, PublishEventArgs<IContent> publishEventArgs)
    {
        foreach (var entity in publishEventArgs.PublishedEntities)
        {
            // Only do this for the blog posts
            if (entity.HasIdentity && entity.ContentType.Alias == AppConstants.DocTypeBlogPost)
            {
                if (entity.HasProperty(AppConstants.PropUrlAlias))
                {
                    var url = library.NiceUrl(entity.Id);
                    entity.SetValue(AppConstants.PropUrlAlias, url.Replace("/blog/", "")
                                    .TrimStart("/").TrimEnd("/"));
                    var result = sender.Publish(entity, 0);
                }
            }
        }
    }
    

    And

        private void ContentServiceSaving(IContentService sender, SaveEventArgs<IContent> saveEventArgs)
    {
        foreach (var entity in saveEventArgs.SavedEntities)
        {
            if (!entity.HasIdentity)
            {
                // Only do this for new nodes
                if (entity.HasProperty(AppConstants.PropMainHeading))
                {
                    entity.SetValue(AppConstants.PropMainHeading, entity.Name);
                }
    
                if (entity.HasProperty(AppConstants.PropDate))
                {
                    entity.SetValue(AppConstants.PropDate, DateTime.Now);
                }
                var result = sender.SaveAndPublishWithStatus(entity);
            }
        }
    }
    

    Have also tried just the .Save() with the same problems.

    Problem

    I had a couple of weird issues, but for both the main problem is that in the backoffice - It looks as though it's been successful. Correct values are in all fields.

    However, if I go to use them in the front end .GetPropertyValue<string>("propertyName") etc... all the properties are empty? No values?

    Looking for any pointers...

  • Richard Soeteman 4049 posts 12922 karma points MVP 2x
    Jan 29, 2014 @ 08:04
    Richard Soeteman
    0

    What happens if you publish the page manually? Just a check to see if the values are persisted correctly.

  • Lee 1130 posts 3088 karma points
    Jan 29, 2014 @ 09:27
    Lee
    0

    So I have started to break it down. I'm going to (Hopefully) get the umbracoUrlAlias on published issue working first then go to the next one (So have commented out the .Saving).

    In answer to your question, on first creating the node from new. The value appears in back office but not in front end. If I go back, and then click the green 'Save and Publish' button. I then CAN get the value in the front end? So am completely confused.

    Note* = Also the result from the sender.Publish(entity, 0) in my event is true!

  • Casey Neehouse 1339 posts 483 karma points MVP 2x admin
    Jan 29, 2014 @ 17:45
    Casey Neehouse
    0

    Hi Lee, 

    A couple things...  

    1. Why are you publishing upon a save? This basically removes non-published state.
    2. Update the properties on publishing versus published.. then let the default publish happen.. Stops duplicate publishes and the need to no re-raise the events (loops)
    3. Be careful calling .Save, .SaveAndPublish, and .Publish from events as they can quickly become circular.  If you have a need to have that happen, be sure to 'track' what has been processed.  I ussed HttpContext.Current.Items to set tracking keys and skip redundant calls.
    4. If you have to use .Save and .SaveAndPublish and .Publish, be sure to use raiseEvents: false
  • Lee 1130 posts 3088 karma points
    Jan 29, 2014 @ 19:09
    Lee
    0

    Hey Casey - Thanks for the reply, appreciated.

    1) That was just a left over from me trying everything I could think of. I did have just Save() in there.

    2) I can't update on publishing, as entity.HasIdentity() is false in publishing when first creating (So no Id) which means I have no way to get the URL which is what I use to create a urlAlias?

    3) Could you expand on this in regards to 'I ussed HttpContext.Current.Items to set tracking keys and skip redundant calls'

    4) Thanks for this. Just trying it now and seeing if it makes a difference :)

  • Morten Christensen 596 posts 2773 karma points admin hq c-trib
    Jan 29, 2014 @ 20:40
    Morten Christensen
    2

    Let me try and elobrate on the various events before going into your question.

    The 'Saving' event occurs before an item is actually saved, so in using this event you are tapping into the process of saving a specific item that may or may not have been saved before (meaning that it might have an I'd). Any changes you make to the item will automatically be saved (as you are currently 'saving' it), so you should avoid calling save or publish on this item after you have applied your changes. This event is often used to perform actions for items that are being saved for the first time using either .HasIdentity or .IsNew to get an indication of whether or not the item has been saved before.

    You can use this event to cancel the item from being saved for whatever reason.

    The 'Saved' event occurs after an item has been saved and will thus always have an id. This event is typically used for some kind of postprocessing like relating the current item to another item or moving the item to a different location. Because the item has been 'saved' its perfectly fine to call Save or Publish for that item, but its important to remember to set raiseEvents to false when calling one of these methods from within an event to ensure you don't end up in an infinite loop.

     

    The 'Publishing' event occurs before an item is saved and published. An item is always saved before its published because the new state (and dates) needs to be updated. So this event is very similar to the 'Saving', but it does a bit more as it adds publishing. You can update your item through this event, but you should avoid calling Save or Publish because that is the process you are tapping into. This event is typically used to cancel an item from being published for various reasons, but can also be used to set a "first published date" by using the passed in ContentService to check if the item has been published before (sometimes the UpdateDate is not sufficient ;-)).

     

    The 'Published' event occurs after an item has been both saved and published. The item will always have an id and a published state set to true. This event is very similar to the 'Saved' event in that its used for postprocessing an item, and again its totally fine to call Save or Publish from within this event - just remember to set raiseEvents to false.

    One thing to keep in mind is that even though the item has been published the cache might not have been updated yet, which means the 'IPublishedContent' (incl. url) is not available yet. There is another event available, which triggers once the cache has been updated.

    EDIT: One important thing to note is that the Publish/SaveAndPublish methods does not have the option to set raiseEvents to false. The Publish methods will always raise events as thats what is used to trigger a refresh of the cache. So you have to take this into consideration, so you don't end up in an infinite loop.

    I hope this gives some insight into the events in the ContentService.

    With regards to your two code samples I think you need to rework them with the above information in mind. I'll have to get back to you with the 'cache updated' event as I can't remember it at the top of my head. But this is probably what you'll need to update the urlAlias unless you want to construct the relative URL yourself.

    As for the 'Saving' event you should remove the use of the Save method. But not sure this is really what you want... Could be that you simply need to do the same in Publishing so your SetValue applies to both "Save" and "Save and Publish" in the backoffice.

     

    - Morten

  • Mads Krohn 211 posts 504 karma points c-trib
    Jan 29, 2014 @ 21:52
    Mads Krohn
    0

    Just to add to Mortens post, the event you need to listen to when the cache is updated is content.AfterUpdateDocumentCache.
    Anything url related should definitely go in there.

    Cheers
    Mads

  • Casey Neehouse 1339 posts 483 karma points MVP 2x admin
    Jan 29, 2014 @ 22:23
    Casey Neehouse
    1

    Hi Lee:

    #3: I have a routine that keeps relateOnCopy pages in sync.  Thus, if page A is copied with Relate On Copy to page B, when A or B is updated, the related items will be updated.  Since they will be raising events themselves, then I need to keep from triggering the update on the original, and so on.

    I don't remember the exact reason why, but I had to do this as the raiseEvents: false didn't solve the problem.

            void ContentService_Published(Umbraco.Core.Publishing.IPublishingStrategy sender, Umbraco.Core.Events.PublishEventArgs<IContent> e)
            {
                var rs = ApplicationContext.Current.Services.RelationService;
                var cs = ApplicationContext.Current.Services.ContentService;
                foreach (var entity in e.PublishedEntities)
                {
                    if (!HttpContext.Current.Items.Contains(string.Format("SkipRelateOnCopyEvents-{0}", entity.Id.ToString())))
                    {
                        var relations = rs.GetByParentOrChildId(entity.Id).Where(x => x.RelationType.Alias == "relateDocumentOnCopy");
    
                        foreach (var relation in relations)
                        {
                            int relatedId = relation.ParentId == entity.Id ? relation.ChildId : relation.ParentId;
                            var relatedContent = cs.GetById(relatedId);
    
                            if (relatedContent.HasPublishedVersion())
                            {
                                HttpContext.Current.Items.Add(string.Format("SkipRelateOnCopyEvents-{0}", relatedContent.Id.ToString()), true);
                                cs.SaveAndPublish(relatedContent, userId: entity.WriterId, raiseEvents: false);
                            }
                        }
                    }
                }
            }
    
    In regard to the identity, test the identity and then save if necessary.  This will then provide your entity with the Identity.
                    if (e.Entity.Id == 0)
                        sender.Save(e.Entity, raiseEvents: false);
    
    Example on Created:
            void ContentService_Created(IContentService sender, Umbraco.Core.Events.NewEventArgs<Umbraco.Core.Models.IContent> e)
            {
                if (e.Entity.ContentType.Alias == "Website")
                {
                    // save the node to get the Id, if not already present
                    if (e.Entity.Id == 0)
                        sender.Save(e.Entity, raiseEvents: false);
    
    // Create the Home Page var homePage = sender.CreateContent("Home", e.Entity.Id, "HomePage", e.Entity.CreatorId); sender.Save(homePage); e.Entity.SetValue("umbracoInternalRedirectId", homePage.Id);
    // Create matching media folder. var ms = ApplicationContext.Current.Services.MediaService; var siteMedia = ms.CreateMedia(e.Entity.Name, -1, "Folder", e.Entity.CreatorId); ms.Save(siteMedia); e.Entity.SetValue("mediaRoot", siteMedia.Id); sender.Save(e.Entity, raiseEvents: false); } }
    There are many ways to do the different things, but the trick is to be sure and not create loops.
    As for your need to set the umbracoUrlAlias based on the published url, a rewrite rule may be better use for you with a custom NiceUrl extension that does the manipulation.  umbracoUrlAlias is not the most efficient method as it relies on 404 handlers and a xpath query that is not terribly optimal.
  • Lee 1130 posts 3088 karma points
    Jan 30, 2014 @ 07:33
    Lee
    0

    Wow. #H5YR or it should be #H5YGR (High five you guys rock!)

    Thanks for the replies, this thread is a wealth of knowledge now! Thanks for the replies, I'll have a rejig of everything.

    My main problem is trying to set values when something is first created and get them to appear in the cache. But as I say I'll rejig based on the above and see if I can get something working. Whether this is relevant or not, it seems it's a Date field I'm having most issues with.

  • Phill 115 posts 289 karma points
    Jan 30, 2014 @ 19:41
    Phill
    0

    Lee, I could be mistaken but I think at the moment it's not possible to set initial values (defaults) when an item is created. I spent a lot of time attempting this and was unsuccessful. I came across a post somewhere, I think it was Tim, that said the ability to set initial values won't be available until v7.1 (not to be confused with v7.0.1). Maybe someone with more knowlege on Events and Umbraco development can confirm if this is correct or not.

  • Morten Christensen 596 posts 2773 karma points admin hq c-trib
    Jan 30, 2014 @ 20:18
    Morten Christensen
    0

    In version 7 content is initially created different then it was in version 6. The backoffice works differently, so the Creating/Created events have been obsoleted as explained here: http://our.umbraco.org/documentation/reference/events-v6/ContentService-Events#WhathappenedtoCreatingandCreatedevents

     

    If you want to set an initial value (only on first save) the use the 'Saving' event and check whether or not the item has an id (or use the IsNew extension). But please note that these initial values won't show up when a blank content or media item is shown in the backoffice upon creation as it works differently the in version 6 (where the content item was saved before it was loaded and shown in the content editor).

    - Morten

  • Casey Neehouse 1339 posts 483 karma points MVP 2x admin
    Jan 30, 2014 @ 21:23
    Casey Neehouse
    0

    @Morten,

    Thanks for that heads-up regarding creating and created - hadn't thought about that, but we use it heavily here...  Will have to investigate how to hook into the document type to cause the data to be pre-populated.  (modifying the JS model somehow).

     

Please Sign in or register to post replies

Write your reply to:

Draft