3/20/2009I thought it would be instructive to describe how I build and deploy a SharePoint solution that I have built in Visual Studio 2008. I put this process together before I was aware of WSPBuilder, and probably before WSPBuilder was as popular and mature as it is now. That means that I created my solution manifest and my diamond directive file manually. It also means that although I use the structure of the 12 hive in my solution, I don't do it in quite the same way that you would with WSPBuilder. I also find that the out of the box VS2008 / VSeWSS 1.2 support for workflow development doesn't do solutions in the way I want. I set up my Visual Studio project to do the following on every build ( side note: additional build modes that have different behaviors are sometimes desired - perhaps I'll set that up for my next project). As background, note that I am working in a virtual machine that has MOSS and Visual Studio installed locally. The Post-Build script in Visual Studio 2008 for my project: time /T cd ..\..\deployment call RollbackDeployment.bat http://%COMPUTERNAME%/pathToSiteCollection <solutionName> echo end of rollback time /T copy $(TargetPath) $(ProjectDir)WebSolutionPackage echo start install call Install.bat http://%COMPUTERNAME%/pathToSiteCollection <solutionName> time /T What does RollbackDeployment.bat do? It un-installs the previous build: if "%1"=="" GOTO Problem echo Retracting previous version of Solution echo CWD is %CD% rem URL to site collection is %1 and solution name is %2 call RetractSolutionPackage.cmd %1 %2 echo Deleting previous version of solution call DeleteSolutionPackage.cmd %2
goto TheEnd :Problem @ECHO OFF echo You must specify the url of the site collection. :TheEnd RetractSolutionPackage.cmd does this:
rem STSADM is in the path and so is PowerShell rem If you are building a workflow, you may want to delete the workflow association before you deactivate its feature. rem I use a bit of PowerShell that you can find at codeplex.com/psbb to do that. powershell.exe -NoLogo -Command ".\DeleteAssocation.ps1" stsadm -o deactivatefeature -name %2 -url %1 -force rem Note that here I assume my feature name is almost the saem as the WSP filename. stsadm -o retractsolution -name %2.wsp -immediate stsadm -o execadmsvcjobs DeleteSolutionPackage.cmd not surprisingly does this: stsadm -o deletesolution -name %1.wsp Now we are ready to install our new build. Install.bat does this: if "%1"=="" GOTO Problem if "%2"=="" GOTO Problem echo Building package call CreateSolutionPackage.cmd %2 IF %ERRORLEVEL% NEQ 0 EXIT 1 copy "..\WebSolutionPackage\%2.wsp" "."
echo Installing Solution call InstallSolutionPackage.cmd %2 echo Deploying Solution call DeploySolutionPackage.cmd %1 %2 %3 rem If we need to restart the OWSTimer service (e.g. for workflows that have delay activities), we use the next two lines. net stop sptimerv3 net start sptimerv3 echo Done! rem pause goto TheEnd :Problem @ECHO OFF echo You must specify the url of the site collection and the package name.
:TheEnd CreateSolutionPackages does this: cd ..\WebSolutionPackage if EXIST %1.wsp del %1.wsp echo Building DDF file echo CWD is %CD% "C:\Program Files\Microsoft Visual Studio 9.0\SmartDevices\SDK\SDKTools\makecab" /f package.ddf IF %ERRORLEVEL% NEQ 0 EXIT 1 del setup.inf del setup.rpt rem Next step is so I can easily open the wsp in Windows Explorer to see what's inside. copy %1.wsp %1.cab rem to open a Windows Explorer window where you can see the .wsp and the .cab, uncomment the next line. rem start . cd ..\Deployment InstallSolutionPackage does this: stsadm -o addsolution -filename %1.wsp IF %ERRORLEVEL% NEQ 0 EXIT 1 DeploySolutionPackage does this: stsadm -o deploysolution -name %2.wsp -immediate -allowgacdeployment IF ERRORLEVEL 0 stsadm -o execadmsvcjobs IF ERRORLEVEL 0 stsadm -o activatefeature -name %2 -url %1 rem Next line is only used for a workflow project. It creates the workflow association IF ERRORLEVEL 0 C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe -NoLogo -Command ".\MakeAssociation.ps1"
So now you can see how I get my project to deploy on build. Hope you find this helpful. --Michael 2/18/2009I have a task list, and I have added a calculated value column to it. The calculated value column returns a text string which is recognized as a URL and is a clickable link. The formula for the column is =concatenate("http://server/managedpath/sitecoll/site/_layouts/UpdateSomethingStatus.aspx?TID=",ID). When you click on the link, the target page checks a web service to see if one of the columns in the task list (the "Is A" column) needs to be updated, if so updates that column, and then redirects back to the task list. The code does not touch the calculated value column at all. When the column gets updated, the calculated value field drops the value of the ID field from the displayed link. WHY? Here is a picture. The calculated value column is named Recheck. See how the there is no number to the right of "TID=" in the first item, but there is in the second item? Of course, all items have an ID, so why did this one disappear? Ideas? Michael 2/16/2009I prefer to blog about solutions rather than problems, but lately I've been running into more of the later... Here's one. I have a list with a workflow association, and when I try to remove the workflow association in my development environment, SQL Server goes nuts and eats up all the CPU. Interactive performance degrades and the only thing I can do is restart the SQL Server service. My workaround at this point is just to rename the workflow association to include the word "Bad" in the name, so I know not to try to delete it again. I suspect the only way to fix this is to go into the content database and do some table editing directly, but that is a strictly forbidden action unless under the supervision of Microsoft Support, and it's not worth a call to them at this point. Though if anyone has seen this happen before or has any idea why it happens and how a workflow association can "go bad", I'd like to hear about it. --Michael I've just posted a question on the MSDN forums as follows: I have a Task list that has two content types that inherit from Workflow Task. Let's call them CT1 and CT2. CT2 has a Business Data Column while the others do not. This Task list can contain several thousand records, though the number of active tasks at any given time is small (e.g. 20). The Business Data Column gets its data from a web service. I have a view that displays only the active tasks, and includes the business data column in the columns displayed. When I click on the update link (the circular green arrows at the top of the business data column), the subsequent pages warns that it will update ALL items in the list, not just the ones in the current view. Is it possible to restrict the update to only the items in the view? I posted that at http://social.msdn.microsoft.com/Forums/en-US/sharepointbdc/thread/fae084a3-0fdf-4951-a8f9-d0229a4b0a83 . In my scenario, updating only a few records is perfectly reasonable, and the time that it would take to update all records would be enough to make the users unhappy. In my scenario, a user might want to run the update several times a day, and really only cares about making sure they have the latest data for a very small number of rows. I'd like to be able to offer the users a way to update only a single record at a time, or only the records in their view. If you have any suggestions, please post a comment here, on Twitter, or in the MSDN forum. Michael On Friday, I was debugging a SharePoint workflow that I built in Visual Studio 2008. When I ran it, then stepped through the running workflow in the debugger, the designer view of the running XOML did NOT match the designer view of the workflow. In fact, the "live" XOML that was generated by the debugger was a visualization of an old build of my codebase. WTF? In particular, I had a parallel activity in my workflow, with 5 branches. In my current build, I had commented out branches 2-5, and renamed all the activities in branch 1. When my code ran, I could tell by the messages I was writing to the history list that the current version of my workflow was indeed running. But when I stepped into it, the "live" XOML designer view that the debugger created had all 5 branches of parallel activity enabled, and branch 1 had all the old names. How is that even possible? Michael 5/30/2008This is potentially a much bigger question, but I'll just address the narrow section of code migration from a hardware/software level, what I would recommend is that each developer have their own Virtual Machine which is a Windows Server with SQL Server and MOSS. Each developer does their development on their personal VM (either running at their desktop or on a VM server), and each developer produces WSPs containing Features. These WSPs get deployed to a single common farm for integration testing, and from there, with additional testing and due process, they get promoted to subsequent environments. Graphically, here is a picture representing this, with the code flowing from the bottom up. Some organizations have different names for Integration and Staging, for example, Development and Test. --Michael 5/29/2008Once I remember reading about a data center that altered the air conditioning level of the room occupied by the system admins, and made the room's "weather" more turbulent when a server started reporting an error. The result was that the system administrators could feel the server health without even having to look at anything. Similarly, Martin Woodward has hooked up a Nabaztag Rabbit (no, not a Nazgul Rabbit) to his TFS build process. It made me think about what you could hook it up to in a SharePoint environment. Thinking along the lines of a build process, you put a rabbit on the desk of your SharePoint developer, and then when your SharePoint Farm Administrator uses STSADM to deploy a .WSP from that developer, the result is sent to the rabbit. If STSADM throws an error, the ears go down. I'd bet there's a way to tie this into any of the stats that you would want to monitor (CPU busy-ness, failed logins, etc), and I'd bet you could tie it into Server Center Operations Manager. --Michael 5/28/2008So I got a MOSS VM from a class a while ago, and I've been using it for a while - for a variety of projects, any time it wasn't practical to take the time to build a development environment from scratch. It was built using an evaluation version of Windows Server 2003 R2, and it finally expired. I finished development on one of my MOSS workflows last Friday afternoon, and it expired Friday night, so when I went to use it Monday morning, it happily told me that it would shut down in an hour. Well, I have an non-evaluation version (MSDN license I think) of the OS that I can use, so I upgraded the OS. Not exactly a smooth process. First of all, I shut down the VM and copied it to another disk (USB Hard drives are Great! I really like my Western Digital 250GB external hard drive ). Attempt #1: Boot the VM from the image for Windows Server 2003 R2 CD 1. Go through the repair process. It spends a LONG time on the Saving Configuration screen, and I think it's dead, but it's not, it just takes a loooooooooooooooooong time to finish. It does, but it reports that it couldn't find a share that it was using to save configuration information. That's not good. I log in and the desktop is intact, but when I open IE to my MOSS site I get HTTP 500 error - internal server error. Uh oh, that's not good. Because it gave me that error about not finding the configuration information it had written to a share, I decide I should just start over. Attempt #2. I realized by browsing several KB articles, that I could start the upgrade from within the existing OS. So I start with a copy of my VHD from before I started the OS repair, and I kick off the upgrade from the GUI. I put in the product key and it runs over night, and this morning it is upgraded and no longer time-bombed. I open Central Admin and - Eeek! c:\windows\microsoft.net\framework\v2.0.50727\mscorwks.dll could not be loaded It's on the filesystem, but that's not good enough. So I "reinstall" the 2.0 SP1 framework. I say "reinstall" because I went into Add/Remove programs and clicked the Change button on that item, and instead of it asking if I wanted to repair or remove, it just did stuff (repair I assume, because the Framework and the service pack were still there afterwards). After repairing .NET 2.0 SP1, Central Admin came up. For good measure, I repaired the 3.0 SP1 and 3.5 Frameworks too, and ran Windows Update (43 updates, oh my!). Finally though, my MOSS site and Central Admin were working again, and the time bomb was gone. --Michael 5/22/2008Anytime I'm developing something in SharePoint, I'll get to a point where I load a SharePoint page, and it says "An unknown error has occurred." or "An unexpected error has occurred.". There are two things you can do about this. Turn custom errors off, and turn up the verbosity on the logging. To turn custom errors off, you make a change or two to the web.config. You can turn this into a Feature if you want ( or use the one someone else built - http://www.codeplex.com/features - see "Debug Config Feature"), but the most immediate way is just to change the web.config for your web application, as explained here http://blog.solanite.com/keith/Lists/Posts/Post.aspx?ID=10 and here http://blog.thekid.me.uk/archive/2007/02/15/a-solution-to-quot-an-unexpected-error-has-occurred-quot-in-wss-v3.aspx. To turn the logging verbosity up, go into Central Administration, then Operations, and click on Diagnostic Logging. There is a section in the middle where you can choose a category, and change the logging level for both the event log and the ULS log (the ULS log files usually end up in the 12 hive, in the LOGS folder). I recently was debugging a custom Workflow I wrote, and I found turning up the logging to Verbose for the ULS log for the General, Workflow, and Feature Infrastructure categories was helpful. I'd include pictures, but I don't have my development VPC with me at the moment... --Michael
|
|
|
|
|