Fixing RBS/Provider version mismatch issues
The
problem
Release of a new RBS library will cause the
providers developed with older version to not work due to version
mismatch.
The
symptoms
Let’s take an example of SharePoint to
understand where and how the problem might appear. On a running SharePoint
instance with the RBS client and RBS providers installed, after an upgrade of
the RBS client (being used by SharePoint), an error is thrown as below (assuming
the provider is a Filestream provider):
Microsoft.Data.SqlRemoteBlobs.RemoteBlobConfigurationException:
No provider of type <Filestream> found. Check the server configuration or
install the provider on the client.
One
scenario where this can happen is when
an existing setup on a machine has SharePoint front-end, RBS client (v10.5) and
some provider (compiled using RBS client v10.5). Now, upon release of a new RBS
client (v11), SharePoint is developed/compiled on a separate machine and simply
deployed on this one. Thus it only copies the latest RBS client library along
with SharePoint front-end but RBS client is not completely installed on this
machine. So even though SharePoint can find the newer version of RBS client,
this new RBS client will not be able to use the Provider. If
RBS is explicitly installed on the machine where the application (e.g.
SharePoint) is used, then the installer will install appropriate files in .NET’s
Global Assembly Cache (GAC) to
make things work seamlessly.
Why
does it happen?
CLR
uses strong names for libraries and classes (more details
here).
This strong name includes the version of the class/DLL, among other things. All
classes in a specific DLL have the same version number as that of the DLL. Hence
the Abstract Class (BlobStore), which providers need to implement, also has the
version of RBS dll. And this is where the issues are.
For
RBS v10.5, this abstract class is also v10.5 and any existing provider would
have extended this. Now, if the app starts using a newer version of RBS without
installing it on the app machine (or recompiling the provider with newer version
of RBS, thus marking the provider as sub-class of abstract class BlobStore
v11.0), the RBS client will not be able to use the older provider (as CLR is
trying to load provider v10.5 for RS v11) even though nothing has changed except
the version number. This is because the RBS client doesn't identify provider as
a subclass of BlobStore v11.0.
How
to fix it?
There are a couple of ways this issue can be
fixed without installing RBS completely on the application machine. Users can
either compile the provider with new RBS version or install a couple of Policy
files to Global Assembly Cache (GAC) on the
system.
In this post, I’ll only focus on using the
policy files for GAC. Please read this
and this
before
continuing. The link has more details about using policy files.
I'd like
to emphasize here that the most robust way is to install the new version of RBS
on the application client machine. Following fix should only be used if this is
not possible.
Below is the publisher policy file that you need
to use:
<?xml version="1.0"
encoding="UTF-16"?>
<configuration>
<runtime>
<assemblyBinding
xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity publicKeyToken="89845dcd8080cc91"
name="Microsoft.Data.SqlRemoteBlobs"
culture="neutral"></assemblyIdentity>
<bindingRedirect oldVersion="10.5.0.0"
newVersion="11.0.0.0"></bindingRedirect>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
Please save this in an xml file. The file need
to have a specific name Policy.10.5.Microsoft.Data.SqlRemoteBlobs.config
Now,
use Assembly Linker (Al.exe) to create
the publisher policy assembly.
The
Assembly Linker is included with the .NET Framework SDK. To create the publisher
policy assembly that redirects a binding from version 10.0 of
Microsoft.Data.SqlRemoteBlobs.dll to version 11.0 using a publisher policy file
named as above, run the following command:
al.exe
/link:Policy.10.5.Microsoft.Data.SqlRemoteBlobs.config
/out:Policy.10.5.Microsoft.Data.SqlRemoteBlobs.dll
This should create the publisher policy
assembly. Copy this file to C:\Windows\Assembly.
It should install the policy file to GAC. Now, the app should be able to find
and use the appropriate provider.