So what happens when you’ve built out a SharePoint Designer workflow with a Pause Until Date activity, and then the date changes on you? Obviously, we want to the workflow to handle this situation and update the Delay logic accordingly.

Scenario

Let’s assume we have a Date Received column. After 2 weeks of initial item creation, we want to send a reminder notification to the user. So based on the value of Date Received column, add 14 days, and if Today matches that value, then send a notification. For this we need the Pause Until Date activity, so we do a quick evaluation, if there is a match, send the reminder, otherwise, pause until we reach that date.

  1. User enters Jan 13, 2012 in date received and creates new item.
  2. Workflow kicks off and determines that Jan 13, 2012 + 14 days is equal to Jan 27, 2012.
  3. Workflow checks if Today is equal to Jan 27, 2012. If it is, send the email reminder.
  4. If it isn’t, Pause Until Jan 27, 2012. You will see the pause activity log to the workflow history list the day it’s planning to pause until.

Perfect right, works great. Now what happens when a user edits the item and changes the date received to Jan 17, 2012. We want the delay to postpone until the 31st of Jan, not the 27th. I’ve read a great deal of posts that document how others have tackled this problem, ranging from an event handler to some sort of custom workflow logic. In our case, since the forms were custom ASP.NET forms submitting programmatically to the list, it was easy enough for me to track any changes to the date received column, and if I do find that it has changed, I simply stop and restart the workflow within the submit event. The logic looks like this:

// stop and restart the workflow if date received is different
if (dtcDateReceived.SelectedDate.ToShortDateString() != dateReceived.Value)
{
    // stop workflow
    SPWorkflowCollection itemWorkflowCollection= item.Workflows;
 
    SPWorkflowAssociation workflowAss = yearEnd.WorkflowAssociations[new Guid("369dcef7-b35c-48f1-bf2f-5b9f53d568ee")];
 
    foreach (SPWorkflow itemWorkflow in itemWorkflowCollection)
    {
        if (itemWorkflow.ParentAssociation.Id == workflowAss.Id && (itemWorkflow.InternalState & SPWorkflowState.Running) == SPWorkflowState.Running)
        {
            SPWorkflowManager.CancelWorkflow(itemWorkflow);
            site.WorkflowManager.StartWorkflow(item, workflowAss, workflowAss.AssociationData);
            break;
        }
    }
}

For completeness, this is how I set the hidden field on load that stores the original Date Received value.

// set date received to see if it changes
 dateReceived.Value = Convert.ToDateTime(yearEndItem["Date Received"]).ToShortDateString();

Thanks Tony for the original post that helped me build out the logic above:

http://www.tonytestasworld.com/post/Howto-Start-a-Sharepoint-Workflow-Programmatically.aspx

Tagged with:  

Why Don’t You Use InfoPath?

On January 23, 2012, in SharePoint 2007, by shereen

I get asked this question a lot.

Hey Shereen, Why don’t you use InfoPath more often in your projects?

To which I often reply, it’s the 80/20 rule. InfoPath doesn’t get me all the way there, and to invest that much time and effort only to hit some project impeding roadblocks is not a conversation I like to have with our clients. It’s not fun, no one enjoys explaining why you CAN’T do something, because when it all boils down, clients are only interested in the solution.

Recently, however, I was given the opportunity to work with InfoPath again, and it’s reminded me in many ways, the pros and cons of using this tool. So I’ve jotted some notes down, and I’ll share with the rest of you, and if we can have a constructive, intelligent debate about this, I’m all for it. Keep in mind this is InfoPath 2007.

Let’s start with the Pros.

  1. It’s incredibly easy to do some basics in InfoPath. Adding controls to a page, validating those controls. Applying conditions that define when to show/hide specific content, or when to display that content in a different way. Tab order, submission and layout are all examples of things we can do well in InfoPath. This is something any power user can do, and probably do well.
  2. It makes it possible for power users to maintain a form post-development and well into the future. The same is not true for a custom form or web part built in ASP.NET I don’t care how ‘powerful‘ your users think they are.
  3. It’s definitely a bit easier to deal with Lookup columns and People or Group columns in the sense that it takes very little effort to wire them up and save/load from those controls within InfoPath. These are often problematic in standard ASP.NET form development.
  4. Repeating tables are great, these take little to no effort to add to the page and give users a lot of flexibility so that they may dynamically add or remove additional rows.

