Wednesday, December 14, 2011
Office 365 HIPPA Compliant
Sunday, December 4, 2011
SharePoint - Presidential Memo to Records Management
On November 28, 2011 a new Presidential Memorandum was sent out regarding Records Management - http://www.whitehouse.gov/the-press-office/2011/11/28/presidential-memorandum-managing-government-records
In the Mandate there are two notable action items that should be top of mind with your customer and open the door for a discussion:
- “Within 30 days of the date of this memorandum, designate in writing to the Archivist of the United States (Archivist), a senior agency official to supervise the review required by subsection”
- “Within 120 days of the date of this memorandum, each agency head shall submit a report to the Archivist and the Director of the Office of Management and Budget (OMB) that describes the agency's current plans for improving or maintaining its records management program…”
This is a great opportunity for Federal Agencies to utilize what they own, specifically SharePoint, to assist you with building records management solutions. As a starting point, customers such as USDA where they have implemented a SharePoint 2010 Standard-only solution (no additional 3rd party software was required) to deliver cost effective Records Management - USDA Records Management Case Study.
If you required DoD 5015.2 certified records management solutions, Microsoft does have ISV partners that have built solutions that adhere to these standards.
Thursday, December 1, 2011
Gartner Rates Microsoft a Leader in Enterprise Search
I am happy to say the Microsoft has again been ranked as a top Enterprise Search provider in the marketplace - http://www.gartner.com/technology/reprints.do?id=1-1835DKL&ct=111123&st=sb. You will see that some Enterprise Search providers dropped in rankings and some were removed.
As you can see, FAST is not slowing down and we have an extremely strong roadmap for it. It is a very fiscally responsible Enterprise Search solution when you consider it as part of your Total Cost of Ownership (TCO) when investing with SharePoint Enterprise. FAST provides tons of added features and capabilities to solutions such as Portals, Sites, ECM, Document Management, BI, Social, Composites, Platform Development, etc. Plus if you know how to configure SharePoint Search; FAST search is configured and managed through the same screens and procedures thus requiring less ramp up time.
Even if an organization just needs a pure Enterprise Search solution, FAST is a great Enterprise Search platform. Having SharePoint in the mix, is great value additive because many other Enterprise Search ends provide you no user interfaces. Yes FAST does have services so that other applications tiers can tap into it. However having a web portal like SharePoint immediately available with numerous web parts to start building search screens and search applications is a huge time and money saver. Plus, when Enterprise Search is made accessible through SharePoint, you get to take advantage of all the other SharePoint features to deliver a more engaging user experience. For instance:
- You can create blogs from the search team to the users
- Wikis to explain to users how to do advanced search
- Stream training videos
- Maintain documents and FAQs
- Create a Search Knowledge Base
- Create support forums
- Manage technical specifications about line of business data that is index
- Etc.
Monday, November 28, 2011
Productivity Hub now supports SharePoint 2010 SP1
The SharePoint 2010 Productivity Hub has just been released support SP1 - http://www.microsoft.com/download/en/details.aspx?id=28178. This has been a rather popular web site to install into SharePoint for knowledge management around Microsoft products. I have also seen customers take it and extend the content delivered in this site to support applications, business processes, etc. that are unique to their organization.
There were some issues with running this because unless you installed this because many customers upgraded to SharePoint 2010 SP1 but the installer files were targeted for a pre-SP1 build of SharePoint 2010. This has now all be resolved and is ready to go.
Friday, November 25, 2011
SharePoint Online Service Descriptions Updates Fall 2011
Some of you may be aware but many of the service descriptions associated to Office 365 have been updated in the past month. It is really easy to find all of the Office 365 Service Descriptions – just search on “Office 365 Service Descriptions”. I highly recommend that you bookmark these locations because this is where the new service descriptions are always released. To save you a few seconds:
- Multi-tenant service descriptions - http://www.microsoft.com/download/en/details.aspx?id=13602
- Dedicated service descriptions - http://www.microsoft.com/download/en/details.aspx?id=18128
- Dedicated Federal service descriptions - http://www.microsoft.com/download/en/details.aspx?id=23910
SharePoint Online Multi-tenant Updates
In November 2011 there was an update to the SharePoint Online service description. There are a couple updates that you should be aware of:
- Business Connectivity Services (BCS) – is now available. Yes we heard about it at the SharePoint conference but now it available in the service descriptions. It supports WCF Web Service End Points (basically you need a WSDL web service available). This is great if you are trying to go completely cloud and you want to use Azure (PaaS) to use such things as Azure services, SQL Azure, App Fabric, etc. with SharePoint Online. So if you have complex data structures you want to manage and integrate directly in SharePoint use SQL Azure. If you can use App Fabric to connect premise back end applications, making those services available through SharePoint Online.
- A new capability available for partner accounts that are using Windows Live ID. Please read the service description for specifics. I personally think this is a huge new offering because SharePoint Online in general is a great solution of Partner Portals (Extranets). Nothing against doing an extranet on premise (and they work well), but it just takes more configuration and management than what system administrators what to take on responsibility for. With this partners can be given secure access to areas of content in SharePoint Online and they do not have to manage accounts in AD, Forms Auth, etc. This is absolutely huge and when I sit back and look at what SharePoint Online is offering as a whole, SharePoint Online has so many redeeming qualities for Partner Portals.
- There are a lot of new “Notes” that have been added to the service description that clearly communicate some of the most common questions that I have had over the past few months. I highly recommend reviewing these.
For the SharePoint Online Dedicated plan was updated in October 2011; there have been some updates that you should be aware of.
- Increased storage the max storage limit to 120 TB (which is 4 times more than previous). That is a whole lot of storage available to an organization. All the rules associated to purchasing extra TBs of storage to get to that 120 TB still hold the same.
- There is a new Administration portal for you to manage configuration requests, a new reports area providing analytic reports on usages and such, and support documentation.
- Active Directory Rights Management with IRM is now available for document libraries. SharePoint Online (both dedicated and multi-tenant) to store documents that had rights added prior to upload in SharePoint (and it is still supported). However the challenge is the document cannot be indexed. Now for SharePoint Online Dedicated, the document library IRM configuration is available so you can set rules on a document library and when the document is taken out of the SharePoint Online site, the IRM rights will be applied based on the setting in the document library. Documents put in a library using this new way are searchable.
- There is new support for Data Loss Prevention (DLP) solutions to scan SharePoint Online for sensitive content, PII, etc. Read the documentation for details.
Finally there is a new document called “Content Migration Policy and Storage Design for SharePoint 2010”. This is a really interesting document because it actually gives you some real insight into the storage architecture and how we manage quotas for site collections and such. I would even say a premise deployment of SharePoint 2010 should read this document take some best practices from it to implement on premise.
Tuesday, November 1, 2011
FAST for SharePoint 2010 Case Studies
There is a new FAST Case Study that for FAST for SharePoint 2010. IMF - http://www.microsoft.com/casestudies/Case_Study_Detail.aspx?CaseStudyID=4000011274
Here are two other good FAST for SharePoint Case Studies:
- Case Study – General Mills Research (FAST) - http://www.microsoft.com/casestudies/Microsoft-FAST-Search-Server-2010-For-Sharepoint/General-Mills/General-Mills-Frees-More-Time-for-Innovation-with-Research-Focused-Search-Application/4000007255
- Case Study – Mississippi State Department of Transportation (FAST) - http://www.microsoft.com/casestudies/Microsoft-SharePoint-Server-2010/Mississippi-Department-of-Transportation/State-Transportation-Department-Saves-Lives-with-Better-Business-Insight/4000007073
InfoPath 2010 and Digital Signatures
I have had several questions about InfoPath 2010 and support for Digital Signatures. The answer is yes, InfoPath 2010 supports them and there is even more improved capability. Here are some good references.
- This provides good general information about InfoPath Digital Signatures - http://office.microsoft.com/en-us/infopath-help/digital-signatures-in-infopath-2010-HA010381868.aspx
- This provides information describing in more detail the improvements with SharePoint and InfoPath 2010 - http://blogs.msdn.com/b/infopath/archive/2010/02/18/digital-signature-support-in-infopath-2010.aspx
- This is a good article about the event model around digital signatures and how you create customizations around those event - http://msdn.microsoft.com/en-us/library/aa948780.aspx
SharePoint 2010 Max File Size
I have as well been receiving an inordinate amount of questions associated to the max file size the SharePoint 2010 supports. It is been clearly stated for some time that the max file size supported by SharePoint 2010 is 2 GB - http://technet.microsoft.com/en-us/library/cc262787.aspx#ListLibrary. A lot of customers are asking why. I am not on product team but usually couch it as SharePoint is a web based ECM platform. Two GB uploads and downloads is not very effective over the internet in general. Yes, internet speeds are getting better but still, that is a big file. Plus, if you are not using Remote BLOB storage, that is a lot of data to put into SQL Server.
If you have files that are larger than 2 GB you should look into storing the content externally and then utilize enterprise search and third party web parts to make the large files accessible through SharePoint 2010.
SharePoint Search Index Document
I received several questions about indexing of SharePoint content lately. Specifically does SharePoint index the entire document?
First off if FAST is being utilized, yes, the entire document will be indexed.
Second if you are using the out of the box SharePoint search by default it configured to index the content of items that are under 16MB or under. Metadata associated to these documents will still be indexed (so if the big files are videos they will still be searchable).
The max file size for indexing can be upped up to the max file size limit; which is 2GB. Before upping the size, it is recommended that you do some testing and understand any performance ramifications relative to your environment and data. Here are some good references on the topic.
SharePoint 2010 Content Database Sizing
A lot of people already know this but on July 14, 2011 it was announced that Content Database Sizing has been updated http://technet.microsoft.com/en-us/library/cc262787.aspx#ContentDB.
There is still recommendation to keep content databases at 200GB. Why? This recommendation is still a good recommendation because if you need to back-up and restore a database very quickly, you do not have move around large back-up files. Plus if you have an Information Architecture that drives content to specific site collections (with dedicated content databases), you will be much more agile to requirement changes, upgrades, etc. One big massive content database is an indication of poor planning and governance.
The first new recommendations in this article is that 4TB of data can be stored in a content database. There are some parameters around this recommendation that you should read.
The second new recommendation is that there is no explicit recommendation on sizing for document archiving scenarios. However there are some very specific recommendations made in here to support that scenario – so review http://technet.microsoft.com/en-us/library/cc262787.aspx#ContentDB. This is really important for Records Management solutions. On this specific point, it would also be good to review the “Extremely large-scale content archive” section in http://technet.microsoft.com/en-us/library/cc263028.aspx. When going down this path you will need to have Remote Blob Storage and FAST to support this solution architecture.
Finally SQL Server tuning is fundamental to your success for managing large content databases. Here is a blog that I wrote on the topic - http://www.astaticstate.com/2010/12/sharepoint-2010-high-availability-with.html
Sunday, October 16, 2011
SharePoint Online Hybrid Architecture Whitepaper
I will be working on some SharePoint architecture blogs that discuss this along with general SharePoint Governance and Information Architecture. I have been having way too conversations with clients where people confuse the real spirit of governance making it too authoritative. It is not about locking down SharePoint; it is about setting up business services and service level agreements and then delivering capabilities on them. It is about setting up a real Information Architecture! More to come I promise.
Create InfoPath Form Instance through Workflow
Issue
Have you ever wanted to have an InfoPath form generated by a workflow? Well I thought it would be a simple task but I had to do some extra things to make it happen correctly.
I recently wanted to be able to generate an InfoPath form based on an event on a SharePoint Designer workflow. So I published my InfoPath form to a Form Library, added an action to create a list item and then ran the workflow. I believed this would work because I have created Word templates, associated them to content types and the word file would be created just fine with the appropriate template. The net result in this situation does not work. Instead the InfoPath form template (.xsn file) is created as a file instance. The InfoPath xml that I had expected was not there.
Solution
I found this article (http://www.bizsupportonline.net/blog/2009/06/create-infopath-forms-sharepoint-designer-workflow/) which I reviewed. My solution is a little bit different because I was building this solution in SharePoint Online in Office365 and I was not able to implement this exact solution. However I was given some clues and came up with the following.
My solution was to:
- Publish the InfoPath form the same way I did before.
- Then I created an instance of the InfoPath form xml and saved it to my desktop.
- Then went to the form library configuration, advanced settings and turned on “Allow management of content types”.
- Then clicked on the default Form Content Type.
- Then clicked on Advanced Settings for the Form Content.
- Then I selected Upload a new document template and selected xml template I saved locally.
The following is what I had.
The InfoPath form template (.xsn file) is still there behind the scenes and the form will render correctly through InfoPath form services.
There are a few limitations of this solution:
- The user will not be able to create a new InfoPath form instance through the browser using the New Document button in the ribbon. What will happen is the InfoPath client will launched. This is not such a big deal because in my situation InfoPath forms will always be created through the workflow.
- If the InfoPath form changes, you will have to publish the InfoPath form template (.xsn file) and then go through these steps again.
Monday, September 5, 2011
Happy Four Years Old
It is amazing to see that I have been able to keep this blog going for the past 4 years. Through change jobs two times, continue being a top performer at work, having a second child, writing a book, etc. I have kept it going. I have to say thank you to all the readers, your feedback keeps me wanting to write.
Birthday Gift
As a reward, Google Blogger has given me a new interface as this month to write blogs. I had been using Windows Live Writer for the past year to format the blog better. However Google Blogger would continue to foul up the HTML and jack up the presentation for which I have dumped hours into fixing however still can never make perfect. The tool seems better now. I have not moved off Google because it is just too much work given that this is something I do in my personal time.
Stats
I started using Google Stats in May 2009. Here is how I have been doing, pretty happy.
Most popular posts since May 2009 are the following. The Silverlight series I wrote is mind boggling. I had no clue that would become what it did. It is funny because I got put on a contracting engagement for about 9 months doing all Silverlight project with no SharePoint work. Now I am back to really only focusing on SharePoint since I am working at Microsoft now. I am happy to see how popular my SharePoint 2010 architecture series has been as well.
What’s Next?
Expect to see a lot over the next few months on architecture, enterprise patterns and such for Office365 with a focus on SharePoint Online. There are a lot of smart people who are out there who know SharePoint well, but are missing the bigger picture and the strategic thinking of how to align SharePoint Online to create more architecturally sound solutions that save money for organization. A lot more to come there.
Friday, August 26, 2011
SharePoint 2010 Independent Market Analysis
I get asked a lot about reasons to move to SharePoint 2010. I simply state, look at the how the market evaluates SharePoint.
Here is a great link managed by Microsoft that showing Gartner and Forrester reports - http://www.microsoft.com/presspass/itanalyst/default.mspx
As of right now, I recommend reading the following:
- Enterprise Content Management (ECM) – View Report
- Business Intelligence (BI) – View Report
- Enterprise Search – View Report - Just Updated in Nov 2011 and continued leader - View Report
- Social Computing – View Report - Just Updated Aug 2011 (continued to be leader, here is the 2010 report)
- Portal Platform – View Report
- Unified Communications – View Report and View Report
- Email – View Report
Saturday, August 20, 2011
SharePoint 2010 SQL Server Encryption
I have been asked several times what SharePoint ability to encrypt data that resides the SQL Server databases. I was answering this question when I ran across this awesome presentation that I highly recommend. “SQL Transparent Data Encryption for SharePoint Content Databases” at http://technet.microsoft.com/en-us/edge/Video/ff711430. Just want the first few minutes of the video.
Smaller notes I usually bring up are:
· Row level encryption is not really possible as we do encryption at the database level.
· An important note is that the SQL connection from the SharePoint application layer to SQL server is done through a service account. Users are not directly authenticating and accessing data in the database.
· Documents themselves can have rights management applied so the BLOB is encrypted when it is stored in SharePoint. However metadata associated to the document is not encrypted and documents will not be searchable.
Using Transparent Data Encryption really is a great solution.
SharePoint 2010 Architecture Introduction
I recently had a client ask be about how to get started on understanding the SharePoint 2010 architecture and how they should deploy. Unfortunately the answer is it depends based on your business requirements.
Gartner recognizes the SharePoint platform as a best of breed across all major workloads like web portal, enterprise content management (document management, web content management, records management, etc.), business intelligence, workplace social computing, search/enterprise search, and as an application development platform. Knowing this, the SharePoint platform delivers a single platform that is managed together helping agencies consolidate costs in people, process and technology. Plus SharePoint is tightly aligned to Office and Lync (instant messaging, sharing, meeting, and phone solution).
Now depending on what you will implement will depend on how you scale SharePoint 2010. Plus with many agencies, there is never just on SharePoint farm. There will be multiple SharePoint farms which will be configured to support the business requirements.
References
If you are trying to get an initial understanding of the SharePoint 2010 architecture, here are some good references:
· SharePoint 2010 Architecture - http://msdn.microsoft.com/en-us/library/gg552610.aspx - this is a good starting place if you are not familiar with SharePoint.
· SharePoint 2010 Technical Diagrams - http://technet.microsoft.com/en-us/library/cc263199.aspx - all the big picture of both physical and logical architecture.
· Hardware and Software Requirements - http://technet.microsoft.com/en-us/library/cc262485.aspx - I suggest reading this right off the bat.
Performance, scaling, business continuity topics always come up when starting to learn about SharePoint 2010. Here is a good place to start.
· Performance and capacity technical case studies (SharePoint Server 2010) http://technet.microsoft.com/en-us/library/cc261716.aspx - More good case studies.
· SharePoint 2010 Performance and Capacity whitepapers - http://technet.microsoft.com/en-us/library/ff608068.aspx - Whitepapers on specific workloads.
· SharePoint 2010 Capacity boundaries - http://technet.microsoft.com/en-us/library/cc262787.aspx - This is pretty detailed discussion on testing.
Now if you are familiar with SharePoint 2007 architecture:
· I have written a multiple part series on SharePoint 2010 architecture here- http://www.astaticstate.com/2010/01/sharepoint-2010-service-architecture.html
· I have another blog on scaling SQL Server because this is a critical component to SharePoint - http://www.astaticstate.com/2010/12/sharepoint-2010-high-availability-with.html.
· Here is a series on SharePoint 2010 Search - http://www.astaticstate.com/2010/12/sharepoint-2010-search-architecture.html
· Here is a series on FAST for SharePoint 2010 - http://www.astaticstate.com/2011/01/part-1-fast-for-sharepoint-2010.html
Office365
Finally it is also IMPORTANT to know when reviewing all these architectures, that SharePoint 2010 is the only portal technology on the market that software as a service (SaaS) cloud offering called Office365. This ultimately means major reduction on hardware and software that must be installed and managed, better service level agreements to your users, quicker deployment of solutions, better ability to scale, better ability to support telework and external collaboration, and the list really just goes on. Be in the business of creating business solutions.
I say the best way to learn about SharePoint Online Service is read the service level agreements which I have linked to here - http://www.astaticstate.com/2011/07/office365-slas.html
Thursday, August 18, 2011
BCS Connection to WCF Web Service
Introduction
I recently needed to connect BCS to some WCF services. The goal was show how I can then use the data out of those WCF services as a data source for FAST. Creating a WCF service and publishing it out through IIS was a pretty simple task. For search you only really need two web methods. First you will need a method that returns a full collection of the dataset which will be used as part of the indexing process. The second method you will need is a get item method that will get the details of a record in the data set.
Issue I ran into
However I ran into a challenge with getting the connection to work initially. When filling in the WCF connection window I would get errors like:
In the Event Logs I had some more detailed errors which really did not help much.
Could not obtain a proxy to WebService for LobSystem 'Default' in App Domain 'ConnectionDomain'. The full exception text is: Metadata contains a reference that cannot be resolved: 'http://demo2010a:8000/SoftwareService/SoftwareService.svc'.. The inner exception text is: <?xml version="1.0" encoding="utf-16"?><Fault xmlns="http://www.w3.org/2003/05/soap-envelope"><Code><Value>Sender</Value><Subcode><Value xmlns:a="http://schemas.xmlsoap.org/ws/2005/02/sc">a:BadContextToken</Value></Subcode></Code><Reason><Text xml:lang="en-US">The message could not be processed. This is most likely because the action 'http://schemas.xmlsoap.org/ws/2004/09/transfer/Get' is incorrect or because the message contains an invalid or expired security context token or because there is a mismatch between bindings. The security context token would be invalid if the service aborted the channel due to inactivity. To prevent the service from aborting idle sessions prematurely increase the Receive timeout on the service endpoint's binding.</Text></Reason></Fault>.
Could not obtain a proxy to WebService for LobSystem 'Default' in App Domain 'ConnectionDomain'. The full exception text is: There was an error generating the XML document.. The inner exception text is: The type System.Web.Services.Discovery.DiscoveryDocument was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically..
Resolution
After playing around with the configuration I finally found the following worked. Notice the “mex” extension added to the end of the Service Metadata URL. Once I had that done, just wire up the web methods like you would anything else in BCS.
Now here is another way to do this. Any service that has a wsdl description can be integrated as well. Notice here how I put the wsdl address for the Service Metadata URL.
Sunday, August 7, 2011
Part 5 – Custom Visio Services Reports with SharePoint 2010 Workflow
· Part 1 - Pattern for Building Stateful Workflows with SharePoint Designer 2010
· Part 2 - Custom Action for Workflow Initiation
· Part 3 - Delays for Workflow Initiation Action
· Part 4 - Using Business Connectivity Services (BCS) with SharePoint 2010 Workflow
· Part 5 - Custom Visio Services Reports with SharePoint 2010 Workflow
Introduction
This is the last part in this workflow series. In the first part of this series I wrote extensively about how Visio Services allow us to now do visual reporting on the progress of a workflow process instance. More importantly, it allows us to provide a visual report to business users removing all the technical steps that may be needed to implement an end to end workflow.
For example, I below I have a ton steps in a workflow. When SharePoint Designer 2010 publishes this workflow a Visio workflow diagram will be generated.
That Visio diagram will accurately show where it is within its execution however I can guarantee that the business user does not care about all these steps. All they want to know is what the major business process steps are and what the current status is.
Solution
We can provide a perfect solution using a custom Visio report.
My solution is to create a completely different Visio diagram to the business reporting. So what I did was take this original diagram I created in this series (below) with the objective of “lighting it up” with the current status of the business process.
The solution is simple.
· I create a column on my list item to store the current step in the business workflow the workflow is in.
· Then during my workflow, I update this column object in the Visio diagram I want to light up.
· Then connect a list and Visio web part together to allow a user to select a running workflow and then visually see the status of the workflow.
Configuration
To achieve this I need to perform a few steps.
In the workflow I added an Update List Item action. I updated my CurrentAction column with the name of the Visio object I want to light up. In this instance it is “Process.3”. Throughout other workflows I will update the CurrentAction column with other values that correspond to different objects in the Visio diagram.
Next I uploaded the Visio diagram to a location in SharePoint; simple enough.
Next I created a web part page. On that web part page I placed the list where the workflow is running.
Next I added a Visio web part and pointed to the Visio diagram that I had just uploaded. Below is a screenshot.
Next I need to connect the list web part to the Visio web part. I need to do this so that when a user selects a list item, the Visio diagram on the right will highlight the correct Visio object. On the Visio web part I made a connection to the Review list web part. Notice I select “Get Shapes to Highlight From”.
Next in the Configuration Connection screen, I select the CurrentAction column (which is the column I that I update in the workflow) and then select Shape Names. This is how the “Process.3” value is sent from the selected list item to the Visio diagram to be highlighted.
The net result is the following. As you can see a Visio object is now highlighted based on the item that I selected on the left hand side. Really simple and really effective!!!
Highlighting Multiple Items
In the example I just showed you, I am only highlighting the point where the process is in its execution. However, let’s say you want to highlight all the steps the workflow has gone through. Well that is simple too.
In this case I created a different column called “Actions” where I capture a comma delimited string of all the times I want to be highlighted. In the workflow I have the following. Notice in the String Builder window I concatenate the previous value in the column with the new value “,Process.3”.
Other than that, the configuration is 100% identical other than selecting the “Actions” column when connecting the web parts. The final result is the following – all of the Visio object names I concatenated together are highlighted.
Conclusions
This is such a powerful capability. I can create custom visual reports on my business process with no code.
I truly hope this workflow series will be helpful for you when starting to build process automation in SharePoint 2010.
Part 4 – Using Business Connectivity Services (BCS) with SharePoint 2010 Workflow
· Part 1 - Pattern for Building Stateful Workflows with SharePoint Designer 2010
· Part 2 - Custom Action for Workflow Initiation
· Part 3 - Delays for Workflow Initiation Action
· Part 4 - Using Business Connectivity Services (BCS) with SharePoint 2010 Workflow
· Part 5 - Custom Visio Services Reports with SharePoint 2010 Workflow
Introduction
If you have been reading this blog series closely I mentioned that I will be discussing how we can do reporting for our workflow solutions in SharePoint 2010.
As you may know when you configure a workflow in SharePoint there is a Workflow History list that must be associated which will stored information about the execution of a workflow instance. I have typically viewed this as more of a log. It is not something to be used for reporting. Here is a quick reference about it and I suggest you read it - http://technet.microsoft.com/en-us/library/ee662522.aspx
The reasons I do not use it for reporting is because:
· This list can potentially store a lot of data from a lot of different workflows.
· It will be purged after a period time. Even though you can disable a job to ensure logs are not deleted, doing this would disable the job for every workflow across an entire web application which is not good practice.
· Personally I like it for its logging capability but I would not use it for a reporting capability.
Solution
My approach will be to store data in a SQL Server table using Business Connectivity Services (BCS). With SharePoint 2010 it is so easy to support this from a workflow without doing a ton of code. Now I can do inserts and updates operations to reporting tables and then build reports off of them using the either Excel Services, SSRS, etc.
I am not going to go over the steps on how to create a SQL Table or how to create an external content type using BCS. What I will cover is how to use the external content type from a workflow and discuss one tricky configuration you may not know about.
For this solution you need to:
· Create any sort of SQL tables you need.
· Create external content types to connect to those tables.
· Create external lists on the site to use the external content types.
· Finally I will cover how the workflow will call the external list as a proxy to make transactions against the SQL tables that you will use for reporting.
Insert a Record from a Workflow
There is really nothing special to this at all. Add a Create List Item action into my workflow that references the external list. In my case, the external list I created was called “Review Actions Table”.
Note that I created a variable called ReviewActionID, where I store the SQL generated ID of the new item that was created. If you need to update this SQL record as part of a different workflow process, I recommend updating this value into a column on the item where the workflow is running against.
Updating a Record
Now this is the tricky part. Let’s say later on in the same workflow process you want to update the same SQL record you just created. To accomplish this just add an update action like the following.
The tricky part is the configuration of the update – look at the screen shot below. Notice how I have to select the BDC Identity Field to get the primary key value to perform the update. If you do not do this the update will fail (sorry do not have the error log handy).
Initially I had set it to use the ID Field on the external content type thinking it would have the generated key from the SQL table as part of the original insert I did early. However that was not the case.
Note you do not need to create this BDC Identity column; it is auto-generated for you.
One more note, I had to do this for a SQL Server table with an auto-generated primary key. I have not tested this out for other scenarios like a web service or another DB platform.
Finally let’s say I need to update an external list item on a record that was created prior to the workflow being started. Add an Update List Item action to the external list like the following. Notice here for the Field I use the ID column from the external content type. We do not have to do what we did earlier.
Conclusions
Why do I get so excited about this? Now I am able to start dumping data out into SQL server to do reporting with SharePoint 2010 Business Intelligence solutions. I can create reports with Excel Services or SSRS. In this example I used SSRS using Report Builder 3.0 to create reports about the execution of my business process.
For instance I created an SSRS report that shows the average duration of steps in the business process. I embedded the reporting into SharePoint and I was off and running.
I then created another report that shows the duration by business process instance.
I even created another report that shows how employees perform.
I just embedded these reports into SharePoint 2010 and I was done. Now I can provide some real business insight into process execution.
Part 3 – Delays for Workflow Initiation Action
· Part 1 - Pattern for Building Stateful Workflows with SharePoint Designer 2010
· Part 2 - Custom Action for Workflow Initiation
· Part 3 - Delays for Workflow Initiation Action
· Part 4 - Using Business Connectivity Services (BCS) with SharePoint 2010 Workflow
· Part 5 - Custom Visio Services Reports with SharePoint 2010 Workflow
Introduction
In the previous part of this blog series I provided an approach for chaining together a bunch of sequential workflows together so that I can create a “state like” workflow without having to use Visual Studio. However one thing I did not go over was a few configurations you will have to do to actually start working with data.
One important issue I would run into with my approach was that workflows would start to trip over each other. For instance I have workflow A and workflow B associated to a list. In this case, workflow A would start workflow B. Every once and a while the workflows would fail for no apparent reason. Digging through the logs I would find errors like this which would not tell me much.
OWSTIMER.EXE (0x0A00) 0x0968 SharePoint Foundation Workflow Infrastructure 88xr Unexpected WinWF Internal Error, terminating workflow Id# 13531682-5bef-4194-aaf6-8cf32b31345d
OWSTIMER.EXE (0x0A00) 0x0968 SharePoint Foundation Workflow Infrastructure 98d4 Unexpected System.ArgumentException: listItemKey at Microsoft.SharePoint.WorkflowActions.WaitForDocumentUnlockActivity.Initialize(WorkflowContext context, Guid listID, SPItemKey listItemKey) at Microsoft.SharePoint.WorkflowActions.WithKey.UpdateItemActivity.Execute(ActivityExecutionContext provider) at System.Workflow.ComponentModel.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()
Solution
The solution is simple; if you are going to use the approach that I outlined earlier in this series you will need to introduce some delays into your workflows.
For instance in Workflow A, I put in the following delay before my custom action to initiate a workflow.
Then in Workflow B, I put another delay.
This way I am ensured that if there are any lagging transactions are completed against the list item that both workflows are working on.
You will also have to configure the interval workflow timer job in Central Admin. The default is 5 minutes and I upped it to one minute in my development environment.
There is no perfect configuration however you will need to make the correct configuration to make sure everything works well. You need to introduce enough delays and configure the workflow service to make sure you do not get these locking issues.
Saturday, July 30, 2011
Part 2 – Custom Action for Workflow Initiation
· Part 1 - Pattern for Building Stateful Workflows with SharePoint Designer 2010
· Part 2 - Custom Action for Workflow Initiation
· Part 3 - Delays for Workflow Initiation Action
· Part 4 - Using Business Connectivity Services (BCS) with SharePoint 2010 Workflow
· Part 5 - Custom Visio Services Reports with SharePoint 2010 Workflow
Part 2
Building the Custom Action
In the previous part of this blog I explained my approach and in this part I am going to show you how I created two custom actions that is needed to support my approach. I am first going to show you the code solution I created and then dive a bit into why I made the solution as is.
I can tell you honestly that I really wanted this solution to be a SharePoint 2010 Sandbox solution however I ran into a few challenges that prevented me from doing that. This forced me to build a full trust solution with Visual Studio 2010. There are basically two actions I needed to create. The first one is an action that can initiate another workflow. The second action I needed checks to see if 1 to N workflows are running on a list item, and if so, stop the running of that workflow.
It is pretty well documented on how to create a custom action, deploy it and then use that action in SharePoint Designer. The following are some good references:
· http://blog.voltje.be/?p=144
Workflow Helper Class
First thing I did was create a simple helper class where I stored logic to initiate the workflow and to check to see if there are any existing workflows running. The ItemHasActiveWorkflows method is really straight forward as it is searching workflows that are running for the specific item. If it finds a workflow is running, it will return false. Why is this important? Well because a document or list item can only have one of a particular type running at a time. But since we broke the larger business process up into five smaller ones, we need to check to see if any of the five are running on the item. If any one of them is running, we need to block any new workflows from being started. This method will take a comma delimited list of workflow names that must be checked.
The second method is StartWorkflow which will initiate a workflow on a specified item. This code is very straight forward.
public class WorkflowHelper
{
private string siteCollectionUrl;
private string webUrl;
private string listName;
private int itemID;
private string workflowName;
public WorkflowHelper(string siteCollectionUrl, string webUrl, string listName, int itemID)
{
this.siteCollectionUrl = siteCollectionUrl;
this.webUrl = webUrl;
this.listName = listName;
this.itemID = itemID;
}
public WorkflowHelper(string siteCollectionUrl, string webUrl, string listName, int itemID, string workflowName) : this(siteCollectionUrl, webUrl, listName, itemID)
{
this.workflowName = workflowName;
}
public bool ItemHasActiveWorkflows(string workflowNames)
{
string[] seperator = new string[] {","};
string[] workflowNamesSplit = workflowNames.Split(seperator, StringSplitOptions.RemoveEmptyEntries);
//Get the site collection
using (SPSite site = new SPSite(siteCollectionUrl))
{
//Get the web
using (SPWeb web = site.OpenWeb(webUrl))
{
SPList list = web.Lists[listName];
SPListItem workflowItem = list.GetItemById(itemID);
//Loop over the workflows to look for
foreach (string workflowName in workflowNamesSplit)
{
//Loop over the workflows on the item
foreach (SPWorkflow workflow in workflowItem.Workflows)
{
//Check the state of the workflows to see if any are running
if (workflow.InternalState == SPWorkflowState.Running ||
workflow.InternalState == SPWorkflowState.Expiring ||
workflow.InternalState == SPWorkflowState.Faulting)
{
if (list.WorkflowAssociations[workflow.AssociationId].Name.ToLower() == workflowName.Trim().ToLower())
{
return true;
}
}
}
}
}
}
return false;
}
public void StartWorkflow()
{
//Open the site collection. Cannot go across site collections in
//sandbox so easier to just pull of workflow context
using (SPSite site = new SPSite(siteCollectionUrl))
{
//Just open web because we cannot go across site collections
//with a sandbox solution.
using (SPWeb web = site.OpenWeb(webUrl))
{
//Get the manager that will initiate the workflow
SPWorkflowManager workflowMgr = site.WorkflowManager;
//Get the available workflows on the list
SPWorkflowAssociationCollection workflowAssocs = web.Lists[listName].WorkflowAssociations;
//Get the list item that the workflow will be initiated on
SPListItem workflowItem = web.Lists[listName].GetItemById(itemID);
//Get the workflow that has been associated
SPWorkflowAssociation workflowAssoc = workflowAssocs.GetAssociationByName(workflowName, System.Threading.Thread.CurrentThread.CurrentCulture);
//Start the workflow
workflowMgr.StartWorkflow(workflowItem, workflowAssoc, workflowAssoc.AssociationData, true);
}
}
}
}
Start Workflow Action
Next I created an action that would start a second workflow. I created the following code.
public class InitWorkflowAction : Activity
{
#region Properties
public static DependencyProperty SiteCollectionUrlProperty = DependencyProperty.Register("SiteCollectionUrl", typeof(string), typeof(InitWorkflowAction));
[Description("Site Collection URL")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string SiteCollectionUrl
{
get
{
return ((string)(base.GetValue(InitWorkflowAction.SiteCollectionUrlProperty)));
}
set
{
base.SetValue(InitWorkflowAction.SiteCollectionUrlProperty, value);
}
}
public static DependencyProperty WebUrlProperty = DependencyProperty.Register("WebUrl", typeof(string), typeof(InitWorkflowAction));
[Description("Web Url")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string WebUrl
{
get
{
return ((string)(base.GetValue(InitWorkflowAction.WebUrlProperty)));
}
set
{
base.SetValue(InitWorkflowAction.WebUrlProperty, value);
}
}
public static DependencyProperty ListNameProperty = DependencyProperty.Register("ListName", typeof(string), typeof(InitWorkflowAction));
[Description("List Name")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string ListName
{
get
{
return ((string)(base.GetValue(InitWorkflowAction.ListNameProperty)));
}
set
{
base.SetValue(InitWorkflowAction.ListNameProperty, value);
}
}
public static DependencyProperty WorkflowNameProperty = DependencyProperty.Register("WorkflowName", typeof(string), typeof(InitWorkflowAction));
[Description("Workflow Name")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string WorkflowName
{
get
{
return ((string)(base.GetValue(InitWorkflowAction.WorkflowNameProperty)));
}
set
{
base.SetValue(InitWorkflowAction.WorkflowNameProperty, value);
}
}
public static DependencyProperty ItemIDProperty = DependencyProperty.Register("ItemID", typeof(int), typeof(InitWorkflowAction));
[Description("Item ID")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int ItemID
{
get
{
return ((int)(base.GetValue(InitWorkflowAction.ItemIDProperty)));
}
set
{
base.SetValue(InitWorkflowAction.ItemIDProperty, value);
}
}
#endregion
#region Methods
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
//WorkflowHelper workflowHelper = new WorkflowHelper(this.SiteCollectionUrl, this.WebUrl, this.ListName, this.ItemID, this.WorkflowName);
//workflowHelper.StartWorkflow();
WorkflowHelper workflowHelper = new WorkflowHelper(this.SiteCollectionUrl, this.WebUrl, this.ListName, this.ItemID, this.WorkflowName);
Thread thread = new Thread(new ThreadStart(workflowHelper.StartWorkflow));
thread.Start();
return ActivityExecutionStatus.Closed;
}
#endregion
}
With the StartWorkflow method you see the code is straight forward but there some threading. You may be wondering why I have implemented threading? Well I was getting the below error message in the SharePoint logs when the workflow was initiated on the same thread. I did not find any information on why this was occurring but on a hunch I thought the workflow service was competing for the same resources. My solution was to move the call to StartWorkflow into a different thread and the problem was resolved.
w3wp.exe (0x2BC4) 0x0A2C SharePoint Foundation Workflow Infrastructure xmfh Medium Workflow Compile Failed: Invalid token for impersonation - it cannot be duplicated.
w3wp.exe (0x2BC4) 0x0A2C SharePoint Foundation Workflow Infrastructure 72fs Unexpected RunWorkflow: Microsoft.SharePoint.SPException: Invalid token for impersonation - it cannot be duplicated. at Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler.SubCompiler.DoCompile(WorkflowCompilerParameters parameters, String xomlSource, String assemblyName, CompilationPacket& packet, DirectoryInfo& tempDir) at Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler.CompileBytes(Byte[] xomlBytes, Byte[] rulesBytes, Boolean doTestCompilation, String assemblyName, SPWeb web, Boolean forceNewAppDomain) at Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler.LoadXomlAssembly(SPWorkflowAssociation association, SPWeb web) at Microsoft.SharePoint.Workflow.SPWinOeHostServices.LoadDeclarativeAssembly(SPWorkflowAssociation association) at Microsoft.SharePoint.Workflow.SPWinOeHostServi...
w3wp.exe (0x2BC4) 0x0A2C SharePoint Foundation Workflow Infrastructure 72fs Unexpected ...ces.CreateInstance(SPWorkflow workflow) at Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut) at Microsoft.SharePoint.Workflow.SPWorkflowManager.RunWorkflowElev(SPWorkflow workflow, Collection`1 events, SPWorkflowRunOptionsInternal runOptions)
0x0A2C SharePoint Foundation Workflow Infrastructure 98d8 Unexpected Microsoft.SharePoint.SPException: Invalid token for impersonation - it cannot be duplicated. at Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler.SubCompiler.DoCompile(WorkflowCompilerParameters parameters, String xomlSource, String assemblyName, CompilationPacket& packet, DirectoryInfo& tempDir) at Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler.CompileBytes(Byte[] xomlBytes, Byte[] rulesBytes, Boolean doTestCompilation, String assemblyName, SPWeb web, Boolean forceNewAppDomain) at Microsoft.SharePoint.Workflow.SPNoCodeXomlCompiler.LoadXomlAssembly(SPWorkflowAssociation association, SPWeb web) at Microsoft.SharePoint.Workflow.SPWinOeHostServices.LoadDeclarativeAssembly(SPWorkflowAssociation association) at Microsoft.SharePoint.Workflow.SPWinOeHostServices.CreateIns...
w3wp.exe (0x2BC4) 0x0A2C SharePoint Foundation Workflow Infrastructure 98d8 Unexpected ...tance(SPWorkflow workflow) at Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut) at Microsoft.SharePoint.Workflow.SPWorkflowManager.RunWorkflowElev(SPWorkflow workflow, Collection`1 events, SPWorkflowRunOptionsInternal runOptions)
Check Active Workflows Action
Below is the code that will check to see if there is an action running on a workflow item. The code is straight forward and calls my helper class that I created earlier.
public class CheckActiveWorkflowsAction : Activity
{
#region Properties
public static DependencyProperty SiteCollectionUrlProperty = DependencyProperty.Register("SiteCollectionUrl", typeof(string), typeof(CheckActiveWorkflowsAction));
[Description("Site Collection URL")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string SiteCollectionUrl
{
get
{
return ((string)(base.GetValue(CheckActiveWorkflowsAction.SiteCollectionUrlProperty)));
}
set
{
base.SetValue(CheckActiveWorkflowsAction.SiteCollectionUrlProperty, value);
}
}
public static DependencyProperty WebUrlProperty = DependencyProperty.Register("WebUrl", typeof(string), typeof(CheckActiveWorkflowsAction));
[Description("Web Url")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string WebUrl
{
get
{
return ((string)(base.GetValue(CheckActiveWorkflowsAction.WebUrlProperty)));
}
set
{
base.SetValue(CheckActiveWorkflowsAction.WebUrlProperty, value);
}
}
public static DependencyProperty ListNameProperty = DependencyProperty.Register("ListName", typeof(string), typeof(CheckActiveWorkflowsAction));
[Description("List Name")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string ListName
{
get
{
return ((string)(base.GetValue(CheckActiveWorkflowsAction.ListNameProperty)));
}
set
{
base.SetValue(CheckActiveWorkflowsAction.ListNameProperty, value);
}
}
public static DependencyProperty ItemIDProperty = DependencyProperty.Register("ItemID", typeof(int), typeof(CheckActiveWorkflowsAction));
[Description("Item ID")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public int ItemID
{
get
{
return ((int)(base.GetValue(CheckActiveWorkflowsAction.ItemIDProperty)));
}
set
{
base.SetValue(CheckActiveWorkflowsAction.ItemIDProperty, value);
}
}
public static DependencyProperty HasActiveProperty = DependencyProperty.Register("HasActive", typeof(bool), typeof(CheckActiveWorkflowsAction));
[Description("Has Active")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public bool HasActive
{
get
{
return ((bool)(base.GetValue(CheckActiveWorkflowsAction.HasActiveProperty)));
}
set
{
base.SetValue(CheckActiveWorkflowsAction.HasActiveProperty, value);
}
}
public static DependencyProperty WorkflowNamesProperty = DependencyProperty.Register("WorkflowNames", typeof(string), typeof(CheckActiveWorkflowsAction));
[Description("Workfow Names")]
[Category("Custom Workflow")]
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string WorkflowNames
{
get
{
return ((string)(base.GetValue(CheckActiveWorkflowsAction.WorkflowNamesProperty)));
}
set
{
base.SetValue(CheckActiveWorkflowsAction.WorkflowNamesProperty, value);
}
}
#endregion
#region Methods
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
WorkflowHelper workflowHelper = new WorkflowHelper(this.SiteCollectionUrl, this.WebUrl, this.ListName, this.ItemID);
this.HasActive = workflowHelper.ItemHasActiveWorkflows(this.WorkflowNames);
return ActivityExecutionStatus.Closed;
}
#endregion
}
Deployment
The deployment of this solution was pretty easy with Visual Studio 2010.
· I created an empty SharePoint 2010 project.
· Added the above code.
· Added a Site Collection level Feature.
· Added a SharePoint mapped folder called “Workflow”
· Create a new file called InitWorkflowAction.actions in the Workflow folder.
The InitWorkflowAction.actions file describes my custom actions and makes them available to design tools such as SharePoint Designer 2010 to create a declarative workflow. Information below is very straight forward. It defines the sentence users will fill in and what type of data will be consumed or returned from the methods I created earlier.
<WorkflowInfo>
<Actions Sequential="then" Parallel="and">
<Action Name="Start Workflow"
Assembly="My.Activities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7cb64b163bd9c1db"
ClassName="My.Activities.InitWorkflowAction"
AppliesTo="all"
Category="Custom Workflow">
<RuleDesigner Sentence="Initiate workflow %4 on item %5 in list %3 in Web %2 in Site Collection %1">
<FieldBind Field="SiteCollectionUrl"
Text="Site Collection Url"
Id="1"
DesignerType="TextBox" />
<FieldBind Field="WebUrl"
Text="Web Url"
Id="2"
DesignerType="TextBox" />
<FieldBind Field="ListName"
Text="List Name"
Id="3"
DesignerType="TextBox" />
<FieldBind Field="WorkflowName"
Text="Workflow Name"
Id="4"
DesignerType="TextBox" />
<FieldBind Field="ItemID"
Text="Item ID"
Id="5"
DesignerType="Integer" />
</RuleDesigner>
<Parameters>
<Parameter Name="SiteCollectionUrl"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="Site Collection Url"/>
<Parameter Name="WebUrl"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="Web Url"/>
<Parameter Name="ListName"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="List Name"/>
<Parameter Name="WorkflowName"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="Workflow Name"/>
<Parameter Name="ItemID"
Type="System.Int32, mscorlib"
Direction="In"
DesignerType="Integer"
Description="Item ID"/>
</Parameters>
</Action>
<Action Name="Check Active Workflow"
Assembly="My.Activities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=7cb64b163bd9c1db"
ClassName="My.Activities.CheckActiveWorkflowsAction"
AppliesTo="all"
Category="Custom Workflow">
<RuleDesigner Sentence="Check if workflows %6 on item item %4 in list %3 in Web %2 in Site Collection %1 has a running workflow (Output to %5)">
<FieldBind Field="SiteCollectionUrl"
Text="Site Collection Url"
Id="1"
DesignerType="TextBox" />
<FieldBind Field="WebUrl"
Text="Web Url"
Id="2"
DesignerType="TextBox" />
<FieldBind Field="ListName"
Text="List Name"
Id="3"
DesignerType="TextBox" />
<FieldBind Field="ItemID"
Text="Item ID"
Id="4"
DesignerType="Integer" />
<FieldBind Field="HasActive"
Text="Has Active"
Id="5"
DesignerType="ParameterNames" />
<FieldBind Field="WorkflowNames"
Text="Comma delimited list of workflow names"
Id="6"
DesignerType="TextBox" />
</RuleDesigner>
<Parameters>
<Parameter Name="SiteCollectionUrl"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="Site Collection Url"/>
<Parameter Name="WebUrl"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="Web Url"/>
<Parameter Name="ListName"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="List Name"/>
<Parameter Name="ItemID"
Type="System.Int32, mscorlib"
Direction="In"
DesignerType="Integer"
Description="Item ID"/>
<Parameter Name="HasActive"
Type="System.Boolean, mscorlib"
Direction="In"
DesignerType="ParameterNames"
Description="Has Active"/>
<Parameter Name="WorkflowNames"
Type="System.String, mscorlib"
Direction="In"
DesignerType="TextBox"
Description="Comma delimited list of workflow names"/>
</Parameters>
</Action>
</Actions>
</WorkflowInfo>
Using Custom Actions in SharePoint Designer 2010
Now I am going to show you how I used the custom actions in my workflow. Earlier in this series you saw that I had created five different SharePoint Visio 2010 workflow diagrams. I am going to skip documenting the steps on how to bring the Visio diagrams into SharePoint Designer as that is a pretty straight forward process.
Below is a screenshot of the Initiate Process workflow. The first Action is my custom action that checks to see if there is already a workflow running for the custom list item. You will notice that the sentence displayed here corresponds with the sentence in the InitWorkflowAction.actions file. Also note the first parameter is a comma delimited list of all the other workflows (Review,Manager Review,Resubmit Request,Complete Request).
Next I take the value returned from my custom action and check to see if it Yes or No. If it is No, that means there are no running workflows and that I should initiate the Review Workflow. The third sentence in the diagram below captures this. I will initiate the Review workflow on the current item and send a notification email. Otherwise the workflow will not be started and the user will be notified.
Note that for the configuration of this workflow, it is the only one that supports allowing the workflow to be started manually. All of the other workflows I have created have no checkboxes checked for the Start Options section. This reduces the potential for user errors when starting the workflow for the item. The reason why is that we always want users to start with the Initiate Process workflow and let the other workflows be started based on business rules.
Next I have another workflow called Review that corresponds to the Visio diagram in the previous part of this series. Notice again I simply wire into the custom action StartWorkflow to start Manager Review, Complete Review or Resubmit Request.
Below is the Manager Review workflow. As you can see if the Manager approves the Complete Request workflow will be called otherwise the Resubmit Request workflow will be called.
Next is the Resubmit Request workflow. The workflow checks to see if the user cancels the workflow. If they do, the item will be updated and an email will be sent. Otherwise, the item will go back to the Review workflow (for re-review).
Finally the Complete Request workflow is below. I have not done much with it at this time but more can be added.
So now once I validate and deploy my workflow I can initiate it on an item. Below is a screenshot of a user initiate the process for an item. Notice only the Initiate Process workflow is available.
Once I have started the workflow I come back to the workflow status screen. Here you see the Review workflow is In Progress. Notice that the Initiate Process workflow is still available. Since the workflow is in progress I want to make sure that I cannot initiate the entire workflow again while it is current running.
Below is a screenshot of the completed workflow.
Now you can see I was able to chain together several workflows that as a whole make up a larger business process. Pretty neat.
Sandbox Solutions
I alluded earlier that I really wanted to make this a sandbox solution. Why? Because I believe that you should always develop for the Sandbox first because it quick to deploy solutions, it is secure, ensures good performance and works well with Office365.
Here are some good resources on how to deploy actions into the SharePoint 2010 Sandbox:
· http://msdn.microsoft.com/en-us/library/ff798499.aspx
· http://msdn.microsoft.com/en-us/library/ff630175.aspx
· http://msdn.microsoft.com/en-us/library/ff798389.aspx
· http://www.wictorwilen.se/Post/Sandboxed-workflow-activities-in-SharePoint-2010.aspx
The process is a little different and the code above would change a tiny bit so that it is scoped to a Site Collection only. However fundamentally there is not much difference.
When I deployed the custom actions and created the workflows I would get errors initiating the workflows. I went into the logs and found the following.
SPUCWorkerProcessProxy.exe (0x1E70) 0x1EC0 SharePoint Foundation Workflow Infrastructure 72er Medium System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.SharePoint.Library.SPRequest.ClearAllVars(String bstrUrl) at Microsoft.SharePoint.SPListItem.PrepareItemForUpdate(SPWeb web, Boolean bMigration, Boolean& bAdd, Boolean& bPublish, Object& objAttachmentNames, Object& objAttachmentContents, Int32& parentFolderId) at Microsoft.SharePoint.SPListItem.UpdateInternal(Boolean bSystem, Boolean bPreserveItemVersion, Guid newGuidOnAdd, Boolean bMigration, Boolean bPublish, Boolean bNoVersion, Boolean bCheckOut, Boolean bCheckin, Boolean suppressAfterEvents, String filename) at Microsoft.SharePoint.SPListItem.Update() at Microsoft.SharePoint.Workflow.SPWinOEWSSService.CommitUpdateListItem(Transaction txn, Object[] transData)
SPUCWorkerProcessProxy.exe (0x1E70) 0x1EC0 SharePoint Foundation Workflow Infrastructure 72fe High Error in commiting pending workflow batch items: System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.SharePoint.Library.SPRequest.ClearAllVars(String bstrUrl) at Microsoft.SharePoint.SPListItem.PrepareItemForUpdate(SPWeb web, Boolean bMigration, Boolean& bAdd, Boolean& bPublish, Object& objAttachmentNames, Object& objAttachmentContents, Int32& parentFolderId) at Microsoft.SharePoint.SPListItem.UpdateInternal(Boolean bSystem, Boolean bPreserveItemVersion, Guid newGuidOnAdd, Boolean bMigration, Boolean bPublish, Boolean bNoVersion, Boolean bCheckOut, Boolean bCheckin, Boolean suppressAfterEvents, String filename) at Microsoft.SharePoint.SPListItem.Update() at Microsoft.SharePoint.Workflow.SPWinOEWSSService.CommitUpdateListItem...
SPUCWorkerProcessProxy.exe (0x1E70) 0x1EC0 SharePoint Foundation Workflow Infrastructure 72fe High ...(Transaction txn, Object[] transData) at Microsoft.SharePoint.Workflow.SPPendingWorkBatch.Commit(Transaction transaction, ICollection items)
SPUCWorkerProcessProxy.exe (0x1E70) 0x1EC0 SharePoint Foundation Workflow Infrastructure 88xr Unexpected WinWF Internal Error, terminating workflow Id# 8d547a01-bdb8-44ac-b066-586c12367dc0
The information that was provided was not very good. Here are some observations I made.
· Note that the error is in SPUCWorkerProcessProxy.exe and not w3wp.exe. This basically means the entire workflow is running inside the Sandbox service because it has a reference to an action that is deployed there.
· I would only get this error the very first time the workflow run. From then on, it worked every time flawlessly. However if I stopped and restarted the Sandbox service manually, I would get the error again.
· I would also not get the error if Workflow A started a very simple Workflow B. For instance if Workflow B was sending an email, no issues. However if Workflow B had an approval process there would be an error.
After doing some research I came to the conclusion that this error occurs based on a combination of a few things.
1. When you build a workflow in SharePoint Designer 2010 it is a declarative workflow, not a complied workflow. The workflow will be compiled the first time the workflow is initiated. This is why it always takes a long time to start a workflow the very first time.
2. Sandbox solutions have a threshold of 20 seconds before it is determined the process too intensive and will stop the execution.
This combination would push me over the 20 seconds rule the very first time running the workflow. The solution would be to write some sort of script that could manually go through each workflow and initiating them so they would be compiled and ready to go when the user comes to manually start the workflow. I did not find that to be an acceptable solution because the Sandbox cache will be remove items from memory if they are not used often. This is why I did a full trust solution.
Next Part
Hopefully this gave you a pretty good idea of how simple it is to achieve this vision I have. Now in the next part of this series I am going to extend the solution a little bit to support my reporting requirements using Visio Services.