Dedicated to development, configuration, and tips and tricks for both WSS 3.0 and MOSS

Posted by Aaron Varga on Saturday, 31 Jan 2009 01:38

I’ve been waiting for this for a couple months after an announcement was made that it was going to be released, and finally today the SPDisposeCheck tool has been released!  The tool reviews a .NET Assembly (DLL or EXE) and evaluates SharePoint API's used in that assembly. It will produce a report identifying where code doesn't follow best practices for memory management in SharePoint.

To test this out, I created a simple console application that contains undisposed SharePoint objects:

static void Main(string[] args) {
    SPSite siteCollection = new SPSite("http://server");
    SPWeb site = siteCollection.OpenWeb();

    // do something
}


As you know, you must always be sure to dispose of your SPSite and SPWeb objects, as this can lead to expensive memory leaks.  If you’re not a seasoned SharePoint developer, this may not be obvious to you, and for this the SPDisposeCheck tool is a huge asset.  I ran the following command after downloading the tool:

SPDisposeCheck.exe C:\Projects\Test\Aaron.TestApp\bin\Aaron.TestApp.exe

Which produced the following:

image


You can see that 2 errors were found.  Specifically, this tool points out the following for the first error:

Disposable type not disposed: Microsoft.SharePoint.SPSite
***This may be a false positive depending on how the type was created or if it is disposed outside the current scope


This tells me that my SPSite object needs disposed. The second error is exactly the same thing, except in reference to SPWeb.  Let’s clean up the code, this time disposing of our objects:

using (SPSite siteCollection = new SPSite("http://server")) {
    using (SPWeb site = siteCollection.OpenWeb()) {
        // do something
    }
}


Now, when I run this tool I get the following:

image

 

There’s a pretty good chance that if you’ve even made it this far in this post, that you’ve written SharePoint code before, and already know to always dispose of your SPSite/SPWeb objects.  However, what about the less obvious examples.  I ran this tool on an assembly I’m currently developing for a client, and I got an error:

Notes: Dispose/Close was not called on SPLimitedWebPartManager.Web


I went back through my code, and found this line:

SPLimitedWebPartManager manager = defaultPage.GetLimitedWebPartManager(PersonalizationScope.Shared);

Basically this gets the web part manager for a specific page, so you can add/delete/modify the web parts that are on it.  Why is this throwing an error?  I’m not using an SPSite OR an SPWeb anywhere!  It’s because there’s a very non-obvious memory leak in this that creates its own SPWeb object, and this object needs to be disposed.  The correct usage of this is:

using (SPLimitedWebPartManager manager = 
defaultPage.GetLimitedWebPartManager(PersonalizationScope.Shared)) { // do something if (manager.Web != null) manager.Web.Dispose(); }


Not at all obvious, but I’m glad this tool caught it!  PLEASE, if you are writing Object Model code, run this tool.  For a ton more information on SharePoint Dispose() patterns, Roger Lamb’s post is by far the best one out there.  Also check out this MSDN article.

You can (and really should) download this tool here.

Posted by Aaron Varga on Tuesday, 27 Jan 2009 05:04

Once in awhile you’ll find a need to add little widgets or utilities to your SharePoint page, such as the weather, and RSS feed, or some other eye candy.  While they don’t offer a ton of great functionality, they’re often pleasing to the users’ eyes and may make for a better web experience.  Luckily there are a ton of these types of components floating around the web, including ones from Google Gadgets or WidgiPedia.

Since these are usually just a link to a JavaScript file and some HTML, the Content Editor Web Part can be used to display these on your SharePoint page.  For example, I added a couple lines of code from here for a clock:


image


How about weather?

image


Or even a formatted RSS Reader?

image


And if you need a break from productivity, add a game or two :)

image


Google Gadgets is a great place to find hundreds of these, but there are a ton of other places to get these as well, and many of them may actually be useful, and not just pretty eye candy!

Posted by Brian LaSitis on Tuesday, 27 Jan 2009 02:10

For most production SharePoint deployments that involve custom .NET code, such as custom developed web parts, controls, event handlers, etc., best practice dictates that any shared assemblies should be deployed to the Global Assembly Cache (GAC).  While this is a great practice, the GAC location (e.g. %WINDIR%\Assembly) does not behave like a typical folder, or at least doesn’t appear to, and for most .NET developers, the GAC in general is somewhat of a mystery.  One of the biggest perplexities with the GAC is that upon first glace, there does not seem to be a means for retrieving a copy of an assembly that is deployed to the GAC.  While all of us have probably dragged a .NET assembly into the %WINDIR%\Assembly folder to add it to the GAC, if you try dragging an item out of the GAC, it does nothing, and the familiar Cut/Copy/Paste operations that are standard on any Windows Explorer folder view are grayed-out.  How dare you do this to us Microsoft?!

