U4-1372 - Values not available in before save event - UmbracoCms.6.0.0.build.94

Created by Jeroen Breuer 29 Dec 2012, 21:23:16 Updated by Sebastiaan Janssen 28 Jan 2013, 14:15:33

Relates to: U4-1564

Relates to: U4-1368

Relates to: U4-1371

In v4 the following code worked in a before save event: string file = new Media(mediaId).getProperty("umbracoFile").Value.ToString(); In v6 this returns an empty string. Probably because the value won't be available until everything is saved in the database. In the after save event it is available, but this also seems to be a breaking change.

Comments

Jeroen Breuer 29 Dec 2012, 21:55:47

In DAMP I need to update some properties using events. I did this in the before save event and now moved it to the after save event because the values aren't available in the before save event, but this is causing new problems. Have a look at how the Media save method now looks:

public override void Save() { SaveEventArgs e = new SaveEventArgs(); FireBeforeSave(e);

if (!e.Cancel)
{
    foreach (var property in GenericProperties)
    {
        _media.SetValue(property.PropertyType.Alias, property.Value);
    }

    ApplicationContext.Current.Services.MediaService.Save(_media);

    base.Save();

    XmlDocument xd = new XmlDocument();
    XmlGenerate(xd);

    // generate preview for blame history?
    if (UmbracoSettings.EnableGlobalPreviewStorage)
    {
        // Version as new guid to ensure different versions are generated as media are not versioned currently!
        SavePreviewXml(generateXmlWithoutSaving(xd), Guid.NewGuid());
    }

    FireAfterSave(e);
}

}

Between the before save and after save event the xml is updated. So I need to do my code in the before save event, but that doesn't work anymore. This could be fixed by updating the xml after the after save event is fired.


Morten Christensen 30 Dec 2012, 08:05:58

Yea, I see the problem. But you should know that this: ''new Media(mediaId).getProperty("umbracoFile").Value.ToString();'' triggers the media item to load again, which would be the version thats already saved, so yes...that won't work. But any reason why you are not using the "sender" param of the BeforeSave event? Have you tried the following? I believe it should work as the property values that has been set are contained within the object until they are saved in the database.

void Media_BeforeSave(Media sender, umbraco.cms.businesslogic.SaveEventArgs e)


Jeroen Breuer 30 Dec 2012, 08:43:21

Just tried to use sender instead of new Media(mediaId) and that does have the property, but now I'm having another issue. Here is my code:

public DAMP_ApplicationBase() { Media.BeforeSave += new Media.SaveEventHandler(Media_BeforeSave); }

