Getting around GAC problems when you deploy SharePoint solutions with PowerShell
In a previous post I wrote about how to replace the Visual Studio deployment steps with your own PowerShell script, which allows you to take full control over how you deploy solutions to your development machine.
In addition to enabling more advanced deployment scenarios, this allows you to use the same scripts when you deploy locally and to your test and production environments. The Visual Studio deployment engine is great – but it’s almost too helpful. It cleans up everything for you, automatically fixing all kinds of deployment conflicts.
This creates an artificial environment. In test or production, it’s possible that you never want to actually retract and reinstall your solution, just update it, and if you do reinstall it, Visual Studio is not around to fix deployment conflicts for you. So you may be headed for a nasty surprise when you take your solution to a test server for the first time, and discover there are all sorts of upgrade scenarios to consider. (For instance, it’s really difficult to overwrite existing files.)
If you use a PowerShell script to deploy from Visual Studio, you can use that same script in development, test and production. This makes your development environment more like real life, which is a Good Thing. And as I showed earlier, you can use different build configurations to choose between different deployment scenarios: Full reinstall, upgrade from previous version, etc.
But there are some stumbling blocks you may encounter once you leave the safe world of the Visual Studio deployment engine. I mentioned one earlier – getting your PowerShell scripts to run in 64-bit mode – and here’s another: The Global Assembly Cache.
Let’s say you’ve added a new feature and a new feature receiver to your solution, and you deploy it with a PowerShell script. You may experience that the feature can not be installed, because the receiver class couldn’t be found. Or you’ve changed the code in a feature receiver, and you experience that the old code is executed instead of a new one when you deploy.
Why? Because when a process loads an assembly from the Global Assembly Cache, it will keep using that version of the assembly for the rest of its life even if a new version has later been added to the GAC. Solution deployment is run by the SharePoint 2010 Timer service, and features are activated within your PowerShell process. So if something you’ve done earlier has caused one of these processes to load the assemblies you’re updating, an old version of your code will be used during solution deployment or feature activation.
The solution is to restart the timer service, and launch new PowerShell processes, whenever you require the latest version of an assembly to run.
(Update: The timer service problem described here happens when you retract a solution, then reinstall it with a new feature receiver, or a feature receiver with a changed name. The problem does not occur when you update an already installed solution. You still have to launch a new PowerShell process, though.)
To restart the timer service, run this:
And to launch a new PowerShell process, just call PowerShell from your script like this:
$scriptPath = split-path $myInvocation.MyCommand.Definition
powershell -file (join-path $scriptPath Retract-Solution.ps1) -solutionId $solutionId -url $url -package $package
powershell -file (join-path $scriptPath Install-Solution.ps1) -solutionId $solutionId -url $url -package $package
In this example I have one script that retracts a solution, and another that installs it. Each is launched in a separate process, ensuring that they’ll get a fresh copy of the solution assemblies, and before they install/uninstall the solutions, they restart the timer service.
(There may be other processes to consider in other scenarios – check the SharePoint logs to see which process is performing which operations.)
Why isn’t this a problem when you do Visual Studio deployment? Actually I have encountered that problem with Visual Studio, and had to restart it, but that may have been a bug in the beta. In any case, Visual Studio runs its deployment steps with a process called vssphost4, which works directly with the object model, not through the Timer service. So it takes care of this for you.
In other words, the Visual Studio deployment engine is really helpful when you’re getting started with SharePoint 2010, but not something you don’t want to rely on too much later on. If you develop SharePoint solutions, you have to face difficult deployment issues at some point. Better that you face them on your development machine than on a production server.