So definitely some good things we can do with InfoPath, however, there are definitely some pitfalls that make you go ‘ARRGHHHH‘!

  1. You can’t use a Contact Selector field and publish to a column of type Person or Group, you have to use either a workflow to populate these fields or custom code. A lot of times, we use these fields to power views with the [Me] keyword to display personalized views of the data. This is hard to do when a Contact Selector translates to a Single Line of Text. It also starts to challenge the Ease Of Administration principle I talked about above, because now users have to maintain a workflow or a section of custom code to get past this hurdle.
  2. In terms of order and organization of the Data Sources, it sucks. Any field that you create and then remove, does not get removed from the data source (which I understand), and you have to manually manage and maintain your data sources to keep it clean. I can honestly waste a ton of time formatting and moving fields into the appropriate containers and ensuring that overall, the data source stays clean. Maybe I’m just being anal, but it’s not something I particularly enjoy – I do feel it’s necessary though. It can get pretty hard to read if you have a form with 100 fields and you let it get out of control.
  3. It’s not easy adding expandable/collapsable regions. If you don’t agree, let’s throw up a challenge where you build out your regions in InfoPath and I’ll do it in html/css/jQuery and we’ll see who finishes first.
  4. Repeating tables only save the first row of data, not subsequent rows. So anytime you do use a repeating table, don’t plan on using that information for any views or filters of any kind. Normally though, this isn’t something I find myself needing to do often, but when it does come up, it’s kind of a pain that I can’t do it.
  5. Rich text formatting is not supported in browser based forms.
  6. There is no way that I know of to add a header and footer. If you’ve got a header or footer and multiple views, any change to those will have to be applied to each view. I’m not positive about this one, but if anyone corrects me on this, I’d be happy to update this post.

Tips

  1. When setting up tabbing between sections, it’s wise to setup a break in numbers in case it changes down the road. Otherwise imagine defining your tabbing order and then inserting a field at tab order 10.

So to summarize, I definitely see the power of InfoPath and if I can keep the requirements dead simple, and there’s flexibility when we hit roadblocks, I don’t see why this wouldn’t be the faster approach to form development. I’d probably recommend it.

However, if the reverse is true, and I know there will be business workflow or requirements that will make working with InfoPath a challenge, I’ll opt for the custom web form route, because that guarantees me no limitations to what I can do. And it’s likely faster.

It all comes down to an evaluation of the requirements and the prioritization of features over simplicity and maintainability that will ultimately guide which route I take.

If anyone would like to add to this, or has a suggestion for something I overlooked, ping me here or send me a tweet on twitter. I’m all for finding better and more efficient ways for getting things done.

Tagged with:  

If you’ve read my previous posts on FAST Search in SharePoint 2010, you’ll be familiar with my article where I describe the issues I had with the Content Distributor ports for FAST.

My initial research into this issue let me to the following blog: http://fastforum.info/viewtopic.php?f=6&t=223.

Basically the users commenting in this thread talk about an inconsistency between the Install_Info.txt file and the ContentDistributor.cfg file in terms of the port number which is set to 13390. It was always odd to me that the Install_Info.txt and ContentDistributor.cfg file were not consistent and many believe this to be incorrect.

The change that you would make would be an update to the FAST Search Connector in Central Admin, so that the port number reflects what’s in the ContentDistributor.cfg file. While this may work temporarily, this is INCORRECT!

The port for the Content Distributor should be AS IS reflected in the Install_Info.txt file. So 13391 if you stuck with the defaults.

Read the following from a KB article from MS:

The “Fast Connector SSA” may be incorrectly configured to use port 13390. The %FASTSEARCH%\install_info.txt” displays the Content Distributors with port “13391″, however the %FASTSEARCH%\etc\contentdistributor.cfg” displays port 13390. If the portfor the “Content Distributors” in the “Fast Connector SSA” was configured as “13390″, connectivity to FAST will fail. If this is the case, the “Content Distributors” in the “Fast Connector SSA” should be reconfigured to use port 13391 as stated in the install_info.txt.