protected void Media_BeforeSave(Media sender, SaveEventArgs e) { try { if (ConfigurationManager.AppSettings["DAMP_CallImageCropper"] != null && ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"] != null && Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_CallImageCropper"])) { DAMP_Helper.CallImagecropper(sender, Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"])); } } catch (Exception ex) { DAMP_Helper.LogException(ex); } }

///

/// If you create a media item the image crops aren't created by default. You first need to press the save button before crops are created. /// If you call this method in the before save event it will create the crops without that you need to press the save button. /// It's recommended to call this method in a try-catch and check if the selected property alias (usually umbracoFile) for cropping has a path. /// Make sure the culture is the same everywhere. You could run into this problem: http://umbraco.codeplex.com/workitem/30273. /// This only works with the default image cropper that's part of Umbraco 4.5+. /// /// The id of the media item that needs to be cropped. /// If true the image will only be cropped if no crops are available. If false the image will always be cropped. public static void CallImagecropper(Media media, bool onlyIfEmpty) { IDataType imageCropper = new Factory().GetNewObject(new Guid("7A2D436C-34C2-410F-898F-4A23B3D79F54"));

//Get the propertyid and datatypeid of this media item.
string sql = string.Format(@"
            select cpd.id as id, cpt.dataTypeId as datatypeid from cmsPropertyData cpd
                inner join cmsPropertyType cpt on cpd.propertytypeid = cpt.Id
                inner join cmsDataType cdt on cpt.dataTypeId = cdt.nodeId
            where cpd.contentNodeId = {0}
            and cdt.controlId = '{1}'", media.Id, imageCropper.Id);

using (IRecordsReader dr = SqlHelper.ExecuteReader(sql))
{
    while (dr.Read())
    {
        int propertyId = dr.GetInt("id");

        //Set the values on the imagecropper datatype that was found on the media type.
        imageCropper.Data.PropertyId = propertyId;
        imageCropper.DataTypeDefinitionId = dr.GetInt("datatypeid");

        Property propImagecropper = null;
        bool isUpdated = false;
        string configuration = ((PrevalueEditor)imageCropper.PrevalueEditor).Configuration;

        if (onlyIfEmpty)
        {
            //Get the property where the crop data is stored.
            propImagecropper = new Property(propertyId);

            string[] configFiles = configuration.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (configFiles.Any())
            {
                //Get the property that is used for the Image Cropper (the first value from the configuration string).
                Property pathProp = media.getProperty(configFiles[0]);
                if (pathProp != null && pathProp.Value != null && !string.IsNullOrEmpty(pathProp.Value.ToString()))
                {
                    //Get the date when the file was last modified.
                    DateTime modification = File.GetLastWriteTime(HttpContext.Current.Server.MapPath(pathProp.Value.ToString()));

                    //Check if the file is updated less than a minute ago. The cropper must be called if it is.
                    isUpdated = modification > DateTime.Now.AddMinutes(-1);
                }
            }
        }

        if (!onlyIfEmpty || isUpdated || propImagecropper != null && (propImagecropper.Value == null || string.IsNullOrEmpty(propImagecropper.Value.ToString())))
        {
            //Now that all properties are set correctly call the imagecropper and crop the image.
            DAMP_Imagecropper dataEditor = new DAMP_Imagecropper(imageCropper.Data, configuration);
            dataEditor.Page = new Page();
            dataEditor.CallInit();
            dataEditor.Save();
        }
    }
}

}

The CallImagecropper method fixes an [old issue|http://issues.umbraco.org/issue/U4-386] in Umbraco where you need to press the save button twice before a crop is created. Somehow the following code worked in v4 in the before save event, but now only works in the after save event:

//Now that all properties are set correctly call the imagecropper and crop the image. DAMP_Imagecropper dataEditor = new DAMP_Imagecropper(imageCropper.Data, configuration); dataEditor.Page = new Page(); dataEditor.CallInit(); dataEditor.Save();

This simply tries to trigger the Image Cropper which somehow in Umbraco only works after saving the image twice. This code now only works in the after save event. Probably because inside the Image Cropper it also fetches some values which aren't available in the before save event. There probably isn't an easy way to fix this so it still needs to be called in the after save event, but would it be a problem if the xml is updated after the after save event? That would fix things :-).


Jeroen Breuer 30 Dec 2012, 09:07:16

Hmm just discovered another after save event where I already need the new xml so can't change that either. Maybe I can refresh the xml manually again in the after save event. Will do some experiments.


Morten Christensen 30 Dec 2012, 12:49:05

I haven't looked at the ImageCropper yet, but I will probably look at both the ImageCropper, UploadField and the image upload dialog thats been mentioned as having issues - next week. So please feel free to post the code that is causing you trouble, as you have already done, as it helps me to understand how its used. A thing that Randy McCluer (@randylsu) mentioned, which I thought was a good idea, was to extract the image cropping code to a separate and central class that can be used for stuff like cropping images and creating thunbnails, which is currently happening all over the place or within DataTypes (DataEditors), when it could be centralized. But not sure if that would benefit you (?), as I'm not sure how you use or extend the image cropper in DAMP.


Jeroen Breuer 31 Dec 2012, 11:58:25

Did some more testing and it seems that it doesn't matter if I refresh the xml manually in the after save event. The problem is that the ImageCropper xml doesn't get saved in the cmsContentXml table so it doesn't exists in the old and new xml. So the problem is probably related to the ImageCropper and not the before or after save event. I agree with Randy McCluer that it's best to move the Image Cropping to a separete class. Hopefully it can also fix [this issue|http://issues.umbraco.org/issue/U4-386] so I don't even need the CallImageCropper method anymore in DAMP. The only things that DAMP does with the Image Cropper is making sure a crop is created (with CallImageCropper) and preview that crop when selecting media. The preview part still works so we only need to make sure a crop is always created. Something which should be done in the Core and not in DAMP.


Jeroen Breuer 31 Dec 2012, 15:09:30

Did some more research on the ImageCropper. My original DAMP code calls the OnInit again in the before save event and I found this line of code in the OnInit event of the ImageCropper:

// we need this ugly code because there's no way to use a base class CMSNode node = new CMSNode(currentDocumentId); if (node.nodeObjectType == Document._objectType) { uploadProperty = new Document(currentDocumentId).getProperty(config.UploadPropertyAlias); } else if (node.nodeObjectType == umbraco.cms.businesslogic.media.Media._objectType) { uploadProperty = new Media(currentDocumentId).getProperty(config.UploadPropertyAlias); } else if (node.nodeObjectType == Member._objectType) { uploadProperty = new Member(currentDocumentId).getProperty(config.UploadPropertyAlias); } else { throw new Exception("Unsupported Umbraco Node type for Image Cropper (only Document, Media and Members are supported."); }

This is exactly what I also did in my before save event where new Media(id).getProperty("umbracoFile") would return an empty string, but sender.getProperty("umbracoFile") would return the correct value. So this is why it probably won't work.

The reason why I can't update the ImageCropper in the after save event is because all changes have already been sent to the database in 1 transcation. So perhaps there are 2 breaking changes here: 1 Not all values are available in the before save event because the transaction isn't completed yet. 2 You can't set values in the after save event because the transaction is already completed. In v4 both were possible.


Morten Christensen 31 Dec 2012, 15:43:23

Point 1 is only partly true as it depends on how you get the Document. You should use the Event sender ad that is the object that is going to be saved. Point 2 is correct, but you are free to save it again if you need to apply changes to a saved Document, but ypu'd have to ensure that you don't end up an endless loop.

Either way, we obviously have to have the image cropper as the current code is not going to work.


Jeroen Breuer 31 Dec 2012, 16:11:28

You're right about point 2 and that's what I tried for the Image Cropper, but it still doesn't work. Here is my code: public DAMP_ApplicationBase() { Media.BeforeSave += Media_BeforeSave; Media.AfterSave += new Media.SaveEventHandler(Media_AfterSave); }

protected void Media_BeforeSave(Media sender, SaveEventArgs e) { try { if (ConfigurationManager.AppSettings["DAMP_CallImageCropper"] != null && ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"] != null && Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_CallImageCropper"])) { bool? savedImageCropper = (bool?)HttpContext.Current.Items["CallImagecropper-" + sender.Id];

        if (savedImageCropper.HasValue && savedImageCropper.Value == true)
        {
            //Call the Image Cropper in the second save event because all values should be available there.
            DAMP_Helper.CallImagecropper(sender, Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"]));
        }
    }
}
catch (Exception ex)
{
    DAMP_Helper.LogException(ex);
}

}

#region Events

protected void Media_AfterSave(Media sender, umbraco.cms.businesslogic.SaveEventArgs e) { try { if (ConfigurationManager.AppSettings["DAMP_CallImageCropper"] != null && ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"] != null && Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_CallImageCropper"])) { bool? savedImageCropper = (bool?)HttpContext.Current.Items["CallImagecropper-" + sender.Id];

        if (!savedImageCropper.HasValue || (savedImageCropper.HasValue && savedImageCropper.Value == false))
        {
            //Call the save method again of the media object. Be careful that this code is only called once, because it will trigger the after save method again which could cause an infinite loop.
            HttpContext.Current.Items["CallImagecropper-" + sender.Id] = true;
            sender.Save();
        }
    }
}
catch (Exception ex)
{
    DAMP_Helper.LogException(ex);
}

} I first save the media item again so I know that all values are available in the before event which is where I need to call the CallImageCropper method. Now everything should work like in v4, but it still doesn't work. The code is hacky anyway so it's really better to just improve the Image Cropper so all of this isn't needed anymore.


