Skip to content

SharePoint Workflow OnTaskChanged Invoked Event Sender Parameter Is Null

Just when you think you’ve seen it all, you run into something that makes you challenge what you think you know. Today’s SharePoint Workflow challenge was a bit of code that was behaving badly — but for reasons that didn’t make any sense. When I dug into it I found that my invoked method for a OnTaskChanged activity was null. In order to understand the importance of this fact I have to do a quick review.

In simple workflows the design time model and the run time model are the same. So you can have an activity named Foo and you can reference it with Foo in your code. That’s easy. The problem is when you introduce a loop, a replicator, or anything else that might cause activities to be replicated — and therefore you runtime model and your design time model no longer match. As soon as this happens you can’t use the activity name. You have to start referencing things based on the sender that your event receives as its first parameter.

I’m working on a parallel approval workflow which uses a custom sequence activity to hold the instance data for each instance of a replicator. To get to my instance information I walk up the tree from my sender to find my specific sequence activity which I know is the parent — and the activity that holds my instance data. This works great right up and until I don’t get my sending activity in the sender parameter. Without it I’m completely lost as to where I am in the workflow.

The solution is to add a code activity after OnTaskChanged and use the ExecuteCode event on the code event. This event will get its sender and can therefore locate itself in the hierarchy.

Replication, Workflow Serialization Problems and DependencyObject

I’ve been working on a workflow that needs to do parallel approval and therefore I have a replicator in the workflow. One of the things that I did was used the pattern of a custom sequence activity inside the replicator to hold the instance data. The custom sequence ends up with a custom property that is set by utilizing the ChildInitialized event of the replicator. You can see Tom Lake’s detailed explanation of this process in the forums: http://social.msdn.microsoft.com/Forums/en-US/windowsworkflowfoundation/thread/ca034011-d2f7-407b-90c5-d0303f753f50

I was using this to manage my set of tasks for the parallel approval. The problem is I was trying to be “nice” and use dependency properties in a class. So my SequenceActivity contained a reference to my class ApprovalTask. The ApprovalTask class contained the properties for the TaskId and TaskProperties (that are needed for managing a task.) To be nice I made these dependency properties which meant that I had to derive ApprovalTask from DependencyObject. To make a long story short, there’s something wrong with deriving from DependencyObject that causes the serialization of the workflow to get screwed up. If you do an OnTaskChanged in your workflow (which makes sense if you want to see if the task was approved or not) you’ll get an error similar to the following in the ULS:

Engine RunWorkflow: System.Workflow.Activities.EventDeliveryFailedException: Event “OnTaskChanged” on interface type “Microsoft.SharePoint.Workflow.ITaskService” for instance id “397f2b91-156c-4de2-b07b-6cae2fefd072” cannot be delivered. —> System.ArgumentNullException: Value cannot be null.     at System.Workflow.ComponentModel.DependencyObject.FixUpMetaProperties(DependencyObject originalObject)     at System.Workflow.ComponentModel.DependencyObject.FixUpMetaProperties(DependencyObject originalObject)     at System.Workflow.ComponentModel.Activity.FixUpMetaProperties(DependencyObject originalObject)     at System.Workflow.ComponentModel.CompositeActivity.FixUpMetaProperties(DependencyObject originalObject)     at System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity, IFormatter formatter)     at System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity)     at System.Workflow.Runtime.Hosting.WorkflowPersistenceService.RestoreFromDefaultSerializedForm(Byte[] activityBytes, Activity outerActivity)     at Microsoft.SharePoint.Workflow.SPWinOePersistenceService.LoadWorkflowInstanceState(Guid instanceId)     at System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(Guid instanceId, CreationContext context, WorkflowExecutor executor, WorkflowInstance workflowInstance)     at System.Workflow.Runtime.WorkflowRuntime.Load(Guid key, CreationContext context, WorkflowInstance workflowInstance)     at System.Workflow.Runtime.WorkflowRuntime.GetWorkflow(Guid instanceId)     at System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs)     — End of inner exception stack trace —     at System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs)     at Microsoft.SharePoint.Workflow.SPWinOETaskService.RaiseEvent(SPWinOeWorkflow workflow, SPWorkflowEvent workflowEvent, Object workItem, IPendingWork workHandler)     at Microsoft.SharePoint.Workflow.SPWinOeHostServices.Send(SPWinOeWorkflow winoeworkflow, SPWorkflowEvent e)     at Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(Guid trackingId, SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut)

