Skip to content

Workflow Foundation Design Time and Run Time Activities – Knowing the difference

I was having some issues with a workflow I was developing. I had inserted some LogToHistoryListActivity activities that didn’t seem to be recording the correct values into the history list.  I was enlightened by Gabe Hall about something subtle in workflows that became obvious after he said it.

I was setting the HistoryDescription property of my design activity (in my case logToHistoryListActivity1) to the value I wanted.  The line looked like …

logToHistoryListActivity1.HistoryDescription = IterationNumber.ToString();

Great, except that this isn’t actually the one that’s running.  Because the activity was in a loop WF was doing some special magic to make multiple copies of my activity.  What I found that I could do instead is take the sender parameter of the event, cast it to a LogHistoryListActivity and use that instead so the snipit becomes…

LogToHistoryListActivity log = (LogToHistoryListActivity) sender;
log.HistoryDescription = IterationNumber.ToString();

The net result is that I now get the properties of the specific instance set correctly.  This is definitely something to think about if you’re putting activities in repeaters, loops, etc.

I was cautioned that sometimes the sender might be null and in which case I’d have to locate the correct activity in the tree manually.  However, casting the sender has worked fine for everything I’ve tried thus far.

A few things you should know about CreateTaskWithContentType in SharePoint Workflow

Here are a few things that you should know when working with the CreateTaskWithContentType activity in a SharePoint workflow.

1)      If you don’t enable ContentTypes in the task list you’re get a null reference exception (from the activity itself, not your code.)

2)      The ContentType that you specify in the ContentType property isn’t automatically associated.  You’ll want to verify the content type exists in the _MethodInvoking() event.  You could call the code below to automatically enable content types and if necessary add the contentType:

/// <summary>

/// Verify — and if necessary modify — the task list to ensure that the required fields are available.

/// </summary>

/// <param name=”taskList”>The list to be verified</param>

/// <param name=”contentType”>The content type id to add</param>

public static void VerifyModifyTaskList(SPList taskList, string contentType)

{

try

{

SPContentTypeId contentTypeId = new SPContentTypeId(contentType);

 

taskList.ContentTypesEnabled = true;

SPContentTypeId matchContentTypeId = taskList.ContentTypes.BestMatch(contentTypeId);

 

if (matchContentTypeId.Parent.CompareTo(contentTypeId) != 0)

{

SPContentType ct = taskList.ParentWeb.AvailableContentTypes[contentTypeId];

taskList.ContentTypes.Add(ct);

taskList.Update();

 

}

}

catch

{

throw;

}

}

3)      You can’t test for whether a content type is associated with a list or not by its “short” identifier directly.  You have to use the .BestMatch method as shown above to determine whether the content type is associated or not.

Turning a GET into a POST for SPWorkflowManager.StartWorkflow()

I mentioned in a previous post that you must run StartWorkflow on a POST request and not a GET request but I didn’t have time then to figure out how to do this quickly in a web part…  Here’s how to do it…  In any WebControl (or anything that can be to the Page object) add the following line.

this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), “post”, “<SCRIPT Language=\”JavaScript\”>\n<!–\ndocument.forms[0].submit();\n–>\n</SCRIPT> “, false);

This will cause the page to post back to itself once it’s loaded.  It’s a kluge, but it solves the issue

Making a Custom Activity Work in Your Project (even if you started with a class library)

Most of the time when I’m developing and I have to learn something new – a new API, a new event model, etc. – or I just need to try something that I don’t know whether it will work or not I create a new project (often with a name that begins with the prefix of TEST).  These projects are where I prove out the technology before integrating it with the core code of the project.  The test project always gets cataloged into a special place in the source control system, and rarely gets directly moved into the main project.

However, every once in a while I guess right and I put together a technology proof (test if you prefer) that works like I want the production to work like.  Today was one of those rare days when I created a new Workflow Activity the way I wanted it.

After I got it checked in I did a bit of source control work to share the test code over to the core project so I could include the files.  (I branched after the share so the files are now on their own unique paths.)  I added the working activity to my core project and… it didn’t work.  I got this really ugly error when I tried to open the design surface for the activity.  It said in part:

The service ‘System.Workflow.ComponentModel.Design.IIdentifierCreationService’ must be installed for this operation to succeed. Ensure that this service is available.

