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.