In the sections below I will explain how you can retrieve the actual DLL for an assembly that is only deployed within the GAC, and in the process, we will make some sense out of how the GAC actually works and see how it really is just a specialized folder hierarchy for storing .NET assemblies.

The Uniqueness of the %WINDIR%\Assembly Path Location

If you open a Windows Explorer to the %WINDIR%\Assembly path location, you are presented with a specialized view of this folder, as shown below:

image

This unique view is the result of a Windows Shell extension called SHFusion.dll (as an aside, the reason for this name is the original codename for the GAC, when the .NET Framework was first being developed, was Fusion).  However, if you open a Command Prompt and switch to the %WINDIR%\Assembly path, you see a slightly different listing:

image

The reason for the Command Prompt displaying this view, as opposed to what Windows Explorer shows, is that Windows Shell extensions are not applied to file operations performed from the Command Prompt.  Here we are presented with seven (7) folders, each of which is explained below:

  • GAC – stores .NET 1.x assemblies
  • GAC_32 – stores .NET 2.x+ assemblies that are built specifically for 32-bit architecture.
  • GAC_MSIL – stores .NET 2.x+ assemblies that are architecture independent, meaning they can be used on 32- or 64-bit systems.
  • NativeImages_Vx_Architecture – there can be multiple folders of this format, specific to each version of the .NET Framework present on the system, with possible 32 and 64 bit flavors of each.  Each of these folders is used for storing native images of .NET assemblies that have been pre-compiled using NGen, to eliminate the need to run the MSIL code through the JIT compiler at execution time.
  • temp, tmp – temporary folders.

Additionally, on a 64-bit system, one additional folder would be present:

  • GAC_64 – stores .NET 2.x+ assemblies that are built specifically for 64-bit architecture.

To determine which folder the assembly you seek is within (e.g. GAC, GAC_32, or GAC_64), refer to the Processor Architecture column within the Fusion-based Windows Explorer view.  Let us consider an example:

Assume we would like to retrieve the DLL for the Contoso.Website.Controls assembly, shown in the Explorer view above.  As we can see, the Processer Architecture indicated is MSIL, indicating that this assembly will be within the GAC_MSIL subfolder, if we proceed to descend into that level, we see the following:

image

At this level, we have a subfolder for each assembly, so let us descend into the Contoso.Website.Controls subfolder, to see the following:

image

At this level, we see folders with names based upon the version of the assembly, culture (if not invariant), and public key token.  It is this exact folder structure the enables the GAC to store multiple versions of the same assembly without one overwriting or conflicting with the other.  Since there is only one subfolder present at this level, let us proceed to descend into it, to see the following:

image

Voila!  At this level, we are able to take a copy of the exact DLL file that was deployed to the GAC.  What was a pleasant surprise to me is that the GAC does not in any way mangle the original name of the DLL that was deployed.

Disabling the SHFusion.dll Shell Extension

There is another option of seeing the actual folder structure of the GAC that does not involve the command-line, but I would not recommend doing this on a production system.  To view the same folder structure within Windows Explorer that we were able to navigate through using the Command Prompt, we can disable the SHFusion.dll shell extension using one of three possible methods:

  1. Rename %WINDIR%\Assembly\Desktop.ini – within %WINDIR%\Assembly, a hidden, read-only, system attributed file named Desktop.ini is present.  By renaming this file to something else, such as Desktop.ini.bak, we effectively prevent SHFusion.dll from loading for this folder.
  2. Add the DisableCacheViewer Registry Value – within the HKLM\Software\Microsoft\Fusion registry path, a new DWORD value can be created with the name DisableCacheViewer and a value of 1 to prevent SHFusion.dll from being loaded.
  3. Rename SHFusion.dll – the SHFusion.dll itself can be found within %WINDIR%\Microsoft.NET\Framework\v.XX, and if this file is renamed, it will not be loaded when Windows Explorer is pointed at the %WINDIR%\Assembly path.

By performing any one of the above steps, upon opening %WINDIR%\Assembly the next time, you will be presented with the following view, similar to what we saw within the Command Prompt dir listing above:

image

So there you have it – the biggest mysteries of the GAC have all been dispelled:  how its path location works within Windows, its unique rendering method within Windows Explorer, how it actually stores DLLs you deploy to it, and how you can retrieve them later.  So in reality, all the GAC truly is made up of is a specialized folder hierarchy for tracking multiple versions of assemblies, independent of processor architecture, that has special .NET CAS policies defined for it to allow assemblies deployed to this location to have Full Trust permissions.  Now go forth, fire up your compilers, and start deploying code to the GAC!

