Try our conversational search powered by Generative AI!

Unable to save properties programmatically

Vote:
 

I am trying to migrate some data into my EPiServer site using a console app with EPiServer CMS 11.3.4. I have used Johan's approach in that linked thread to get the console app working and am now trying to set properties of various pages and save them. Initially after my console app saved a page, it appeared that nothing happened when I would refresh the admin edit view of the page in the browser, but I figured out that it must be caching the pages...I'm guessing the cache is normally updated automatically after saving a page, but since I'm running the site in the console app, maybe its unaware of the changes. So after I restart my web app (I'm just running it out of Visual Studio), the last saved date for the pages I saved is now updated, but all of the properties are still blank. So it seems my console app is successfully saving, but not writing any of the property values. There is even a case when I create a brand new page and set its properties but still only a default page saves without any of the property values. Here is the gist of my code:

foreach (SitePageData page in contentRepository.GetChildren(weekPage.ContentLink))
{
    if (page is CASB_LPS_Detail)
    {
        CASB_LPS_Detail cldPage = (CASB_LPS_Detail)page.CreateWritableClone();

        if (page.URLSegment.ToLower() == "intro")
        {
            cldPage.Body = new XhtmlString(weekPageContent["intro"].Html);
        }
        else if ...[other types]

        contentRepository.Save(cldPage, EPiServer.DataAccess.SaveAction.Publish, EPiServer.Security.AccessLevel.NoAccess);
    }
    else if (page is StationsPage)
    {
        StationPage stationPage;
        IEnumerable existingStationPages = contentRepository.GetChildren(page.ContentLink);

        foreach (StationContent station in weekStations)
        {
            string stationPageName = "Station" + station.StationNum;
            stationPage = existingStationPages.Where(p => p.Name == stationPageName).FirstOrDefault();

            if (stationPage == null)
            {
                //Create a child page for the station
                stationPage = contentRepository.GetDefault(page.ContentLink);
                stationPage.Name = stationPageName;
            }
            else
                stationPage = (StationPage)stationPage.CreateWritableClone();

            //stationPage.Image = Look up image;
            stationPage.Body = new XhtmlString(station.Html);

            //Save the station page
            contentRepository.Save(stationPage, EPiServer.DataAccess.SaveAction.Publish, EPiServer.Security.AccessLevel.NoAccess);

        }
    }
    else if (page is AVPage)
    {
        AVPage avPage = (AVPage)page.CreateWritableClone();
        avPage.AVPlaylistLocation = weekAV.Playlist;

        contentRepository.Save(avPage, EPiServer.DataAccess.SaveAction.Publish, EPiServer.Security.AccessLevel.NoAccess);
    }                               
}

I don't know if this has something to do with running in the context of my console app...like maybe something is not initialized, something unrelated like versioning, or something else.

#193936
Edited, Jun 07, 2018 21:15
Vote:
 

The site will cache data, so you might not see the data created/modified from the console app before the site is restarted (you can setup/configure EPiServer.Events so cache invalidations are sent from your console app to the site but if this a tool that you plan to run once that might be overkill).

Otherwise the code looks fine it should save the properties. I would start by looking at sql when the code is executed, in there you should see entries being added in tblContentProperty (and tblWorkContentProperty for versions) for your custom properties.

#193944
Jun 08, 2018 9:59
Vote:
 

I restored my database to the version from before I ever ran the console app to start from scratch. I then ran the website and, in the browser, set the AVPlaylistLocation property of an AVPage to "Site Save" and published. I can see this value in tblContentProperty and tblWorkContentProperty. But when I run and debug the console app and load this AVPage (the code posted above), page.AVPlaylistLocation is null. So it's not even loading the property value. Then it sets the AVPlaylistLocation property on the writable clone to "en_sy_spb_video_fm/en_sy_spb_video_fm_01" and saves it. This creates new rows in tblworkcontent and tblWorkContentProperty (status = 4, CommonDraft = 1, DelayPublishUntil = null, ChangedOnPublish = 0), but the values tblWorkContentProperty.LongString and tblContentProperty.LongString are still "Site Save".

I don't know if its related but I noticed avPage.IsModified remains false after setting AVPlaylistLocation. There is no approval sequence for the page - it inerhits Disabled from the root. Nothing special about the model either, see below. Given that its not reading or writing page properties, could something be uninitialized or a reference missing from the console app to cause this behavior? Or maybe something required in the app.config? The only thing I brought over into the app.config is the connection string.

    [ContentType(DisplayName = "AV Page", GUID = "B4A55C95-2165-4927-B9BC-5404EDF9B6C1", Description = "An AV page with a playlist.")]
    public class AVPage : StandardPage
    {
        [Display(
            Name = "AV Playlist Location",
            Description = "Location of AV playlist",
            GroupName = SystemTabNames.Content,
            Order = 0
        )]
        public virtual string AVPlaylistLocation { get; set; }
    }
#193973
Edited, Jun 08, 2018 18:23
Vote:
 

You need to reference the assembly containing your model classes (Pages, blocks etc) but I guess you already done that. Also you need to ensure that the InitializationEngine you set up have a reference to that assembly. Because at runtime your classes are subclassed by proxyclasses (you can see this in a debugger breakpoint if you look at the type of one of your models, it should not be the type itself but a proxy class). 

That generated proxyclass takes care of modified tracking and other goodies.  

#193995
Jun 11, 2018 9:27
Vote:
 

That's it! I had not included my own assembly in the collection of Assemblies passed to the InitializationEngine. I knew Castle proxy classes were there, but I didn't know what they were used for. Thanks, Johan!

#194030
Jun 11, 2018 15:51
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.