Jeroen Breuer 01 Jan 2013, 16:10:36

I finally got my CallImageCropper method working again :-). I still need to use the event code from the previous post, but here is the code of the working CallImageCropper method:

///

/// If you create a media item the image crops aren't created by default. You first need to press the save button before crops are created. /// If you call this method in the before save event it will create the crops without that you need to press the save button. /// It's recommended to call this method in a try-catch and check if the selected property alias (usually umbracoFile) for cropping has a path. /// Make sure the culture is the same everywhere. You could run into this problem: http://umbraco.codeplex.com/workitem/30273. /// This only works with the default image cropper that's part of Umbraco 4.5+. /// /// The media item that needs to be cropped. /// If true the image will only be cropped if no crops are available. If false the image will always be cropped. public static void CallImagecropper(Media media, bool onlyIfEmpty) { IDataType imageCropper = new Factory().GetNewObject(new Guid("7A2D436C-34C2-410F-898F-4A23B3D79F54"));

//Get the propertyid and datatypeid of this media item.
string sql = string.Format(@"
        select cpd.id as id, cpt.dataTypeId as datatypeid, cpt.Alias as alias from cmsPropertyData cpd
            inner join cmsPropertyType cpt on cpd.propertytypeid = cpt.Id
            inner join cmsDataType cdt on cpt.dataTypeId = cdt.nodeId
        where cpd.contentNodeId = {0}
        and cdt.controlId = '{1}'", media.Id, imageCropper.Id);

using (IRecordsReader dr = SqlHelper.ExecuteReader(sql))
{
    while (dr.Read())
    {
        int propertyId = dr.GetInt("id");
        string alias = dr.GetString("alias");

        //Set the values on the imagecropper datatype that was found on the media type.
        imageCropper.Data.PropertyId = propertyId;
        imageCropper.DataTypeDefinitionId = dr.GetInt("datatypeid");

        Property propImagecropper = null;
        bool isUpdated = false;
        string configuration = ((PrevalueEditor)imageCropper.PrevalueEditor).Configuration;

        if (onlyIfEmpty)
        {
            //Get the property where the crop data is stored.
            propImagecropper = new Property(propertyId);

            string[] configFiles = configuration.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            if (configFiles.Any())
            {
                //Get the property that is used for the Image Cropper (the first value from the configuration string).
                Property pathProp = media.getProperty(configFiles[0]);
                if (pathProp != null && pathProp.Value != null && !string.IsNullOrEmpty(pathProp.Value.ToString()))
                {
                    //Get the date when the file was last modified.
                    DateTime modification = File.GetLastWriteTime(HttpContext.Current.Server.MapPath(pathProp.Value.ToString()));

                    //Check if the file is updated less than a minute ago. The cropper must be called if it is.
                    isUpdated = modification > DateTime.Now.AddMinutes(-1);
                }
            }
        }

        if (!onlyIfEmpty || isUpdated || propImagecropper != null && (propImagecropper.Value == null || string.IsNullOrEmpty(propImagecropper.Value.ToString())))
        {
            //Now that all properties are set correctly call the imagecropper and crop the image.
            DAMP_Imagecropper dataEditor = new DAMP_Imagecropper(imageCropper.Data, configuration);
            dataEditor.Page = new Page();
            dataEditor.CallInit();
            dataEditor.Save();

            //Set the value on the media object so it will be part of the transaction.
            media.getProperty(alias).Value = imageCropper.Data.Value;
        }
    }
}

}

