December 2008 Entries

Today, I spent some time trying to fix an error with a Standard OOB workflow for content approval.
Root-Cause:
Someone removed the Approvers group from the site collection SP Groups.
Thankfully, SharePoint told me that "An error has occured in Parallel Approval." - Thanks.

When looking over the settings for the workflow in the document library, I saw that Approvers was the group selected, and didn't think much of it, as the role "Approve" was assigned to another group "Site Approvers".
The thing I did not notice, was that the name was not underlined, as it should be when an actual group is selected.

So I dove into the log files and uncovered the following:
Date Time w3wp.exe (0x0AF8) 0x14B8 Windows SharePoint Services Workflow Infrastructure 88xr Unexpected WinWF Internal Error, terminating workflow Id# a5412b24-39cc-4820-83fd-5214122db003 Date Time w3wp.exe (0x0AF8) 0x14B8 Windows SharePoint Services Workflow Infrastructure 98d4 Unexpected System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.Office.Workflow.ReviewRouting.ValidateUser(Contact contact, String& email, String& reason) at Microsoft.Office.Workflow.ReviewRouting.MakeTaskData(Contact assignedTo, String description, Int32 taskType, String taskTitle, Int32 linkedTask) at Microsoft.Office.Workflow.ReviewRouting.OnActivate(Object sender, ExternalDataEventArgs e) at System.Workflow.ComponentModel.Activity.RaiseGenericEvent[T](DependencyProperty dependencyEvent, Object sender, T e) at System.Workflow.Activities.HandleExternalEventActivity.RaiseEvent(Object[] args) at System.Workflow.Activities.HandleExternalEventActivity.Execute(ActivityExecutionContext executionContext) at System.Workflow.Component... Date Time* w3wp.exe (0x0AF8) 0x14B8 Windows SharePoint Services Workflow Infrastructure 98d4 Unexpected ...Model.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext) at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(Activity activity, ActivityExecutionContext executionContext) at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime) at System.Workflow.Runtime.Scheduler.Run() Parsing this mess, "at Microsoft.Office.Workflow.ReviewRouting.ValidateUser(" ...

so, there was obviously a problem with a user, and so I went back to my Site Collection, checked, and WOW! The default Approver group was ... missing.
Back to the start, asking around, I find out that about a month ago, there was a "cleanup" of user permissions on this site collection.
Oh Great! Why does anyone cleanup permissions on the root site collection of a whole intranet, without letting the staff of people that try and maintain the SharePoint farm know. (I have since removed these users from being able to manage several groups).

Anyways, the fix:

Browse to your document libraries that use the approval workflow.
Under Settings, Document Library Settings, Permissions and Management, Workflow settings


Click on the workflow (Parallel Approval in my case) and click next to go to the second screen, no need to make changes to the settings.


On the second page, there is a section "Default Workflow Start Values" and there is a selection for an Approver group. Change this BACK to a group that exists on your site, and your workflow should be working again.



Oh man what fun, I hope this helps save some time down the line for others.

Cheers!

I am going to the Atlanta MDC, which is a summary of PDC, tomorrow. I have seen some screen casts of items that will be covered, but it should be informative and fun to be surrounded by other MS developers. I will let you know how it goes!

I am currently working on a custom expiration policy, the client wants to expire(recycle) documents after 1 year, with a 3 month window for a workflow to notify the document owner, and user who last modified the document, of its expiration. The user(s) can simply click extend in a workflow form and update the list item's last modified date to extend the item expiration for 1 more year. Those are the loose requirements.

There are SEVERAL options here, there is a custom Retention Formula, Custom Action, and as always a Workflow.
The basics, go to Site Collection Settings, (yes, the policies are Site Collection wide)
Then Site Collection Policies

There are a bunch of great things here, Auditing, Expiration, BARCODES!!! Anyways, you can read about the standard OOB stuff from the MS site, or other blogs. I am going to stay focused on the simple/advanced customizations.