Posted by Mike Porreca on Monday, 26 Jan 2009 07:51

Welcome to the SharePoint Developer Blog! This blog is dedicated to SharePoint Development, SharePoint Configuration, and SharePoint Tips and Tricks, all involving Windows SharePoint Services 3.0, Microsoft Office SharePoint Server 2007, and associated tools, for use in an on-premise or hosted environment. For content related to end-user topics, tips, and tricks, visit the blogs at blog.sharepointhosting.com.

Posted by Mike Ursta on Monday, 19 Jan 2009 03:49

MOSS 2007 brings to you the ability to retain information about business documents so they can be tracked and recorded.  Many businesses require or have policies that pertain to company documents.  The MOSS Record Center gives us a repository that allows for custom policies to delete and archive documents.  It also lets us audit things like who viewed, deleted, or updated the document.  All in all, it is a perfect way to make sure historical content is maintained and not lost over years.  The following scenario is an example of how a business could set up a record repository for their company documents.

For simplicity lets start out with a site called Purchases that is a site where the company stores all their Purchase Orders in a Sales document library, and all their receipts in a PO Receipts document library.

 

1

 

One thing to think about when you are going to manage documents is what is going to be the best way to track these documents.  This would be to assign metadata to them.  Therefore, I created a content type called Purchase Orders, which I applied to the Sales Documents library.  Included in this content type are two default document columns, Name and Title, and three custom columns, Cost Center, Fiscal Year, and Product.  These columns will allow for better search results and records management.  It will also give more meaning to your documents.  You will also be able to use these metadata field values in your Information Rights Management Policies, which I will explain later.

I also created a content type called Receipts, which has the default column Title, and a custom column PO Number so it can be tied to a PO.  I added this content type to the PO Receipts document library.

 

2

 

3

 

For these Sales documents, we want to be able to retain historical information and audit activity.  For this we will create a records repository for these documents and any others we would like to retain information for.  It is recommended that you create a new web application for your record repository, and the reason for this is so you have a totally separate site to manage documents for your company.  Also, it would make sense to have this site in its own content database because with all the documents and all the versions for these documents, the record repositories can tend to grow fairly large.  For simplicity of this demo, we will just create a sub site under our Purchases site called Records Repository.  Do this by creating a new site and choosing the Record Center Template.

 

5

 

After the site has been created, it will look like this:
(Note: I have a different theme. That is why the color is different)

 

6

 

After we have created our site, we will need to create a document library to store our Purchase Order documents that we want to store in the the repository.  This is not something you have to do, but if you don't, the documents will go into the Unclassified Records library.  Therefore, I created a document library called Purchase Orders.

 

7

 

Now, to keep this document library consistent with the library it will be getting documents from, which is the Sales Documents library in the Purchases site, we will want to add the Purchase Orders content type to this document library as well.  Now if you didn't add the content type, the documents will still get routed, but you will not see the metadata in the document library list.  You would have to look in the XML file that gets associated with the routed document.  It is located in a properties folder stored with the document.  Now since my repository is located in the same site collection as my Purchases site, I will be able to easily add the Purchase Orders content type, if it was not in the same site collection, I would have to recreate the content type for this site.

 

8

 

Now that we have added our content type to our Purchase Orders document library, we are ready to create a record in the Record Routing list.  This will route our purchase orders to the correct document library.  If we do not create a record, all the documents will get routed to the Unclassified Records document library.

 

9

 

Routing items works off of content types.  In the item I created below, you will see that I give the item a name, a description (optional), a location (document library the documents will be routed to), and an alias.  The way I have it set up now will route two types of documents.  Documents with the Purchase Order content type, and documents with the Receipts content type.  So how does this know if the document content type being routed matches those two types.  Well, since the Purchase Orders document library has the content type purchase orders associated with it, all purchase order content type documents will be routed to there.  Now, if you are routing documents of another content type, such as receipts, which is not associated with the Purchase Orders document library, you have to add that content type name to the alias section of the routing item so it knows where to put documents with the receipts content type.

 

10

 

Now that we have our document libraries and our routing item configured, we want to set up an Information Management Policy because we want to get useful information out of our stored documents.  We do this by going to the Purchase Orders document library settings and click on Information management policy settings.

 

11

You will now come to a list that has the content types associated with this list.  You will need to click on a content type to set up a policy for those documents.

 

12

 

Choose to Define a policy.

 

13

 

Lets begin to define our policy.  The name will be automatically populated since we chose to define a policy for the Purchase Orders.  The description is just for administrative use (Not Required).  The policy statement will be displayed to users when they open the document.  You can also enable labels.  These labels will be printed when you print the document.  Earlier I mentioned that we would be using the metadata to perform special tasks with the documents.  In my label, you will see {Product}.  This will automatically pull the information in the Product metadata for the document and print it on the label.  It is a pretty neat feature!

 