After all code from the CallImageCropper is done I also need to set the property on the media object in the before save event. I get the alias in the custom query which also get's all the other data needed to get the Image Cropper datatype. So if you upload an image DAMP will make sure the crops are always available again.


Morten Christensen 02 Jan 2013, 16:08:14

This issue was originally about the BeforeSave event, but seemed to have turned into how DAMP uses the ImageCropper :) But either way the code in the Save method on both Media and Document has been moved around a bit, so the updated properties are available in the BeforeSave event. I have yet to look at the ImageCropper, but looking at the code in your previous comment I think it can be reduced a bit and more importantly remove the usage of the SqlHelper. I believe the following code should work just as well, and removes the need for the SqlHelper, loading the DataType, Property and configuration. Please note I haven't test this code as well, so there might be issues but I'm positive that it should work:

public void CallImageCropper(Media media, bool onlyIfEmpty) { var imageCropperId = new Guid("7A2D436C-34C2-410F-898F-4A23B3D79F54"); var croppers = media.GenericProperties.Where(x => x.PropertyType.DataTypeDefinition.DataType.Id == imageCropperId); foreach (var property in croppers) { bool isUpdated = false; string configuration = ((PrevalueEditor)property.PropertyType.DataTypeDefinition.DataType.PrevalueEditor).Configuration;

    if (onlyIfEmpty)
    {
        string[] configFiles = configuration.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
        if (configFiles.Any())
        {
            //Get the property that is used for the Image Cropper (the first value from the configuration string).
            Property pathProp = media.getProperty(configFiles[0]);
            if (pathProp != null && pathProp.Value != null && !string.IsNullOrEmpty(pathProp.Value.ToString()))
            {
                //Get the date when the file was last modified.
                DateTime modification = File.GetLastWriteTime(HttpContext.Current.Server.MapPath(pathProp.Value.ToString()));

                //Check if the file is updated less than a minute ago. The cropper must be called if it is.
                isUpdated = modification > DateTime.Now.AddMinutes(-1);
            }
        }
    }

    if (!onlyIfEmpty || isUpdated || (property.Value == null || string.IsNullOrEmpty(property.Value.ToString())))
    {
        //Now that all properties are set correctly call the imagecropper and crop the image.
        DAMP_Imagecropper dataEditor = new DAMP_Imagecropper(property.PropertyType.DataTypeDefinition.DataType.Data, configuration);
        dataEditor.Page = new Page();
        dataEditor.CallInit();
        dataEditor.Save();

        //Set the value on the media object so it will be part of the transaction.
        media.getProperty(property.PropertyType.Alias).Value = property.PropertyType.DataTypeDefinition.DataType.Data.Value;
    }
}

}