Tagged with:  

I’m really excited to be down at SP Conf 2011 this year, along with my fellow colleagues @c0deNinja and @matthewcarriere.

We’re particularly eager this year because we’ve been working hard on the launch of our SharePoint line of add-ons: www.blackninjaparts.com. We’ve officially gone live today, just in time for SP Conf and we’ve got some super awesome t-shirts to give away throughout the week. You’ll see a few of us wearing them, so don’t hesitate to stop us anytime and grab yourself one before they’re all gone.

Black Ninja Parts Tshirt

We have a lot to offer with our web parts, super support being one of the main things you can expect. We’ll be doing our best to answer any questions, field any support issues, and overall, ensure our clients and customers get the best experience possible when purchasing with us.

We’ve also got a lot planned for the future in terms of more web parts and unique applications built right into SharePoint, so please, please, if you have any feedback or questions, reach out to one of us, we hope to surprise you with our quick and friendly response. We love it when we get superior customer support from the products we use, so our aim will be to provide our customers with the same level we’ve come to expect and appreciate from other vendors.

So check our the site, come get a shirt, and have a great week at SP Conf 2011. I hope to meet some of you there and look forward to participating in the live blogging that’s been setup by SharePointTechEdu.

 

I’ve been doing a fair bit of FAST search configuration and re-configuration lately, and I just wanted to point out a few things that are good to know and understand.

Let’s start with some basics. If you use the following guide for configuring FAST (and I usually do) http://technet.microsoft.com/en-us/library/ff381243.aspx, then you should be aware of:

  • You configure two service applications for FAST: FAST Content and FAST Query SSA. FAST Content is a FAST Search Connector. FAST Query SSA is FAST Search Query.
  • The FAST Content service application is where you configure your Content Sources and crawl MOST content. Please note that I say MOST and not ALL. Your user profiles or ‘People’ search, are crawled using the FAST Query SSA.

    Please reference this article for details: http://sptechland.wordpress.com/2010/10/08/fast-people-and-content-search/. This is a key thing to understand, because until you initiate a crawl for the Local SharePoint sites Content Source in the FAST Query SSA, you won’t see any people results in the People scope.
  • If you’re trying to figure out HOW to crawl your user profiles, make sure that the following url is added to your FAST Query SSA – Local SharePoint sites Content Source: sps3://serverurl.

Some other things I’ve noticed:

And finally, if you come across this error:

The search service is not able to connect to the machine that hosts the administration component. Verify that the administration component ’43fa5edd-3e14-4dba-b54c-7aad045dfdf7′ in search application ‘FASTContent’ is in a good state and try again.

Run the following command:

stsadm -o provisionservice -action start -servicename osearch14 -servicetype "Microsoft.Office.Server.Search.Administration.SearchService, Microsoft.Office.Server.Search, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
 

I thought I’d do a quick post for the visitors of my blog on a new initiative by SharePoint Nick called SharePoint Weekly.

So what is SharePoint Weekly. Well, as Nick describes it, it’s “a free, once weekly email round up of SharePoint news and articles.” If you’re like me at all, you really struggle with keeping up to date with all that goes on in a given day surrounding SharePoint. It’s so overwhelming at times, that I could easily spend my entire day reading through blogs and new content just to keep up with it all. I could repeat this every single day, that’s how quickly evolving this community is! At Black Ninja, we’re a bit unique, because we run an Apple shop, using VMWare Fusion to drive our Windows/SharePoint VMs and we are heavy into iOS and Ruby on Rails development. We’ve come to really love and absolutely rely on the weekly updates available in the iOS, Ruby on Rails and Javascript communities. I feel in some ways, the SharePoint side has been lacking a bit when it comes to this type of service.