All of the Policy items you want to use are in the Microsoft.Office.RecordsManagement.PolicyFeatures Namespace, so you will need it included in your project.

If you want to send out an email warning BEFORE the item expires, you should create a custom Retention Formula, but the downside is that now your site collection administrators cannot change the retention time. In my case, it is a new corporate policy to reduce storage, so that is fine. (Just be aware)

So, you will need to create a class that implements IExpirationFormula

When you implement the interface, you will receive a method called ComputeExpireDate(), In here, you are going to determine your date and return it for normal expiration flow, you can start simple, return DateTime.Now! or convert item["Modified"] to a DateTime, and Add one year, etc. Now, we have a custom retention date set to 1 year after it was last modified. (You can also do Published, etc.) and we want to send an email, warning a couple users, In the method, before we hurry up to return the date, can check to see if the date is within a month of expiration, if so, send a couple emails, one to a custom site column we use here for Document Owner, and also the last modified by user. Both in my case are SPUser objects, with Email set, and we send out an email stating that it will be deleted, and we add an entry to a list that warning email has been sent, so that we do not send an email every day. The job running that calculates expiration (SPTimer Job) should be running once a day by default (OOB). You might look to update this job to run more often in dev, so that you can see results more quickly than 1 day!

Now, we have a retention calculation that will expire documents 1 year after last modified, and a warning sent 1 time, 1 month before expiration.

Back to the policy page in Site Collection Settings, the next thing is a custom action, which you might have run into on the MSDN page already, but simply put, we are going to impliment the IExpirationAction interface. When you impliment this interface, you will get a single method OnExpiration(), and you guessed it, just put your goodies in there. In our case, we want to just recycle the document, calling item.Recycle() will take care of our requirements, and we send an eamil out to our users that it has been recycled... etc. If you needed something else there, obviously just drop in what you need.

Finally, the third option, is to use a custom workflow as the action instead of a simple action. In our case, we also have a simple workflow that the owner and last modified by user get assigned a task, so that either can "extend" the expiration for another year. I created a simple InfoPath form with extend, or ignore, where the user can also simply ignore, and let the document expire. If both users ignore, or 30 days pass, the document is recycled. I am not a Workflow expert, but you can see David Mann's site, he is what I would call an expert, even if he doesn't! Anyways, I take care of the initiation and initial assignment from the item properties of Owner and Modified By when creating some initial tasks, one simple InfoPath form to perform the extend or ignore option.

I packaged these into a feature (with a simple receiver to turn on three features, the Workflow, Custom Retention, Custom Expiration Action) when activated allows a Site Collection Admin, to choose the options they want. They then can use the custom retention to send email warnings, select either the direct recycle, or the workflow. Lots of options, good fun, and as always lots to learn, and I would also like to mention that the Workflow will always take longer than expected, as they are JUST time consuming to get working just right.
I was working on a bug in a CAML query to return items from a list of news entries, and discovered, that when using the U2U CAML tool to update a query it removed my IncludeTimeValue=”TRUE” attribute.

This one snuck back into a release, but thankfully got tangled up in a regression test.

Thought I would post on it, as people might miss it if using the tool, and also as a reference.

You can also see, I use SPUtility.CreateISO8601DateTimeFromSystemDateTime() to Get a valid time for my query, I have seen others that use in place, but in my case, I use a passed in date value, or + 10 days.

System.Text.StringBuilder QueryBuilder = new System.Text.StringBuilder();

QueryBuilder.Append("<Where>");
QueryBuilder.Append("  <Leq>");
QueryBuilder.Append("    <FieldRef Name=\"StartDate\" />");
QueryBuilder.Append("    <Value Type=\"DateTime\" IncludeTimeValue=\"TRUE\" >" + SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now.AddDays(10)) + "</Value>");
QueryBuilder.Append("  </Leq>");
QueryBuilder.Append("</Where>");


Hope this answers a few questions.