14

 

You can also style the output of your label and preview it.

 

15

 

Lastly we can configure auditing, expiration, and barcodes.  The auditing feature generates reports to give us statistics on the actions listed below.  It works similar to the site collections auditing feature.  The expiration allows you to either delete a document after a specific time, or set up a workflow to perform a certain action after a specific time, such as moving it to an archive.  Lastly, barcodes can be added to documents.  This will give documents a unique identifier that will allow documents to be easily identified when they are uploaded or printed.

 

16

 

Ok, we have finally finished configuring our record repository.  There is only one last thing to do before we can start routing documents.  We have to go into Central Administration and set the URL of our record repository to create the linkage so we can send documents from our sites to the repository.  To do this, go into SharePoint Central Administration > Application Management > Record Center (Under External Service Connections).  You cannot see it in this image, but the URL you need to use to connect to the records repository is your http://sitename/_vti_bin/officialfile.asmx. So in this demo, my URL is http://pit-moss01v/sites/RecordsDemo/RecordsRepository/_vti_bin/officialfile.asmx.  Lastly, add the name that will show up when you go to send a document to the repository.

 

17

 

Now that everything has been configured, we can test sending a document.  To send a document to the repository, hover over a document the Sales document library and click the down arrow.  Next, hover over Send To, and click on Record Center.

 

18

 

You will get this message if the document was sent successfully.

 

19

 

Once you send the document, look in the Purchase Orders document library in the records repository.  You will see a folder.  These folders are set by which month and year you sent the document.  All of the documents I send during December of 2008 will go into this folder.  This is done to avoid the SharePoint limit that only allows for 2000 documents in a folder.  It also allows for better performance when opening the library.

 

20

 

At this level, you will see all the documents for the that month.

 

21

 

If you click into the properties folder, you will see corresponding xml documents that list all the properties for the routed documents.

 

22

 

Finally, after all is said and done, and users start using the records repository, the site collection administrator can begin to monitor the activity by looking at the audit reports.  At the top level of the site collection, go to Site Actions > Site Settings > (Under Site Collection Administration) Audit Log Reports.

 

23

 

There you go.  This might have been a little lengthy, but if you took the time to try it out, you will see how powerful of a tool Records Management can be!

Posted by Aaron Varga on Thursday, 15 Jan 2009 08:47

For the most part, any workflow we build will involve participants that have access to the respective site, and won’t involve external users, or users that don’t have permission to the site.  A client pointed out a blurb in a TechNet article that mentioned you can allow non-authenticated users to participate in a workflow, and I had never heard of that, so of course I had to find out what it was all about.

MSDN mentions that by enabling this option, you can allow either or both of the following types of non-authenticated users to participate in workflows: internal users who do not have access to the site and external users who do not have access to any internal network resources. For internal users, an email message is sent that explains how to request access to the site (subject to administrator approval). For external users, an email message is sent with an attached document or list item for the participant to review or sign.

To test this, I first enabled the setting in Central Administration.  Navigate to the Application Management tab, Workflow Management, then Workflow settings.  Check the Yes radio button to enable external users to participate:

image


Next, let’s use a document library, and add a simple out-of-the-box approval workflow that is configured to route to an external address.  For this example I’m using a document library named External Documents, and have added an instance of the Approval workflow named External Workflow.  For the approvers, I’m adding an external email address to test with:

image


Whenever a new item is added to the library and the workflow gets kicked off, an approval email is sent to the external email address that was specified in the Approvers field that includes the document as an attachment.  What I don’t particularly like is the email still includes the link to the actual document, and if you hover over it, you can see the full URL to it.  The whole purpose of this is to send a copy of the document because the recipient doesn’t have access.  Why include a link if they’re definitely not going to have access to it?

image


Now, from here the workflow is disconnected.  Obviously because the external users don’t have access to the site, they can’t complete tasks, navigate to the document library, etc.  It us up to the external user to review the document and contact the initiator.

In addition to the email that is sent to the external email address, a email is sent to the initiator of the workflow indicating that the external user doesn’t have access to the item, and a task has been created for the initiator to be completed whenever the external has responded:

image


This isn’t limited to document libraries either – the same rules apply to list items.  The only difference is instead of the document being sent as an email attachment, you get to see the fields directly in the email:

 image

And that’s it!  Even external users and users that do not have permissions can participate in workflows!

Posted by Jarrett Haynes on Friday, 9 Jan 2009 02:18