For example, on the Ruby side, we have so many wonderful weekly podcasts and round ups for content. We’ve even sponsored some of them:

  • Ruby5 – Great 5 minute round up of all things Ruby for the week.
  • Ruby Weekly – Another great example, and very similar to the SharePoint Weekly format.
  • Javascript Weekly – Weekly updates on the javascript world.

I’m a huge fan of this idea, and I’m sure Nick would appreciate any feedback or ideas the community might have on making this service even better. I’m open to supporting it in anyway we can as well. I think what would also be interesting to see is if the SharePoint Weekly concept will need to be broken down further into different categories, such as SharePointDevWeekly, or SharePointAdminWeekly, etc.

So take a minute and sign up here: http://www.sharepointweekly.com/

Thanks Nick for taking the time out to set this up and maintain it weekly.

 

We’ve recently upgraded a server farm from SharePoint 2010 Server Search to SharePoint 2010 FAST Search and ran into a couple of issues with getting the content sources crawled correctly.

Scenario: We have a 2 server farm: a single application server, and a WFE. There is a separate SQL Server installation where we host our databases. FAST was installed on the application server, which it’s worth mentioning, was already running SharePoint 2010 Server Search successfully.

After going through the steps for installation, what we’ve got configured are two NEW service applications and one old one:

  1. FAST Search Connector
  2. FAST Query SSA
  3. Search Service Application 1 – to be deleted once FAST was configured correctly

FAST Search Connector is where we configure our content sources. In the case of the SharePoint content source that we had configured, a full crawl was generating several warnings and errors, but not a single success message. Something was not right.

Checking into the event logs, I found Event ID 2567.

Failed to connect to VCVANKMSSEARCH1.vci.local:13391 Failed to initialize session with document engine: Unable to resolve Contentdistributor

The issue for us was an error in the port listed for the Contentdistributor. Note: for those of you who did not install FAST personally, and need to know what settings were inputted during installation, you’ll find them in the root of the installation folder where FAST was installed.

\\FASTInstallationFolder\Install_Info.txt

Open the above file up, and locate the following configuration section:

---------------------------------------------------------------
 
FAST Search Content Search Service Application configuration
 
---------------------------------------------------------------
 
Content Distributors (for PowerShell SSA creation):   servername:13391
 
Content Distributors (for GUI SSA creation):          servername:13391
 
Default Content Collection Name:                      sp

Notice the port number. Now navigate to:

\\FASTInstallationFolder\etc\contentdistributor.cfg

When viewing the contentdistributor.cfg file, I was able to see that the port number was different from what was specified during installation. It was in fact set to 13390. So by looking at this setting, we know that the FAST Search Connector is going to be configured incorrectly as well.

Open Central Administration, Manage service applications. Click on the FAST Search Connector and select Properties in the Ribbon. Scroll down to the Content Distributors section and change the port number from 13391 to 13390.

In our case, I deleted and recreated the content source, and now the success messages are pouring in and search results are coming back. As always, I would love to know why the port for the Content Distributors was configured differently from what was specified during installation, but unfortunately I do not have the answer to that. If anyone does, ping me and I’ll update this post.

It’s also worth noting that now that my search results are being returned, I am still seeing Event ID 2567 pop up in the logs, and am currently investigating this. Also on my radar are several Timer errors: Event ID 6398 – Failed to communicate with the WCF service.

 

UPDATE: After trying several different calls to MS and being told by some that my only option was to upgrade to the Feb 2011 CU for MOSS, I finally got in touch with someone who was able to give me the CU I needed. According to MS, the CU was pulled due to an issue with Project Server. They seemed to indicate to me that it will be available again at some point, but with no concrete date for when that will be. So my advice, call and be persistent and try to get someone to send you a copy.


This issue has caused me quite a lot of grief and at the time of writing this post, is yet to be resolved.

Thanks to all who attempted to help out by providing links to the CU, I’m going to outline in this post what the issue is and why those links don’t work. Hopefully someone else can make use of this and get past where we are now.

I have a current production farm whose patch level is the MOSS August 2010 CU, or 12.0.0.6545. Let’s say I need to add a new server to this farm. If I download the SharePoint Server software for MOSS from the MS site and install it, I’ll end up with 12.0.0.6421, which is SP2. Makes sense. Downloads from MS should be at the SP level, and you apply the cumulative updates as required.

