I have been attempting to resolve this issue for about two weeks now. So far, everything I try has a problem that makes it unworkable.

Problem
One of the current requirements is that I need to be able to transfer calendar events from multiple site collections into a single, amalgamated merged calendar stored on an entirely separate collection.

To that end, I have downloaded and installed Useful Sharepoint Designer Custom Workflow Activities from CodePlex, which adds extra workflow options for SPD. One of these allows you to copy a list item to another list at another URL. Ok, great. Easy enough to dump all the items we need into the alagamated calendar, just use the workflow to copy it whenever a new item is created or modified.

The problem I'm running into now is that the amalgamated calendar starts accruing duplicates, as every time an item is copied, it does not overwrite the original. To that end, I've created a sequential workflow in Visual Studio that just iterates through the events, and deletes old ones based on their original IDs. Running this manually works fine; I'm left with just the latest versions of events.

Since the copy process uses the System Account, the new item in the amalgamated site collection will not trigger any item creation workflows, to prevent workflow recursion. Alright, I understand that, and try to work around that.

I have tried adding the workflow as a timer job, in order to trigger this workflow on a regular basis. I have tried just creating a permanent whileActivity loop, that doesn't end unless it gets cancelled or triggers a fault. The other addition is a delayActivity, which pauses after iterating through the list, and then just dumps it back to the top of the loop. The idea is to start the workflow manually, and let it go. Unfortunately, the first time works fine, and when the workflow starts again, I get an error: Object reference not set to an instance of the object.

I have also tried using EFWorkflowTimer, to trigger workflows at specific times. I get the same error message as above: Object reference not set to an instance of the object.

This leads me to believe that there is something in my code that doesn't parse properly when disassociated from manual execution.

7/19/2012 11:19 AM System Account Creating and Invoking Duplicate Workflow
7/19/2012 11:19 AM System Account Beginning Checking for Duplicates
7/19/2012 11:19 AM System Account There was an issue checking duplicates.
7/19/2012 11:19 AM System Account Object reference not set to an instance of an object.

So it seems to be erroring on:

using (SPWeb web = workflowProperties.Web)

To narrow it down, I added a history event right after creating the SPWeb object, and it doesn't hit that. So it's something to do with the top line, which doesn't make sense; the implication is that workflowProperties is uninitialized, but if that were so, it couldn't log the history events, as that's exactly what it's using.

Have you considered expanding upon the Useful Sharepoint Designer Custom Workflow Activities action you are using to prevent duplicate items from being created? Following the logic from your snippet, you could add an updateListItem() method that would be called if a list item with the OriginalID exists.
–
LeviSJul 25 '12 at 15:31

The workflow option I'm choosing has an overwrite option; it doesn't work, for some reason.
–
fbueckertJul 25 '12 at 15:47

1

Taking a look at the docs, the overwrite option works only on Documents/Files in libraries. I assume this is because lists do not have a default, unique field to compare on. Whereas as the action can compare file names in a library to do the overwrite. If you can develop a custom workflow I expect you could download the source of the project and add in the ability to overwrite a list item for you special case.
–
LeviSJul 25 '12 at 16:10

I agree with LeviS you can track the ID of the calendar item you want to update and update it using the current item. SP Designer is nice, but this seems like a job for VS workflows.
–
MikeJul 27 '12 at 18:00

Use the console app settings to store things like Site Url, web URL, and list name/id. Then you can change it easier! Right click on your project -> Properties -> Settings tab (scope all of them to application.. not user)

Use log4net and log to a share so you can view the logs in case something goes wrong

Of course.. all this is moot if you checked for duplicates in your consolidated list. In your original workflow, create a step to see if the item exists using ListItemID and do an "update" instead of a "create.

I don't know of any other way to automatically make changes to a list; my understanding of Sharepoint is still very spotty, so the assumption I should just create a console application is going to require some examples for me to understand it.
–
fbueckertJul 26 '12 at 19:37

If I just paste my code into a console application and use a scheduled task to run it, it won't work; where is it supposed to pull the web and list references from? About the only helpful part is the last bit, where I'll have to extend the workflow tools to do what I want.
–
fbueckertJul 26 '12 at 19:46

1

Check out this question for the basic structure of accessing a SharePoint site and list from a console application. It also covers the common pitfalls of console apps & SharePoint.
–
LeviSJul 26 '12 at 20:25

@fbueckert My bad.. I wasn't sure how much you knew about console applications. I've edited my answer to include a link and an example. The example includes opening a SPSite, SPWeb, and SPList.
–
Kit MenkeJul 26 '12 at 21:20

I agree that a custom timer job is better suited based on the requirements in the question. The whole application then has context of both calendars, and will be more reliable.
–
RussellJul 30 '12 at 1:23

Once you remove multiple duplicate entries from your amalgamated calendar, you could do this using a SPD workflow that runs on the amalgamated calendar each time an item is added.

Below is the workflow map of an example I tried:

Step 1 First we set a variable to the ID of a list item that has the same 'OriginalID' as the current item. Be sure to set the variable to have a data type of number, otherwise we will not be able to use it in the expression in Step 2.

If no duplicates exist this will return the ItemID of our current item. If a duplicate does exist it will return the ItemID of the old item. If multiple duplicates exist it will return the ItemID of the first duplicate item it finds.

Step 2 Compare the value we just stored in the variable with the ID of the current item. If the ID in the variable is less than the current item's id it proceeds to step three.

Step 3 Delete the old entry from the list.

The one issue I see with this is if you are using only the ItemID for the OriginalID field in the amalgamated list. Because you are bringing in items from multiple lists, you could run into the situation where a new item has the same OriginalID as item from another list. To get around this, you could add another column called "SourceList" and use that along with OriginalID to find duplicates.

I can create a workflow to compare and eliminate duplicates; that's not hard. The hard part is that when the original item is created, it gets copied over to the amalgamated list. And since it gets copied over by System Account, I can't trigger OnItemCreate workflows on it. I do not believe that list workflows can delete items outside of their site collection, or trigger workflows outside of their site collection. If I could get either of those working, there'd be no problem. Otherwise, this would be a great way to go about it.
–
fbueckertJul 26 '12 at 19:24

I also think that using of workflow isn't the best solution to implement behavior described by you. The workflows should be used if you have some interaction with user or external service. Timer jobs works for you if you just need to perform some tasks at scheduled time. You can move all code needed to timer job and it will be run by SharePoint Timer Service automatically. Here is MSDN article where you can find some information and examples about timer jobs.

If you sill want to use workflow I think that the cause of getting null reference exception is in line:

using (SPWeb web = workflowProperties.Web)

You don't need to dispose Web property of SPWorkflowActivationProperties object. Disposing of this property is performing automatically by SharePoint itself.