The reason is because when ApprovalTask came back from serialization it’s SPWorkflowTaskProperties property was blank. The solution? Don’t derive from DependencyObject, mark my ApprovalTask as Serializable, and convert the properties into regular properties. This made the problem go away.

Mentions: K2 SharePoint Governance Series Interview

I had the pleasure of being interviewed by my buddy Chris Geier at K2 for a new series he’s starting on SharePoint Governance. You can find his introduction to the series here and the download for the interview here. Check it out.

XML, XPath, and Namespaces

One of the problems that I had early on with XML when I started was that I couldn’t figure out an easy way to handle namespaces when I was processing XML. SharePoint and other Microsoft technologies like InfoPath make extensive use of namespaces. For instance, if you right click a field in InfoPath and select Copy XPath you’ll get something in your clipboard that looks like: /my:TestForm/my:Repeating/my:Message –Frankly, that’s not all that complex of an XPath statement, except that it has a namespace in it. In this case we don’t know what “my” refers to. That made it easier for me to transform the XPath statement into /*[local-name()=’TestForm’/*[local-name()=’Repeating’]/*[local-name()=’Message’]. It’s frankly not that big a deal except that it’s somewhat tedious. This allows me to call XMLDocument.SelectNodes(string xPath) instead of XMLDocument.SelectNodes(string xPath, XmlNamespaceManager nsmgr) which was good because I didn’t have a namespace manager and I didn’t know how to create one easily. However, I ran into a new problem that my quick solution didn’t allow me to get around. I wanted to add a set of new nodes to an existing document — in that case I couldn’t ignore namespaces any longer.

After a bit of gnashing of teeth I realized that I can create a XmlNameSpaceManager pretty easily by looking at the attributes of my document element (DocumentElement) node. Take a look at this code:

XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);

foreach (XmlAttribute attr in doc.DocumentElement.Attributes)

{

if (attr.Name.IndexOf(“xmlns:”) == 0)

{

string prefix = attr.Name.Replace(“xmlns:”, “”);

string nsUri = attr.Value;

nsmgr.AddNamespace(prefix, nsUri);

}

}

In this snippet I use the document element attributes to create my namespace manager — thus I can use the same namespace prefixes as are in use in the document itself. (Forgive me for using .Replace() rather than .Substring() – I ultimately decided it was more readable.) Taking this scenario a bit farther, with the namespace manager I can create a node of <my:Message /> with:

XmlElement ele = doc.CreateElement(“my”, “Message”, nsmgr.LookupNamespace(“my”));

This abstracts out what the namespace actually is so that I can just reference the existing prefixes. With the element created I can set its InnerText property and then use XmlNode.AppendChild() to append the new element into my document.

Since it’s easy to create XmlNameSpaceManager objects now … I might have to forget my *[local-name()=’foo’] trick… although it’s still useful when I’m leveraging Xml editing tools and I don’t have namespace support in them.

MOSS Built In Site Column Table

I needed to get the site column IDs for some of the built in site columns and while there are several places on the Internet where you can find the technique for pulling them out of the URL when editing a field that was going to be a bit tedious for what I was going to do so I wrote a quick utility that would dump out the site columns to a text file. The resulting XLS file is available here.

I hope that it helps if you’re looking for a specific field IDs and you don’t want to URL decode them.

Moving SharePoint Development Forward – p&p SPG

One of the things I like best about my work is that I get to work with some great people doing fun and interesting things. I can honestly say that in our small part of the universe we manage to push the ball forward. I’ve had the pleasure of speaking at the SharePoint Best Practices Conference as well as other events – to try to share the things we’ve learned about how to develop scalable, maintainable, robust applications on the SharePoint Platform. One of the things that I have the most fun with is helping the Microsoft Patterns and Practices group put together their SharePoint Guidance. The first iteration we worked on basic collaborative applications. The second iteration (this one) we took a look at web content management scenarios and line of business integration.

Certainly I don’t expect that everyone can use all of the work that was done here – however, I expect that it’s more than worth your time to take a peruse through the materials. I know you’ll find at least one thing that you didn’t know or didn’t think of before. I know that because there were tons of things that I didn’t know about the platform – or hadn’t considered – that I learned.

Go check out the latest version of the SharePoint Guidance from p&p

hop

Hop to It

Marcy Kellar has been trying to convince SharePoint folks to jump for joy – or just because they’re intoxicated. So when Andrew Connell came up to do the SharePoint Users Group of Indiana (SPIN) she convinced a few of us to have our pictures taken. Despite not having anything alcoholic to drink, I decided to be a good sport and jump.

DPI is Danger

So twice in the space of a day I’ve been confronted by some dodgy information about DPI – Dots Per Inch – and about how it applies to the world. Let me first say, that I think that thinking about DPI is about the dumbest thing the desktop publishing industry has inflicted upon us. I say that because it’s a useless number on its own. Let’s say, for instance, that I scan something at 300 DPI. Can you tell me if it will fill a modern screen? No – you can’t. You can’t do that until I tell you how large the original scan was. If it was more than about 3 inches by 2.5 inches, it will fill a 1024×768 monitor.

The real answer when dealing with graphics is knowing how many pixels (individual dots) you need in order to fill the area you want to fill. DPI is the measure of the maximum resolution of the output in a given space. i.e. 300DPI means that you can fit 90,000 pixels in a 1″ square (300×300 = 90,000) If I want to be able to output at full resolution I need a file with a resolution of at least the number of inches times the DPI.

The good news is that people rarely talk about DPI when talking about digital photos … until someone with a desktop publishing background steps in the room. Digital cameras are measured in megapixels (or resolution not pixels per inch.) Occasionally you’ll hear folks talk about 72 DPI screen images – however, this is a misnomer on the PC since the resolution and screen size are not tightly coupled. My 15.4″ Lenovo laptops 1920×1200 screen has a different number of DPI than the 26″ external monitor I connect it to – but both have the same resolution.

Typically when you hear DPI, You heard about it from people talking about a setting for scanning. The interesting thing is that oversampling (scanning at a higher DPI than the output device could produce) can cause some real ugly scans – and some problems for trying to get an image to look right. If you know the resolution of the output device you should match that in order to get the best results. Having a bigger file with a higher resolution generally doesn’t do much harm – but it generally doesn’t do much good either.

So … PLEASE don’t talk about DPI. Talk about the resolution you need.

Things Look Different On the Way Down

For the last few days I’ve been riding ATVs with my friend Paul Thomas. I’ve been posting a smattering of photos on Facebook. The scenery has been beautiful but the trip hasn’t been just about the photos or the riding, it has been a chance for me to recharge and to reflect. During the riding I’ve noticed a few things that apply to my day-to-day in the grind professional world as much as they do to the riding.

Things look different on the way down. I don’t mean that from the perspective of falling from grace, but rather looking at things from the top just isn’t the same as looking at them on the way up. You just don’t see the same things. You sometimes see more and you sometimes see less. However, fundamentally, you’ll see something different. I can’t tell you the number of times over the last few days that I’ve completely missed something going up the trail and saw it plain as day on the way back down. You come around a corner that you had your back to and have to say “Wow!”

Here’s an extreme example of a different view on the way up vs. on the way down. Here’s the photo on the way up:

Here’s the same location from the top:

There’s a dramatic difference. From the top you can’t really tell what’s going on down there. The building looks like it is leaning but it looks like it is leaning back not forward and ready to roll down the mountain.

I bring this up because too many people believe that it’s impossible for the folks at the top to not see the problem. The problems of the organization seem so obvious for those who are there – how could anyone miss it. Well, hopefully as these photos have shown, it’s not that they don’t see the problem; it’s just that they see the problem differently.

So what do you do about it? Communicate. Help your manager understand what you’re seeing and accept that what they’re seeing is very different. You may not be able to see the situation from their perspective, but hopefully you can appreciate that they do have a different perspective.

This difference in perspective isn’t constrained to just management – different parts of the organization will see things from a different point of view and therefore have different concerns. Hopefully you’ll be able to see that they have different perspectives too.

Recent Posts

Public Speaking