Jeroen Breuer 02 Jan 2013, 16:16:42

Hmm if values are available in the before save event again that should make things easier. So both examples should work again in the before save event? Media(mediaId).getProperty("umbracoFile") sender.getProperty("umbracoFile") I know that the code can also work without the SQL Helper, but my custom query is probably a lot faster than your example. In 1 query it fetches everything that I need. Your example probably does a lot more queries to the database (at least with the old API).


Morten Christensen 02 Jan 2013, 16:37:25

This bit won't work as you are reloading the Media object, which obviously won't contain the yet-to-be-saved properties: Media(mediaId).getProperty("umbracoFile") This bit of code will work because you are working with the Media object that is in the process of being saved: sender.getProperty("umbracoFile")

The code will most likely trigger some additional db queries (haven't really gone into that much detail), but I think the advantage of not having to rely on the database/SqlHelper outweighes that. Just because you write a custom query doesn't necessarily mean you can work around db lookups. Something like new Propperty(id) would trigger a lookup. And also keep in mind that Document and Media is refactored to use the new api, so some of the previous lookups have been removed.


Jeroen Breuer 05 Jan 2013, 16:22:15

You're right that this issue is more about the ImageCropper and DAMP, but since all the stuff is already here I'll keep using this issue ;-). Somehow my CallImageCropper method doesn't work anymore. The following code worked in build 94, but doesn't work in build 108: //Now that all properties are set correctly call the imagecropper and crop the image. DAMP_Imagecropper dataEditor = new DAMP_Imagecropper(imageCropper.Data, configuration); dataEditor.Page = new Page(); dataEditor.CallInit(); dataEditor.Save();

//Set the value on the media object so it will be part of the transaction. media.getProperty(alias).Value = imageCropper.Data.Value; I debugged and the crop xml is available in imageCropper.Data.Value and is set on the correct property, but when I check the cmsContentXml table the crop xml isn't there after saving. Something must have changed because this used to work.


Jeroen Breuer 05 Jan 2013, 17:07:46

Did an experiment with another property and that also doesn't work: //Set the value on the media object so it will be part of the transaction. media.getProperty(alias).Value = imageCropper.Data.Value; media.getProperty("hoi").Value = "This is a test"; So somehow properties which are set in the before save event aren't saved anymore. They are not available in the cmsContentXml and after reloading the media item the "hoi" property is still empty. Don't know if it makes any difference, but this is the second before save event like I explained in this code: http://issues.umbraco.org/issue/U4-1372#comment=67-4410. Somehow clicking on that link it goes to the wrong comment so please open the link in a new tab.


Jeroen Breuer 11 Jan 2013, 15:27:56

Just did a test in UmbracoCms.6.0.0-beta.zip and it's still not fixed in there. Values set in the before save event aren't saved. It doesn't matter if it's the first or second time in the before save event.


Jeroen Breuer 11 Jan 2013, 15:50:03

The before save event I'm testing is from DAMP: http://damp.codeplex.com/SourceControl/changeset/view/cbef6f1cc8bd#DigibizAdvanceMediaPicker/DAMP_ApplicationBase.cs

Here is my test code with the extra test property: protected void Media_BeforeSave(Media sender, SaveEventArgs e) { try { if (ConfigurationManager.AppSettings["DAMP_CallImageCropper"] != null && ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"] != null && Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_CallImageCropper"])) { bool? savedImageCropper = (bool?)HttpContext.Current.Items["CallImagecropper-" + sender.Id];

        if (savedImageCropper.HasValue && savedImageCropper.Value == true)
        {
            DAMP_Helper.CallImagecropper(sender, Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"]));
        }
        else
        {
            sender.getProperty("hoi").Value = "This is a test";
        }
    }
}
catch (Exception ex)
{
    DAMP_Helper.LogException(ex);
}

}

