Thursday 19 July 2007

Sharepoint Development Tips 5- Customize MOSS TimerJob

No intention to steal the posts from other people here since Andrew Connell has posted a very nice and detailed article on his blog introducing how to create custom timer job on MOSS. He is kind enough to post his sample project as well.


In his article , he packaged the dll using solution file(*.wsp), here I just introduce how to deploy it using a simple feature if you don't want to add the whole deal with other dlls.

The only difference, as you might already find out, is the xml files. So for the feature.xml, it will be as following

and please note that the "Hidden" value is set to "True", for the UI user can use to turn on/off in sharepoint is using the application pool account to access the content DB, which will be permission denied if you don't grant your account to the DB. So it will fail when you activate the feature.
And the manifest file elements.xml is as following
Note that you have to specify a listtemplateid here, even though you don't want to bind it to any list or doc library.

At last, you should be cautious when changing the code and update the assembly. Sometimes even if you updated the GAC and did a iisreset, it still won't pick up the new one. You have to restart Windows! See my other post regarding this same problem with SPD workflow!

Thursday 5 July 2007

Sharepoint Development Tips 4- SPD workflow madness

As I introduced SPD workflow in my previous post,if all you need is simply customized activity and it's supposed to be stand-alone, i.e. doesn't need to be reused to another list in sharepoint, and you certainly don't want the hassle with init,complete forms with InfoPath, customized activity/condition with SPD's workflow designer is almost perfect choice. But when any offer looks too good to be true, it probably just is. Like the line in Supernatural, "This world just ain't coming without perks...", well, in the bad way in our case of course !-_-...

The catch is when you want to update your code using SPD, you will find the change you made will not be used by sharepoint. And as you come this far with it already, you know there's NO debugging support with SPD workflow. You really want to make sure it "somehow" just works anyway before you deploy it to the server. So how on earth we can make our updated dll work with the SPD workflow on the server? Well, you will have to live with the fact that you can't debug given the fact your dll will not contain huge amount of code. But to update the dll on the server, do the following.

1. Remove the workflow from your list in sharepoint
2. Shut down your SPD
3. Go to your website cache, on my XP pro the path for this is : "C:\Documents and Settings\%user%\Local Settings\Application Data\Microsoft\WebsiteCache", in vista , it's under different path:%System Drive%\Users\%user%AppData\Local\Microsoft\WebSiteCache(You will find it's a mistake to use Vista for professional development for now anyway). Delete everything you see there.
4. Copy the updated dll to the GAC on your server
5. IISRESET on your server
6. reopen SPD
7. Redeploy your workflow.


In this way, you will update your SPD workflow with latest dll. But I have run into the occasions that even above method will not update your dll. I ended up restarting the sharepoint server to get it updated(too much for a real-world software solution , is it?). Hopefully this will help you.

Update:
now every time I have to restart the sharepoint server to make changes. :(

Sharepoint Development Tips 3- Dealing with SPUser- the slippery object

Most of the time you will want to obtain the SPUser object from your sharepoint list. One thing that will defintely make you wonder is how you cast the listitem column containing user info to the SPUser object. If you go


SPUser thisUser = (SPUser)thisItem["User_Column"];




VS will not let you compile because the underlying type of your "User_Column" is just a string, so the cast will fail. So what you can do is to search & compare the user collection in your web site, and get the SPUser from the compared result like following:


private SPUser GetOwnerFromString(string _userString, SPWeb thisWeb)
{
//parse the string after the delimiter '#'
int delimIndex = _userString.IndexOf("#");
string userStr = _userString.Substring(delimIndex + 1);
SPUser owner = null;
foreach (SPUser thisUser in thisWeb.Users)
{
//if this is current user
if (thisUser.Name.ToLower().IndexOf(userStr.ToLower()) > -1)
{
owner = thisUser;
break;
}
}
return owner;
}


As you might have noticed, the delimiter to read the string is set to "#", that's because when you try to get the string from a column containing the user information, the string format will be scrambled up like "10283744#System Account". So the format is a random number + "#" + your user's display name.


This method will work if you populate the user list of sharepoint by users rather than by AD groups. I didn't try the AD group case but will do later.