For just about every MOSS 2007 build-out I have performed, I've needed to connect remotely to the client's Windows 2003-based server.  One thing that always tends to slip my mind is the Internet Explorer Enhanced Security (IEES).  This is enabled by default on the server's installation of Internet Explorer (6.0+ I believe).  Two issues sprung up recently which IEES directly affected:

1. The "Site Actions" menu does not work.

While working on the server, the "Site Actions" button was not highlighting or dropping down to reveal the "Site Settings" action I needed.  I later found out that the site I was working on was not in my trusted sites list.  Without the site being in my trusted sites, it had a higher security using IEES which disabled Javascript.  Javascript is needed for the menu to function properly.  After adding the site to my trusted sites list, the menu worked properly.

2. Trying to create a new My Site freezes while performing.

I was troubleshooting a new My Site host to confirm functionality while logged in as the System Account.  Every time I clicked on the "My Site" link it loaded a new screen which simply said the site was being created for the first time.  It kept freezing here for some reason.  Similar to the previous problem, the My Site host was not a trusted site.  Javascript or another disabled language through IEES was required to complete the action.  Once I added the My Site host to the trusted sites, the My Site was created.

These are minor thorns which may hurt temporarily but after a little troubleshooting, they are easily resolved.

Posted by Aaron Varga on Friday, 9 Jan 2009 09:15

Although this was published over a year ago, I just happened to stumble on this today.  It’s definitely a good read for SharePoint developers, specifically those of us who use the Object Model to access list data.  The Working With Large Lists in Office SharePoint Server 2007 whitepaper available from Microsoft covers in gruesome details the following 8 different ways to retrieve list data, and even includes performance metrics for each different option:

  • Through the browser
  • SPList with For/Each
  • SPList with SPQuery
  • SPList with DataTable
  • SPListItems with DataTable
  • Lists Web Service
  • Search
  • PortalSiteMapProvider

One thing I did want to explicitly point out is the use of the PortalSiteMapProvider to retrieve list data.  Before reading this, I didn’t even know this was an option, but could be a very efficient option for retrieving list data in certain situations. Read the suggestions below to determine if this is the best option for your scenario.  The PortalSiteMapProvider was originally created to help cache content for navigation. However, it also provides a nice automatic caching infrastructure for retrieving list data. The class includes a method called GetCachedListItemsByQuery which first retrieves data from a list based on an SPQuery object that is provided as a parameter to the method call. The method then looks in its cache to see if the items already exist. If they do, the method returns the cached results, and if not, it queries the list, stores the results in cache and returns them from the method call. Here’s a quick example:

public void GetListItemsFromSiteMapProvider() {
    using (SPSite siteCollection = new SPSite("http://server")) {
        using (SPWeb site = siteCollection.RootWeb) {
            string listName = "ListName";
            string camlQuery = "<Where><Eq><FieldRef Name='Title'/><Value Type='Text'>Value</Value></Eq></Where>";

            SPList list = site.Lists[listName];
            SPQuery query = new SPQuery();
            query.Query = camlQuery;

            PortalSiteMapProvider provider = PortalSiteMapProvider.CurrentNavSiteMapProviderNoEncode;
            PortalWebSiteMapNode node = provider.FindSiteMapNode("/") as PortalWebSiteMapNode;                   
            SiteMapNodeCollection results = provider.GetCachedListItemsByQuery(node, listName, query, site);

            foreach (PortalListItemSiteMapNode item in results) {
                // do something for each item
            }

            site.Close();
        }
        siteCollection.Close();
    }
}

Considerations
Using PortalSiteMapProvider in this way can have some drawbacks. The first request for a particular web or page via FindSiteMapNode or GetChildNodes will take longer to fetch than a similar call using the traditional Object Model calls. This is because in this case the caching mechanism must perform a round trip to the database and will often fetch more data than it needs in an attempt to pre-fetch and optimize subsequent requests. Therefore it is not useful to fetch data which is accessed very infrequently via these methods. The benefit associated does not show up until multiple calls have been made for the same data.

In addition, using the above methods to fetch data which changes frequently can also be counter-productive. If the data changes frequently, it will be frequently invalidated and re-fetched from that database negating the benefits of caching. The invalidation mechanism is relatively coarse, with a change to a particular item invalidating any data in the same web as the item.

I bet you didn’t realize there were so many ways just to get list data, huh?  Before beginning a project where you will need to access data from a SharePoint list, read the whitepaper and please consider the different data access methods available to you and make sure you choose the right one, as certain methods are much better than others in various scenarios. 

Posted by Aaron Varga on Friday, 9 Jan 2009 08:46