protected void Media_AfterSave(Media sender, umbraco.cms.businesslogic.SaveEventArgs e) { try { if (ConfigurationManager.AppSettings["DAMP_CallImageCropper"] != null && ConfigurationManager.AppSettings["DAMP_OnlyIfEmpty"] != null && Convert.ToBoolean(ConfigurationManager.AppSettings["DAMP_CallImageCropper"])) { bool? savedImageCropper = (bool?)HttpContext.Current.Items["CallImagecropper-" + sender.Id];

        if (!savedImageCropper.HasValue || (savedImageCropper.HasValue && savedImageCropper.Value == false))
        {
            //Call the save method again of the media object. Be careful that this code is only called once, because it will trigger the after save method again which could cause an infinite loop.
            HttpContext.Current.Items["CallImagecropper-" + sender.Id] = true;
            sender.Save();
        }
    }
}
catch (Exception ex)
{
    DAMP_Helper.LogException(ex);
}

UpdateDAMP(sender, false);

}


Jeroen Breuer 14 Jan 2013, 21:00:44

Just checked the v6 beta source code. This is the save method code: public override void Save() { foreach (var property in GenericProperties) { if (property.Value == null) continue;

    MediaItem.SetValue(property.PropertyType.Alias, property.Value);
}

SaveEventArgs e = new SaveEventArgs();
FireBeforeSave(e);{code}I changed it to this and now the values set in the before save event are saved again:{code:lang=scala}public override void Save()

{ SaveEventArgs e = new SaveEventArgs(); FireBeforeSave(e);

foreach (var property in GenericProperties)
{
    if (property.Value == null)
        continue;

    MediaItem.SetValue(property.PropertyType.Alias, property.Value);
}{code}So it's a small fix. The above code is for media, but for the document api the same needs to be done. After this the DAMP events are also working again.


Sebastiaan Janssen 14 Jan 2013, 21:31:05

@Jeroen this small fix also causes plenty of other problems and is therefore not a fix it was switched around to fix U4-1438 for example (height and width properties were erased because the event was kicking in too late.


Jeroen Breuer 14 Jan 2013, 21:44:52

Didn't know that, but how can it even work by switching around? Currently all values set in the before save event don't work. I don't know what's easier to fix, but isn't it possible to move the before save event up and use that event to fix U4-1438? Something like this: http://issues.umbraco.org/issue/U4-1368#comment=67-4425


Morten Christensen 15 Jan 2013, 10:27:44

Okay, so I tracked down the reason for us switching the setting of the values before firing the event, which meant that we were in a no-win situation :) We were using the new IContentBase object which is available internally through the legacy Document and Media classes for setting the additional properties when uploading an image. Changing the workaround to use the legacy object and getProperty("alias").Value allowed us to change the Save method so the BeforeSave event is fired before the values are set and then saved. So hopefully this is the last we'll see of this ;)


Jeroen Breuer 25 Jan 2013, 17:57:50

Why is this issue backwards compatible? See these comments:

Me: 1 Not all values are available in the before save event because the transaction isn't completed yet. 2 You can't set values in the after save event because the transaction is already completed. In v4 both were possible.

Morten: Point 1 is only partly true as it depends on how you get the Document. You should use the Event sender ad that is the object that is going to be saved. Point 2 is correct, but you are free to save it again if you need to apply changes to a saved Document, but ypu'd have to ensure that you don't end up an endless loop.

Seems like a breaking change.


Morten Christensen 25 Jan 2013, 18:14:58

The topic of this post is the BeforeSave event. Point 2 is about the AfterSave event, so not sure what it is you expect? IMO it doesn't make sense to change this issue, but i'd be happy to create an issue about the AfterSave events having a breaking change.


Jeroen Breuer 25 Jan 2013, 18:22:04

I agree with you. Just wanted to make this issue not backwards compatible because of the comments not the original issue. I think it's a good idea to create a new issue about the after save event having a breaking change.


Sebastiaan Janssen 28 Jan 2013, 14:15:33

Added a new issue for this to list the breaking change U4-1564.


Priority: Major

Type: Bug

State: Fixed

Assignee: Morten Christensen

Difficulty: Normal

Category:

Backwards Compatible: False

Fix Submitted:

Affected versions: 6.0.0

Due in version: 6.0.0

Sprint:

Story Points:

Cycle: