So in my old umbraco installation 4.0.4.2, I wrote some simple methods and batch scripts to create pages, set all their attributes (picture, teaser text, date, etc.) every night at midnight for staff. This was handy because some people at my company have to create pages every single day and it is a very mundane process for them. It all worked fine. Specifically, after setting a displayDate property on the document, the "AutoFolders" package correctly created the date folders and published the document, making it immediately available on the web.
Now, after upgrading the Server hardware, OS and Database server and Umbraco version (4.9.1) I am bringing all the automation back online, but I am running into a problem with the /base requests. I should mention that I switched from "AutoFolders" package to "DateFolders" package since the latter is built on .NET 4 and the former .NET 3.5
Now however, when my /base request executes, everything works except that the date folders created by the DateFolders package are unpublished and I get a generic error ( This is strange because when creating an item in the backoffice manually, the DateFolders are always published after creating the item. But when the same type document is created using /base, ONLY the child document gets published.
If I try to create a document that DateFolders is NOT configured to create folders for, everything works fine.
However, if I set displayDate and try to publish a document using /base, then I just get a generic "Internal Server 500" error with nothing in the Windows Application Log. I do get this in the Umbraco Log:
1404848 0 0 2013-06-04 16:21:02.847 Error Couldn't find any page with the nodeId = 0. This is most likely caused by the page isn't published! Parameter name: nodeId 1404849 0 0 2013-06-04 16:21:02.847 Error Couldn't find any page with the nodeId = 0. This is most likely caused by the page isn't published! Parameter name: nodeId 1404850 0 0 2013-06-04 16:21:02.847 Error Couldn't find any page with the nodeId = 0. This is most likely caused by the page isn't published! Parameter name: nodeId 1404847 0 4282 2013-06-04 16:21:02.673 Publish 1404846 0 -1 2013-06-04 16:21:02.083 System Loading content from disk cache... 1404845 0 4285 2013-06-04 16:21:01.910 New 1404844 0 4284 2013-06-04 16:21:01.647 New 1404843 0 4283 2013-06-04 16:21:01.287 New 1404842 0 4282 2013-06-04 16:21:00.913 Publish 1404840 0 4282 2013-06-04 16:21:00.630 New
//since using Date Folders package instead of Auto Folders, the systemDateFolders are being created with /base calls, //but not published, So...they have to created manually
DocumentType dt = DocumentType.GetByAlias("show"); Document d = Document.MakeNew(name, dt, new umbraco.BusinessLogic.User(0), parentid); var displayDate = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(day)); //to modify the document properties.... d.getProperty("displayDate").Value = displayDate;
Document DayFolderParent = new Document(d.ParentId); DayFolderParent.Publish(new umbraco.BusinessLogic.User(0)); DayFolderParent.Save(); umbraco.library.UpdateDocumentCache(DayFolderParent.Id);
return d.Id.ToString();
I tried to change the method above so that AFTER I create my page, I get the parentId and then send it a publish, save, and update document cache, like this:
//since using Date Folders package instead of Auto Folders, the systemDateFolders are being created with /base calls, //but not published, So...they have to created manually
DocumentType dt = DocumentType.GetByAlias("show"); Document d = Document.MakeNew(name, dt, new umbraco.BusinessLogic.User(0), parentid); var displayDate = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(day)); //to modify the document properties.... d.getProperty("displayDate").Value = displayDate;
//try and get parent folder of newly created document and publish it Document DayFolderParent = new Document(d.ParentId); DayFolderParent.Publish(new umbraco.BusinessLogic.User(0)); DayFolderParent.Save(); umbraco.library.UpdateDocumentCache(DayFolderParent.Id);
//it doesn't work, no error
return d.Id.ToString(); }
Still nothing.
The only thing I can think of is that I will have to alter the Create method above to check for the existence of the year date folder first and then create and publish it if it is not already there, then check the month, then the day, then finally create my item. What a hassle, I'd rather not have to do that. Is there something simple I'm just missing?
I thought to look at the source for the DateFolders package and I noticed that in the New document event that the date's are being set using datetime.now when creating the date folders:
if (_createDayFolders) doc.Move(dayFolder.Id); else doc.Move(monthFolder.Id); doc.Save();
if (yearFolder != null) yearFolder.SaveAndPublish(); if (monthFolder != null) monthFolder.SaveAndPublish(); if (dayFolder != null) dayFolder.SaveAndPublish();
// Order OrderChildrenByName(new Document(parent.Id)); OrderChildrenByName(new Document(yearFolder.Id)); if (_createDayFolders) OrderChildrenByName(new Document(monthFolder.Id)); } } else { // Date folder doctype is null if (BasePage.Current != null) BasePage.Current.ClientTools.ShowSpeechBubble(BasePage.speechBubbleIcon.error, "Date folder property", string.Format("The date folder doctype does not exist ({0})", _dateFolderDocType)); } } catch { } }
In my base class, I'm trying to set the displayDate before I publish the node. I also realized that when publishing in the backoffice, you always have to create the node first before you can access it's displayDate and change it. So I thought, change your base class to publish/save/updateDocCache the node first, then set the displayDate and publish/save/updateDocCache again.
The good news is that when I check the back office, the node is created and moved and it's date folders are published. The bad news is that I still get a 500-Internal server error and so the nodeId is not being returned to the whatever the calling function is (in this case a script that makes the base request needs the nodeId for other stuff). No event, nothing negative in umbracoLog. It shows the node and date folders being created with no issues.
Almost there.....
Here's the edited class:
//since using Date Folders package instead of Auto Folders, the systemDateFolders are being created with /base calls, //but not published, So...they have to created manually
DocumentType dt = DocumentType.GetByAlias("show"); Document d = Document.MakeNew(name, dt, new umbraco.BusinessLogic.User(0), parentid); var displayDate = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(day));
Ok, so I tried breaking up the method into to two parts. One method handls the create. The next one changes the displayDate.
The first one works, the second one gives me the error (but the node is still moved).
Maybe I should switch to the auto hook up style of base classes?
No, that didn't work.
How about trying to pass back the exception through the base request?
[RestExtensionMethod(returnXml = false)] public static string GoodBye(int nodeid, int year, int month, int day, int hour, int minute, int second) { // Get the document by its ID
string result = "1";
try {
Document mdoc = new Document(nodeid);
//var displayDate = new DateTime(Convert.ToInt32(year), Convert.ToInt32(month), Convert.ToInt32(day), hour, minute, second); var displayDate = new DateTime(year, month, day, hour, minute, second);
//to modify the document properties.... mdoc.getProperty("displayDate").Value = displayDate;
// After modifying the document, prepare it for publishing mdoc.Publish(new umbraco.BusinessLogic.User(0)); mdoc.Save();
// Tell umbraco to publish the document so the updated properties are visible on website umbraco.library.UpdateDocumentCache(mdoc.Id); } catch(Exception e) { result = e.StackTrace.ToString() + "<br /><br />" + e.Message;
}
return result;
Ok, that gets me past the generic internal server error; at least now I know which method in the DateFolders package is throwing the error.
at InfoCaster.Umbraco.Common.DateFolders.Document_AfterSave(Document doc, SaveEventArgs e)
at umbraco.cms.businesslogic.web.Document.SaveEventHandler.Invoke(Document sender, SaveEventArgs e)
at umbraco.cms.businesslogic.web.Document.FireAfterSave(SaveEventArgs e)
at umbraco.cms.businesslogic.web.Document.Save()
at BaseTest.TestClass.GoodBye(Int32 nodeid, Int32 year, Int32 month, Int32 day, Int32 hour, Int32 minute, Int32 second)
Object reference not set to an instance of an object.
...and here is that method, Document_AfterSave(Document doc, SaveEventArgs e)
/// <summary> /// After save event /// </summary> /// <param name="doc">The document</param> /// <param name="e">The event args</param> void Document_AfterSave(Document doc, SaveEventArgs e) { if (_itemDocType.Contains(doc.ContentType.Alias)) { DocumentType folderDocType = DocumentType.GetByAlias(_dateFolderDocType); if (folderDocType != null) { if (doc.ParentId > 0) { // Date item saved DateTime date = default(DateTime); if (!string.IsNullOrEmpty(_itemDateProperty)) { string dateValue = doc.GetDatePropertyValue(_itemDateProperty); if (!string.IsNullOrEmpty(dateValue)) DateTime.TryParse(dateValue, out date); } if (date == default(DateTime)) date = doc.CreateDateTime;
if (_createDayFolders) { dayFolder = new Document(doc.ParentId); monthFolder = new Document(dayFolder.ParentId); yearFolder = new Document(monthFolder.ParentId); } else { monthFolder = new Document(doc.ParentId); yearFolder = new Document(monthFolder.ParentId); } parent = new Document(yearFolder.ParentId);
if (_createDayFolders) { // Day newDayFolder = newMonthFolder.Children.FirstOrDefault(x => x.ContentType.Alias == _dateFolderDocType && x.Text == date.Day.ToString("00")); if (newDayFolder == null) { // Create day folder newDayFolder = Document.MakeNew(date.Day.ToString("00"), DocumentType.GetByAlias(_dateFolderDocType), doc.User, newMonthFolder.Id); } }
// Move if (_createDayFolders) doc.Move(newDayFolder.Id); else doc.Move(newMonthFolder.Id);
if (doc.Published) doc.SaveAndPublish();
int orderParentId = newMonthFolder.Id; if (_createDayFolders) orderParentId = newDayFolder.Id;
if (!string.IsNullOrEmpty(_itemDateProperty)) OrderChildrenByDateProperty(new Document(orderParentId), _itemDateProperty); else OrderChildrenByCreateDate(new Document(orderParentId));
if (newYearFolder != null) newYearFolder.SaveAndPublish(); if (newMonthFolder != null) newMonthFolder.SaveAndPublish(); if (newDayFolder != null) newDayFolder.SaveAndPublish();
// Delete if empty if (_createDayFolders) { dayDoc = new Document(dayFolder.Id); if (dayDoc.ChildCount < 1) { dayDoc.DeleteCompletely(); } }
monthDoc = new Document(monthFolder.Id); if (monthDoc.ChildCount < 1) { monthDoc.DeleteCompletely();
yearDoc = new Document(yearFolder.Id); if (yearDoc.ChildCount < 1) yearDoc.DeleteCompletely(); }
// Order OrderChildrenByName(new Document(parent.Id)); OrderChildrenByName(new Document(newYearFolder.Id)); if (_createDayFolders) OrderChildrenByName(new Document(newMonthFolder.Id));
doc = new Document(doc.Id);
BasePage.Current.ClientTools .ChangeContentFrameUrl(string.Concat("editContent.aspx?id=", doc.Id)); } } else { // Item is created under 'Content' root, which is unsupported if (BasePage.Current != null) BasePage.Current.ClientTools.ShowSpeechBubble(BasePage.speechBubbleIcon.error, "Unsupported", "Creating a datefolders item under 'Content' root is unsupported"); } } else { // Date folder doctype is null if (BasePage.Current != null) BasePage.Current.ClientTools.ShowSpeechBubble(BasePage.speechBubbleIcon.error, "Configuration error", string.Format("The date folder doctype ('{0}') does not exist", _dateFolderDocType)); } } }
Not that good at C#....I'm not seeing the answer. Is there any change I can make to how I'm setting the displayDate property in my "GoodBye" method to not cause this error. I'm not sure where the "Object Not Set" error is coming from in the above DateFolders method....
/base, DateFolders package, simple "Create" method
So in my old umbraco installation 4.0.4.2, I wrote some simple methods and batch scripts to create pages, set all their attributes (picture, teaser text, date, etc.) every night at midnight for staff. This was handy because some people at my company have to create pages every single day and it is a very mundane process for them. It all worked fine. Specifically, after setting a displayDate property on the document, the "AutoFolders" package correctly created the date folders and published the document, making it immediately available on the web.
Now, after upgrading the Server hardware, OS and Database server and Umbraco version (4.9.1) I am bringing all the automation back online, but I am running into a problem with the /base requests. I should mention that I switched from "AutoFolders" package to "DateFolders" package since the latter is built on .NET 4 and the former .NET 3.5
Now however, when my /base request executes, everything works except that the date folders created by the DateFolders package are unpublished and I get a generic error ( This is strange because when creating an item in the backoffice manually, the DateFolders are always published after creating the item. But when the same type document is created using /base, ONLY the child document gets published.
If I try to create a document that DateFolders is NOT configured to create folders for, everything works fine.
However, if I set displayDate and try to publish a document using /base, then I just get a generic "Internal Server 500" error with nothing in the Windows Application Log. I do get this in the Umbraco Log:
Here is my base method:
I tried to change the method above so that AFTER I create my page, I get the parentId and then send it a publish, save, and update document cache, like this:
Still nothing.
The only thing I can think of is that I will have to alter the Create method above to check for the existence of the year date folder first and then create and publish it if it is not already there, then check the month, then the day, then finally create my item. What a hassle, I'd rather not have to do that. Is there something simple I'm just missing?
Update.
I thought to look at the source for the DateFolders package and I noticed that in the New document event that the date's are being set using datetime.now when creating the date folders:
In my base class, I'm trying to set the displayDate before I publish the node. I also realized that when publishing in the backoffice, you always have to create the node first before you can access it's displayDate and change it. So I thought, change your base class to publish/save/updateDocCache the node first, then set the displayDate and publish/save/updateDocCache again.
The good news is that when I check the back office, the node is created and moved and it's date folders are published. The bad news is that I still get a 500-Internal server error and so the nodeId is not being returned to the whatever the calling function is (in this case a script that makes the base request needs the nodeId for other stuff). No event, nothing negative in umbracoLog. It shows the node and date folders being created with no issues.
Almost there.....
Here's the edited class:
Ok, so I tried breaking up the method into to two parts. One method handls the create. The next one changes the displayDate.
The first one works, the second one gives me the error (but the node is still moved).
Maybe I should switch to the auto hook up style of base classes?
No, that didn't work.
How about trying to pass back the exception through the base request?
Ok, that gets me past the generic internal server error; at least now I know which method in the DateFolders package is throwing the error.
...and here is that method, Document_AfterSave(Document doc, SaveEventArgs e)
Not that good at C#....I'm not seeing the answer. Is there any change I can make to how I'm setting the displayDate property in my "GoodBye" method to not cause this error. I'm not sure where the "Object Not Set" error is coming from in the above DateFolders method....
Ok, I guess I'll just catch the error being thrown on .Save() and move on:
Here is the thread on the DateFolder package Bug List
is working on a reply...