After I stared at the screen wondering how to figure this out, searched for answers (and came up with nothing), I started looking into the project file and found that there are two necessary pieces to make the workflow designer surface to work.  The first entry that’s necessary belongs in the <PropertyGroup> and is:

 <ProjectTypeGuids>{14822709-B5A1-4724-98CA-57A101D1B079};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>

Basically, it’s saying that it’s a workflow project and it’s a C# project.  If you’re using VB, create a new custom workflow activity then open the project file in notepad and you should see a different ProjectTypeGuids node that you can use.

The second part is an import statement that just goes inside of the root <Project> node.  It is:

<Import Project=”$(MSBuildExtensionsPath)\Microsoft\Windows Workflow Foundation\v3.0\Workflow.Targets” />

Adding these two entries to your project file makes the workflow extensions work in Visual Studio and can make your custom activity work – even when you started with a standard class library.

Workflow Custom Activity Events

Nearly every example of how to create a custom workflow activity demonstrates the use of the DependencyProperty.  There’s not much new there.  However, few of the examples will show you how to add events to your custom activities.  It’s not that difficult really, they’re still dependency properties with a bit of a spin.  For instance, if you want to implement a MethodInvoking event you can use the following code:

public static DependencyProperty MethodInvokingEvent =

DependencyProperty.Register(“MethodInvoking”, typeof(EventHandler), typeof(NetSendEmailActivity));

 

public event EventHandler MethodInvoking

{

add { base.AddHandler(MethodInvokingEvent, value); }

remove { base.RemoveHandler(MethodInvokingEvent, value); }

}

This should look really similar to the structure of a regular DependencyProperty – because it is.  Other than the non-static property and the name of the Dependency property, everything is the same.

For a full fledged example you can look at “Send E-mail Activity Sample” in MSDN.  (This isn’t a complete replacement for the SharePoint SendEmailActivity to resolve the issues mentioned in my previous post, but it’s not a bad start.)

SharePoint SendEmailActivity

I’ve recently stumbled across to pretty important limitations of the SendEmailActivity in SharePoint…

1)      The From property of the SendEmailActivity doesn’t actually do anything.  The message is always sent out from the SharePoint Server’s configured email address.  Setting the From property of the activity won’t change where the message appears to be coming from.

2)      The SendEmailActivity doesn’t support attachments.  As a result you can’t send the item to which the workflow is attached to workflow participants who are not on the system.

If you need either of these functionalities – you’ll have to develop your a SendEmailActivity replacement on your own.

Software Craftsmanship: The New Imperative

Book Review-Software Craftsmanship: The New Imperative

I struggle to find the right way to express how to make software development right.  I can’t say that I subscribe to every idea that is put forth by Software Engineering.  The Software Engineering Institute does drive software development forward.  However, having had the opportunity to listen to a few of the speakers that work for the SEI, I can’t say that I feel like they’re in touch with reality.

The appealing thing about this book, Software Craftsmanship- the New Imperative, is the opportunity to take a different perspective towards software development.  I’ve always felt in some ways that building software was about getting a feel for the users, the technology and making them come together.  The idea that you don’t build software you craft it is certainly appealing.

The whole book puts forth the idea that we think about software wrong.  We take the few examples of large projects and expect that the experiences gained there will apply to every software project.  There have been numerous observations that the software development practices that we know, from these observations, lead to better software are routinely ignored or not followed.  Although there are many reasons for this, the reality is that we don’t do what we are taught to do.

The other end of the spectrum is the apprenticeship model that’s practiced in many other professions either from a formal structure or informally. Most trade professions have some sort of a process from taking apprentices and making them into professionals.  This is an approach that the author proposes we should be doing with Software Development.

In my own experience, I can say that both are needed – and the idea of software as a craft is widely under discussed in professional articles and books.  Despite this it’s the primary way that I teach, and learn, about software development and how to make it better.  As a coach and mentor I train developers to remember to watch error handling, to test, to think about boundary conditions, to care about the resulting code, and all of the things that make up good software.

They learn not through the one time reading and single verbalization of these ideas but through the continual reinforcement of the ideas and the continued application of the ideas to their work.

I learn through work with my colleagues.  They teach me their approach and I teach them mine.  Whether I alter my approach or they alter their approaches, we’re both better for the exchange.