Lately I have been answering a number of questions related to workflows, specifically what you can and can't do with SharePoint Designer (SPD), and what advantages a custom Visual Studio workflow has over one created in SPD.  Basically, there are 3 ways to implement a workflow for SharePoint: use an out-of-the-box workflow, build a custom one using SharePoint Designer, or build a custom one from scratch using Visual Studio.  99.9% of the time, we eliminate the first option right away, as our clients rarely need something as simple as what the included workflows provide.  The following is a description of what's possible with the other 2 options, and how to make the right decision for which one to use.

 

SharePoint Designer

SharePoint Designer is obviously the preferred choice for creating workflows that need to do basic things, such as sequential document approvals, sending emails, creating tasks, etc.  The workflow designer wizard is user-friendly and easy to use, and attaching a workflow to a list or library is a cinch.  However, if you need to do something that's not given to you in the wizard, you don't really have much of an option other than to fire up Visual Studio and develop something custom.  Let's take a look at some of the things SPD can't do...

#1. [Lack of] Reusability
The most frequently mentioned limitation of SPD workflows is the inability to reuse them.  These workflows are bound to a list and site at design time through the workflow designer wizard, which does not offer the ability to publish to multiple locations.  This can potentially be overcome with manually copying the source files and updating the list and field ID's in the XML manually as described here, but this is extremely error-prone and not always effective.  I've seen cases where the source files were copied manually, the ID's were updated, the workflow republished, and the workflow still did not fire.  I didn't spend a significant amount of time troubleshooting it, just be aware that this is not a supported method of reusing workflows, and may not always work.

#2. Limited Conditions and Actions
With SPD you're basically limited to what is provided with the workflow designer wizard.  You're given a handful of conditions and a handful of actions, and that's what you have to work with if you're unwilling to write any code.  The included conditions and actions are simple and straight-forward and do not offer any customizations. Some of things that one might think SPD is capable of doing out-of-the-box, but can't:

  • Accessing Active Directory information directly, such as manager name or email
  • Kick off another workflow
  • Remove or grant permissions on the list item
  • Remove or grant permissions on a list, library, or site
  • Copy/move list items to a list in another site
  • Send emails with attachments
  • Jump to, or return to, another step in the workflow
  • Access information or content of the actual document in a document or form library -- SPD can only see the list columns.
  • Create or delete lists, libraries, sites
  • Wait for an item to change for a maximum amount of time

#3. No State-Machine Workflow Support
Workflows usually fall into one of two categories: sequential and state machine.  A sequential workflow is one that runs through all the steps and actions in sequence, one after another.  This may include parallel activities, where a bunch of people receive an email at once, for example, but the workflow as a whole runs from start to finish.  A state machine workflow represents a set of states, transitions, and actions. One state is denoted as the start state, and then, based on an event, a transition can be made to another state. The state machine would have a final state that determines the end of the workflow.  A state machine workflow is typically used when a particular step in a workflow needs to be repeated, such as during an approval process.  Take for instance the following scenario I encountered at a client:

A form to approve a product was created and submitted to a SharePoint form library.  This form when initially submitted needed to be routed to the requestor's manager.  The manager has the option to approve it and forward it on to the pricing manager, or reject it and send it back to the requestor, in which case that portion of the workflow would start over again, and would follow the same approval process.  If approved and sent to the pricing manager, this person would have the option to approve the form, send it back to the requestor, send it back to the manager, or send it back to both parties.  Yyyyeah...SPD can't do that.  There isn't a handy "Jump to Workflow Step" action.  The solution that was provided to the client was to handle a lot of the logic in the InfoPath form itself which used a decent amount of managed code in the form itself for some of this. All SPD was used for was to send emails.

In conclusion, if the workflow requires steps to be repeated, look elsewhere other than SPD.  If you're using an InfoPath form, you may be able to throw in enough logic there to do what you need, and if not a Visual Studio workflow may need to be explored.

#4. Limited User Data Collection
SPD provides a Collect Data From a User action that allows will create a task in the Task List and allow you to provided fields for the user to provide simple information.  For example, a single line of text, a checkbox, a drop-down list with pre-defined values, etc.  This creates an associated ASPX with custom SharePoint controls and logic, and cannot easily be modified.  In addition, you can't code the ASPX page to do anything custom in conjunction with the workflow, such as provide a drop-down list populated with SQL data, then use that elsewhere in the workflow.  Once again, you're limited to what you're given here.  A similar SPD action is Assign a To-Do Item, where you're able to specify some text which will create a task for a person and use the value you specify as the Task title. 

What's nice about a Visual Studio workflow is you are able to assign a custom task form to a task, which can be used to collect data.  This can be an InfoPath form or a custom ASPX form, and can contain custom code and logic, and the usual InfoPath and ASP.NET controls, respectively.  You can do whatever logic and data presentation you need to do, and are not restricted to what's provided out-of-the-box with SPD.

