TL;DR: If you’re bin-deploying WCF Data Services you need to make sure that the .svc file contains the right version string (or no version string).
The idea for this post originated from an email I received yesterday. The author of the email, George Tsiokos (@gtsiokos), complained of a bug where updating from WCF Data Services 5.0 to 5.0.1 broke his WCF Data Service. Upon investigation it became clear that there was an easy fix for the short-term, and perhaps something we can do in 5.1.0 to make your life easier in the long-term.
What’s Bin Deploy?
We’ve been blogging about our goals for bin deploying applications for a while now. In a nutshell, bin deploy is the term for copying and pasting a folder to a remote machine and expecting it to work without any other prerequisites. In our case, we clearly still have the IIS prerequisite, but you shouldn’t have to run an installer on the server that GACs the Microsoft.Data.Services DLL.
Bin deploy is frequently necessary when dealing with hosted servers, where you may not have rights to install assemblies to the GAC. Bin deploy is also extremely useful in a number of other environments as it decreases the barriers to hosting a WCF Data Service. (Imagine not having to get your ops team to install something in order to try out WCF Data Services!)
Replicating the Problem
First, let’s walk through what’s actually happening. I’m going to do this in Visual Studio 2012, but this would happen similarly in Visual Studio 2010.
First, create an Empty ASP.NET Web Application. Then right-click the project and choose Add > New Item. Select WCF Data Service, assign the service a name, and click Add. (Remember that in Visual Studio 2012, the item template actually adds the reference to the NuGet package on your behalf. If you’re in Visual Studio 2010, you should add the NuGet package now.)
Stub enough code into the service to make it load properly. In our case, this is actually enough to load the service (though admittedly it’s not very useful):
using System.Data.Services; namespace OData101.UpdateTheSvcFileWhenBinDeploying { public class BinDeploy : DataService{ } public class DummyContext { } }
Press F5 to debug the project. While the debugger is attached, open the Modules window (Ctrl+D,M). Notice that Microsoft.Data.Services 5.0.0.50627 is loaded:
Now update your NuGet package to 5.0.1 or some subsequent version. (In this example I updated to 5.0.2.) Debug again, and look at the difference in the Modules window:
In this case we have two versions of Microsoft.Data.Services loaded. We pulled 5.0.2 from the bin deploy folder and we still have 5.0.0.50627 loaded from the GAC. Were you to bin deploy this application as-is, it would fail on the server with an error similar to the following:
Could not load file or assembly 'Microsoft.Data.Services, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
So why is the service loading both assemblies? If you look at your .svc file (you need to right-click it and choose View Markup), you’ll see something like the following line in it:
<%@ ServiceHost Language="C#" Factory="System.Data.Services.DataServiceHostFactory, Microsoft.Data.Services, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Service="OData101.UpdateTheSvcFileWhenBinDeploying.BinDeploy" %>
That 5.0.0.0 string is what is causing the GACed version of Microsoft.Data.Services to be loaded.
Resolving the Problem
For the short term, you have two options:
- Change the version number to the right number. The first three digits (major/minor/patch) are the significant digits; assembly resolution will ignore the final digit.
- Remove the version number entirely. (You should remove the entire name/value pair and the trailing comma.)
Either of these changes will allow you to successfully bin deploy the service.
A Permanent Fix?
We’re looking at what we can do to provide a better experience here. We believe that we will be able to leverage the PowerShell script functionality in NuGet to at least advise, if not outright change, that value.
So what do you think? Would you feel comfortable with a package update making a change to your .svc file? Would you rather just have a text file pop up with a message that says you need to go update that value manually? Can you think of a better solution? We’d love to hear your thoughts and ideas in the comments below.