The book is somewhat repetitive in places and over the top in others, however, it’s a good read if you can put aside the details and focus on the core message and evaluating it against the way that you do software development today.

GETting SPWorkflowManager.StartWorkflow()

Sometimes when you start a workflow you need to collect information user in order to make sure that the workflow has all of the information it needs to start.  Perhaps it needs to know the people to send the document to for approval, or perhaps it’s something simpler like the due date.  That’s what the workflow initiation form is for.  It’s designed to capture the data necessary to get a workflow going.

However, what happens if you already have all of the information that you need to start the workflow.  The user has entered a due date into a field in the item, or you’re fetching the list of approvers from a third party system.  When you hit the workflow initiation page you’re ready to start the workflow and move on – without prompting the user.  The net effect is that they only see the initiation form when they need to provide information or confirm something which is ambiguous.

This a great idea, but out of the box with SharePoint and Workflow it won’t work.  You’re going to have to do a workaround.  There’s a design limitation that prevents you from calling the StartWorkflow() method of the SPWorkflowManager from a HTTP GET.  It only expects to be called from a HTTP POST and because of that you won’t be able to directly start the workflow even if all of the information is available to you.  If you’re thinking that you should be able to do it if you use SPSite.AllowUnsafeUpdates – you’re right you SHOULD.  However, it doesn’t work that way.

The work around is to cause the form to post back to itself, say through JavaScript.  You’ll end up with one more round trip between the browser and the server, but it will allow you to effectively hide the workflow initiation form when the user doesn’t need to enter any information.

electricity

Article: Empower Your SharePoint Power Users

How much energy have you invested in supporting SharePoint? Have you been asked to help add a column, define a list, or share some advice on the best way to do something in SharePoint? If you have, you’re not alone. What you need is an army — an army of people who can spread the load so that, instead of dozens of questions, you rarely get one at all. Enter the power user. This is a mythical creature of dread for some organizations and a champion of IT in others. When enabled correctly SharePoint power users can give all of the users better support and simultaneously reduce your load building solutions and answering questions. Here’s how to do it.

http://mssharepoint.advisorguide.com/doc/18690 [Website removed]

I’ve been Assaulted (Tagged) someone call someone else who cares

I’ve been assaulted… more precisely tagged by fellow MVP Todd Klindt.  I’ve been thinking about The Wizard of Oz and the quote “Are you a good witch or a bad witch?” I generally detest engineered attempts to get to know other people – particularly at company parties.  But I’ll oblige so here goes…

  1. I’m a pilot – who never flies.  That’s not quite true.  I am a licensed private pilot – something I had always wanted to do but I’m finding that time and money never seem to intersect in ways that allow me to enjoy much of it.  My brother is an Airline Transport Pilot – so occasionally I find some time to go flying with him.
  2. I take pictures too.  One of my attempts to make some money is taking pictures.  My IStockPhoto profile has got a few of the things that I’ve published.  I take the camera with me most places these days and try to disprove the belief that taking digital pictures doesn’t cost anything.  If you take enough of them you have to have a budget for the DVD archival of them.
  3. I’m the (volunteer) technical director for Hazel Dell Christian Church.  If you’ve been to a contemporary Christian church you may or may not have noticed all of the technology making the experience immersive.  Sound reinforcement, video projectors, cameras, computer controlled lighting, closed circuit video distribution, etc., are all there to make sure that attendees don’t notice that they are there.  (Sounds paradoxical doesn’t it.)
  4. I recently mounted a laser illuminator to an air rifle.  I have two dogs that are not able to climb trees and get squirrels – and the squirrels know it.  I’ve decided to even the odds a bit (or tip the balance of power you decide.)  I don’t yet have a good kill ratio but I’ve definitely reduced the amount of time that the squirrels sit in the trees and bark.  And yes, I know that an air rifle doesn’t have any accuracy so mounting a laser illuminator to it is like trying to strap a rocket to a Pinto.
  5. I’ve forgotten what I’ve written.  There’s been more than one occasion where I’ve went looking for information and one of the links that came up was one of my own articles.  I used to get annoyed now I am just glad I can find it so I can move on and do something else.  Most of what I’ve written or edited is either in my MVP profile or on my book listing.

So, the folks that I’m tagging are:

Recent Posts

Public Speaking