#5. Task/Action Dependencies
Another item not often thought of is the dependence of a task to the action that actually needs taken.  For example, a task can be created that says "Review this form and update some value", but how does the task know when it's completed?  If you bypass the task completely and go to the form and update the values and save it, the task will have no idea that the form has been updated.  Likewise, if you just complete the task without actually doing anything, it doesn't ensure that you did what you're supposed to do.

Since you control every step of the workflow in a custom VS workflow, you can enforce this dependency.  Do not provide complete buttons on your task forms, and leave it up to the running workflow to check the status of the submitted form and update the associated task accordingly.

These are just a few of the main points that continuously come up when designing workflows, and assessing whether or not SPD is the right tool.  Luckily, we haven't had many requests to provide the aforementioned functionality, so we've been able to make SPD jump through enough hoops to provide what they've needed.

When to Use SharePoint Designer
So, when is it a good idea to use SPD?  The answer is all of the time unless you absolutely can't.  If you can do it in SPD cleanly (key word being cleanly), then I recommend you do.  You won't find an easier way to create a simple task, send an email, or associate the workflow to a list, and you shouldn't recreate the wheel if the functionality is provided for you already.  If you need to do one of the items described above, or if you find yourself creating many individual workflows for the same "workflow", or if something you need to do can only be done using custom code, then consider writing a custom SPD activity or creating a workflow in Visual Studio.  Read on to find out if these other options are the right choices.

 

Custom SharePoint Designer Workflow Activities

As already mentioned, SPD gives you a handful of conditions and actions ("activities") out-of-the-box.  There are a ton of actions that I think should be included, but aren't.  Luckily, a framework is in place that allows developers to design their own SPD workflow activities, deploy them to a server, and have them be accessible to all workflows created in SPD.

Through a little bit of coding, configuration, and deployment, you are able to build your own activity that will appear in the SPD workflow designer wizard as an action.  This is plenty useful if you foresee a need to provide missing functionality to variety of workflows, such as an Active Directory lookup, or the ability to create sites or lists on the fly within a workflow.  Custom activities should only be considered when #1. the functionality isn't already included as an SPD action, and #2. the custom activity can be used for more than one workflow.  Custom activities are deployed globally, so it's not a good idea to create one specific to a single workflow, because there's nothing stopping other users of SPD from using it on one of their workflows, potentially screwing something up or doing something unintended.

Limitations of Custom SharePoint Designer Activities
While you can do almost anything with .NET code (and custom activities are written in .NET), you're still bound to the limitations imposed by the SPD workflow design process.  You still can't write an action to jump to a particular step in the workflow, you still can't have the workflow run as another user (you can run your custom activity as another user, however), you still can't move SPD-authored workflows around easily, etc.  You can do whatever you want for that particular action in that particular step of the workflow, but you're still constrained to using the SPD workflow designer.

When to Use Custom SharePoint Designer Activities
Custom activities are a nice middle-ground between what you're given with SPD by default, and building a workflow from scratch using Visual Studio, but keep in mind they serve a very specific purpose: to provide common functionality to all workflows.  Since they're available in the wizard, they are able to be used in any workflow.  If you haven't picked up the point yet, do not create a custom action that shouldn't be used by more than one workflow!

Useful SharePoint Designer Custom Workflow Activities
Luckily, other developers have seen the light when it comes to custom activities, and have built a few useful ones to address some of the missing functionality described above.  The following activities can be downloaded here:

  • Send Email with HTTP Attachment
  • Send Email with List Item Attachments
  • Start Another Workflow
  • Grant Permission on Item
  • Delete List Item Permission Assignment
  • Reset List Permissions Inheritance
  • Is User a Member of a SharePoint Group
  • Is Role Assigned to User
  • Lookup User Info
  • Copy List Item Extended Activity
  • Send Email Extended

 

Visual Studio Workflows

All workflows used in SharePoint rely on Windows Workflow Foundation (WWF), which is a piece of .NET goodness introduced in version 3.0.  Whether it's an out-of-the-box workflow, or SPD-authored workflow, they're all powered using this technology.  The difference with those 2 options versus creating one yourself in Visual Studio is most of the leg work and overhead is already done for you.  With Visual Studio it's up to you, the developer, to code every single thing that needs to happen during the workflow.  It's important to note that by creating a custom workflow in Visual Studio, it's not going outside the bounds of an appropriate workflow-creation tool -- Visual Studio is just another tool to use to create SharePoint workflows, and a very powerful one at that.