In our case, we required that we patch to August 2010 CU, so that we could run the configuration wizard on this server and add it to the farm. For those of you who don’t know, if the patch level of the server you are adding to the farm is DIFFERENT from the farm itself, the config wizard will fail with an access is denied error in the upgrade log file. So getting the right patch level is important.

Now let’s review what’s currently published on this site: http://blogs.technet.com/b/stefan_gossner/archive/2010/09/02/august-2010-cumulative-update-for-sharepoint-has-been-released.aspx.

Stefan kindly lists all of the CU information for the August 2010 update. Please note I’m not talking about SharePoint 2010 here, but rather the August 2010 CU for MOSS 2007. Anyways, let’s try the following two links from Stefan’s site:

WSS: http://support.microsoft.com/hotfix/KBHotfix.aspx?kbln=en-us&kbnum=2276474
MOSS: http://support.microsoft.com/hotfix/KBHotfix.aspx?kbln=en-us&kbnum=2276472

You will notice that the WSS link has a hotfix available for download, whereas the MOSS link gives you:

The KB article has no public hotfixes. Please contact support if you need immediate assistance.

This means the CU has been pulled. Several phone calls with MS have occurred and I’ve received confirmation from them that the August 2010 CU for MOSS has been pulled due to an issue that affects Project Server. How frustrating! I get that they’ve pulled it, but what about those customers not using Project Server in need of this CU?

It’s been suggested by others and MS that we upgrade the farm to the Feb 2011 MOSS CU. I understand that this is an option, but it’s really not. This will take us days worth of effort to test, plan and upgrade a QA, Staging, Production and Dev environment.

I have noticed that the individual updates that make up this CU are available for download, but I would feel much better patching this server to the exact same configuration as the others. I’m not confident that what’s available now is not different from what’s been pulled.

That’s it, that’s all I have for now, I will update this post as soon as I hear back from MS. They are attempting to get the CU for us in a back channel sort of way. Anyone who has additional information, I’d be happy to post.

Lesson Learned:

WHEN DOING AN INSTALLATION OF A PRODUCTION SHAREPOINT ENVIRONMENT, KEEP THE INSTALLATION FILES SOMEWHERE DOCUMENTED AND ACCESSIBLE SHOULD THEY BE PULLED IN THE FUTURE.

In Rails, we have a concept called Freeze Gems that’s similar to this idea:

Freezing Rails is recommended if you are using a Rails application for a business site or another production environment where stability is the most important concern. If you don’t freeze your application, there is a small possibility that your application might stop working due to compatibility problems when a new version of Rails is installed on our servers.

Reference: http://support.tigertech.net/freeze-rails

 

I want to clarify the well known WSS SP1 declarative workflow issue that’s found in abundance on the web. We ran into this recently when attempting to use the Start Another Workflow activity that comes with the Useful SharePoint Designer Custom Workflow activities codeplex solution. Actually, if you read through the comments on codeplex, others are having the same problem with nothing really identified as the fix. This post will outline our solution, along with some guidance on the recommended Microsoft route.

This issue is outlined in detail here: http://support.microsoft.com/kb/947284.

Directly from MS: After you install Windows SharePoint Services 3.0 SP1, declarative workflows do not start automatically if the following conditions are true:

  • The Windows SharePoint Services Web application runs under a user’s domain account.
  • The user logs in by using this domain account.
  • The site displays the user name as System Account.

So typically, when we install SharePoint 2007, we have a domain admin account that we do the installation under, or even a local administrator, and we specify a service account during installation that’s responsible for running our services and app pools. You’ll notice that when you log into SharePoint using this service account, regardless of the name of that service account, it will display System Account. This is important to understand.

What Microsoft is asking us to do is change the application pool, so it runs under someone other than what you’ve specified for the service account. So, if for example our service account upon installation was domain\wss_service, our app pool will run under domain\wss_service. You’ll need to change that to domain\new_account.