What's wonderful about a workflow created from scratch is you're given all the power to decide what you want the workflow to do.  You're not bound to certain conditions or certain activities like you are with SPD.  In addition, some workflows (like a state-machine workflow) aren't even possible in SPD, so Visual Studio must be used.

Visual Studio workflows also enable you to use custom forms at certain points in the workflow.  A custom InfoPath form or ASPX page can be written to display or collect any information that you want, and have that integrated into the workflow.  For example, if you need to collect information or provide user-configurable options when assigning a workflow to a list, you can develop an association form that collects this data. If you need to collect information when the workflow is kicked off for a particular item, you can implement an initialization form.  You can even collect information during the workflow using custom task forms.  For workflows that need a significant amount of user-provided data during the workflow in order to make decisions inside that workflow, Visual Studio will probably need to be leveraged to provide a custom form for that data collection.

Finally, Visual Workflows are reusable and moveable.  They're implemented as SharePoint Features, and only need installed and activated on whatever SharePoint environment you're using.  You assign the workflow to a list at runtime, not design time like you do with SPD.  You can use the same workflow on 100 different lists if you need to.  In SPD, you would have to recreate that same workflow 100 times, or make 100 copies of the workflow in order to achieve this.

Drawbacks of Visual Studio Workflows
Obviously the drawback to building a custom workflow in Visual Studio is the time it takes to do so.  With the out-of-the-box and SPD-authored workflows, so much of the initial overhead is done for you, and it's easy to take that for granted.  It's up to you to decide exactly what is supposed to happen, how to get the data from the list item as needed, and make the decisions in the workflow.  Visual Studio uses a number of activities that help facilitate this, but it is a time-consuming and cumbersome process.

Another drawback is implied from the first: only developers have the ability to create these workflows.  An advantage of an SPD workflow is that business users are [usually] smart enough to create them, and don't need to contact IT or a developer to do it for them (yes, I know what I just said, but that's the intended use of SPD...)

When to Use Visual Studio Workflows
The default answer for this is....use a Visual Studio workflow when you can't do something with an out-of-the-box workflow or with SPD.  If you need to implement a state-machine workflow, or you need to collect a lot of complex information from a user during the workflow, or you need to reuse a workflow over and over again, etc., then you should build it in Visual Studio.

This next answer should have as much weight as the previous...build a Visual Studio workflow if it will result in a better-architected, cleaner solution.  It may very well be possible to accomplish something using a combination of SPD workflows and a handful of custom actions, but rarely is that good design.  By having multiple moving parts, you're introducing multiple points of failure that each have to be maintained.  It is better to force a good solution than to force a particular tool on a client.

 

So, How Do I Choose?

Great question!  The answer is easy -- do the simplest thing possible that will result in a clean solution.  If you can implement the requirements with an out-of-the-box workflow, use that.  If you can implement the workflow in SPD using the included conditions and activities, use that.  If you can use SPD for all but one tiny thing that could be addressed by a reusable activity, build one and use SPD.  And if you can't provide the requirements in a clean, maintainable solution using SPD, then build it in Visual Studio.

Posted by Mike Ursta on Friday, 9 Jan 2009 08:42

Recently, a client expressed a concern about what users could see when they use the People Picker web control in SharePoint.  When the address book pops up, you can see all the users in Active Directory.  This client is using SharePoint as an external collaboration tool with their own clients. Since these users are external to the company, they only want them to see users that are site collection specific.  To allow this to happen, certain properties can be set on the People Picker using STSADM.  Below is a TechNet article from Microsoft that explains what properties you can set and how to set them.


The peoplepicker properties are part of the setproperty and getproperty operations. The syntax for the setproperty operation is:

stsadm -o setproperty

   -propertyname <property name>

   -propertyvalue <property value>

   [-url] <URL>

The syntax for the getproperty operation is:

stsadm -o getproperty

   -propertyname <property name>

   [-url] <URL>


Note:

You can substitute -pn for -propertyname and -pv for -propertyvalue.

The following table describes the peoplepicker properties.


Properties

Peoplepicker-activedirectorysearchtimeout
Configures the timeout when a query is issued to Active Directory.

Peoplepicker-distributionlistsearchdomains
Restricts the search of a distribution list to a specific subset of domains.

Peoplepicker-nowindowsaccountsfornonwindowsauthenticationmode
Specifies not to search Active Directory when the current port is using forms-based authentication.

Peoplepicker-onlysearchwithinsitecollection
Displays only users that are members of the site collection.

Peoplepicker-searchadcustomquery
Permits the administrator to set the custom query that is sent to Active Directory.

Peoplepicker-searchadforests
Permits a user to search from a second one-way trusted forest or domain.

You can find the article here:
http://technet.microsoft.com/en-us/library/cc263318.aspx

 Next >>