Ok so none of that was really new information, but I do want to shed some light on the issues that users are experiencing with the Start Another Workflow activity that was the original motivation behind this post. Basically, if you look through the codebase, Start Another Workflow uses elevation to do what it needs to do, to trigger the requested workflow. Elevation always runs under the credentials of the account specified to run the application pool. Read this post and it’s comment entirely to understand this process: http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.spsecurity.runwithelevatedprivileges.aspx.

Because we’re trying to trigger another workflow (that’s the whole point of this activity) and we’re doing it while elevated, thus running as the app pool account, IF this account also happens to be the System Account, you will receive the declarative workflow error. So, again, you either change that app pool account, or you can do something like this:

// even when taking the elevation out of this code, the workflow would still
// trigger as System Account. In theory, users may not have Start Workflow permissions
// on a given list, so it makes sense to impersonate and leverage a workflow_svc account
SPUser user = web.SiteUsers[@"domain\\new_account"];
// we could use: __Context.Web.CurrentUser.UserToken
// but what if user does not have access, so we use user instead
SPSite site2 = new SPSite(site.ID, user.UserToken);
SPWeb web2 = site2.OpenWeb();
 
// using the debugging information below, we are able to see the following output:
// user running under: Joe User
// site user: Sytem Account
// context user: Joe User
// so the web objected instantiated above is using the System Account context
string userString = "user running under:" + __Context.Web.CurrentUser.Name;
string siteUser = "site user:" + web.CurrentUser.Name;
string contextUser = "context user:" + web2.CurrentUser.Name;
 
Common.AddCommentWorkflowHistory(userString, executionContext, this.WorkflowInstanceId);
Common.AddCommentWorkflowHistory(siteUser, executionContext, this.WorkflowInstanceId);
Common.AddCommentWorkflowHistory(contextUser, executionContext, this.WorkflowInstanceId);
 
// so when we create our SPList object below, we have to use web2, not web
// so that we can make sure our workflow runs under the user context not System Account
// why don't we want to run under System Account? because SP1 prevents declarative workflows.
SPList list = web2.Lists[new Guid(ListId)];
 
SPListItem listItem = list.GetItemById(ListItem);
 
SPWorkflowAssociation myWorkflowAssoc = null;
 
//resolve any lookup parameters
string wkId = Common.ProcessStringField(executionContext, this.WorkflowIdentifier);
 
//find workflow association by name
myWorkflowAssoc = list.WorkflowAssociations.GetAssociationByName(wkId, System.Threading.Thread.CurrentThread.CurrentCulture);
 
if (myWorkflowAssoc != null)
 {   
     // using site2 to start the workflow is not enough, the listItem passed into the StartWorkflow
     // method has to have been instantiated using the web2 object
     site2.WorkflowManager.StartWorkflow(listItem, myWorkflowAssoc, myWorkflowAssoc.AssociationData, true);
}
 
site2.Close();
web2.Close();

The above code is a direct replacement of what’s currently in source on codeplex for the Start Another Workflow activity. This is just presented as an option to those not wanting to change their app pool configuration for whatever reason.

 

Karine Bosch’s blog post on the SharePoint DateTimeControl is really great for understanding how to use this control in your custom web parts or application pages. It’s probably one of the only really good resources out there on this control.

So to summarize, the SelectedDate property let’s us know what date the user has selected. However, if the user didn’t enter a date the SelectedDate property returns Today’s date. Huh?

This presents a problem because of form submission. Let’s review a scenario where this causes issues:

  1. User enters a date in a DateTimeControl: April 3, 2011.
  2. User submits. Date is saved as April 3, 2011 in the SharePoint DateTime field.
  3. User loads form, and clears out the date in the DateTimeControl and hits submit.
  4. Date is saved as April 1, 2011 (Today’s date).

We don’t want it saved as Today’s date, we want it saved as blank. To get around this, we constantly have to check whether a value is entered using the IsDateEmpty property, and if so, handle the save appropriately. See my code sample below for an example of this.

if (!dateControl.IsDateEmpty)
{
    item["Deadline"] = dateControl.SelectedDate;
}
else
{
    item["Deadline"] = null;
}