0

Overview

I have an application running as a Windows service on Windows Server 2019. My application references a number of nuget packages, particularly including:

  • Microsoft.SharePoint.Client
  • Microsoft.SharePoint.Client.Runtime

The nuget versions are both 16.1.23311.12000 (the latest stable as of a couple days ago).

When running the application, I always end up getting this error:

InvalidCastException - Message: [A]Microsoft.SharePoint.Client.FieldUserValue cannot be cast to [B]Microsoft.SharePoint.Client.FieldUserValue. Type A originates from 'Microsoft.SharePoint.Client, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' in the context 'Default' at location 'path\to\my\program\Microsoft.SharePoint.Client.dll'. Type B originates from 'Microsoft.SharePoint.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c' in the context 'Default' at location 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.SharePoint.Client\v4.0_16.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.Client.dll'.

Attempts

1 - Binding Redirect

At first I thought I just needed to do a binding redirect in my app.config, so I have tried this:

App.config

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.SharePoint.Client.Runtime" />
        <bindingRedirect oldVersion="0.0.0.0-16.1.23311.12000" newVersion="16.1.23311.12000"/>
      </dependentAssembly>
    </assemblyBinding>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.SharePoint.Client" />
        <bindingRedirect oldVersion="0.0.0.0-16.1.23311.12000" newVersion="16.1.23311.12000"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    ... stuff in here ...
  </entityFramework>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
  </startup>
  <connectionStrings>
    ... stuff in here ...
  </connectionStrings>
</configuration>

Same error after stopping and restarting the Windows Service that runs this app.

2 - Other attempts from SO question

Other things I've tried from this question (Assembly binding redirect does not work):

  • Moved binding as close to the top as possible, from a comment on this answer. This caused the service to fail to start.
  • Verified the expected assembly version was in my application's root directory.
  • Verified the built MyProgram.exe.config file was in my application's root directory.
  • Tried including culture="neutral" from this answer.

Same error.

3 - Fusion Log Viewer

Then I configured Fusion Log viewer according to this tutorial. After restarting the service again, I noticed two binding attempts for both assemblies (see screenshot):

Assembly Binding Log Viewer Results

Some initial questions:

  1. Why would my application (or any application) try to bind to the same assembly twice?
  2. Why would my application attempt to bind to the assembly late (notice it's 4 seconds after the initial binding)?

And here are the respective logs of each of the four bindings:

Microsoft.SharePoint.Client.Runtime, Version 16.1.0.0...

**GOOD: **Redirect found in application configuration file, exactly as expected.

*** Assembly Binder Log Entry  (2/20/2023 @ 11:11:00 AM) ***

The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  path\to\my\program\MyProgram.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = Microsoft.SharePoint.Client.Runtime, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
 (Fully-specified)
LOG: Appbase = file:///path/to/my/program/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyProgram.exe
Calling assembly : Microsoft.SharePoint.Client, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: path\to\my\program\MyProgram.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Redirect found in application configuration file: 16.1.0.0 redirected to 16.1.0.0.
LOG: Post-policy reference: Microsoft.SharePoint.Client.Runtime, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///path/to/my/program/Microsoft.SharePoint.Client.Runtime.DLL.
LOG: Assembly download was successful. Attempting setup of file: path\to\my\program\Microsoft.SharePoint.Client.Runtime.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: Microsoft.SharePoint.Client.Runtime, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
LOG: Binding succeeds. Returns assembly from path\to\my\program\Microsoft.SharePoint.Client.Runtime.dll.
LOG: Assembly is loaded in default load context.

Microsoft.SharePoint.Client.Runtime, version 16.0.0.0

GOOD: Redirect found in application configuration file, exactly as expected.

*** Assembly Binder Log Entry  (2/20/2023 @ 11:12:01 AM) ***

The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  path\to\my\program\MyProgram.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = Microsoft.SharePoint.Client.Runtime, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
 (Fully-specified)
LOG: Appbase = file:///path/to/my/program/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyProgram.exe
Calling assembly : Microsoft.SharePoint.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: path\to\my\program\MyProgram.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Redirect found in application configuration file: 16.0.0.0 redirected to 16.1.0.0.
LOG: Post-policy reference: Microsoft.SharePoint.Client.Runtime, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
LOG: Binding succeeds. Returns assembly from path\to\my\program\Microsoft.SharePoint.Client.Runtime.dll.
LOG: Assembly is loaded in default load context.

Microsoft.SharePoint.Client, versino 16.1.0.0

GOOD: Uses the local assembly version since it couldn't find another in the GAC **BAD: **Why didn't it use the assembly binding redirect from the application configuration file?

*** Assembly Binder Log Entry  (2/20/2023 @ 11:11:00 AM) ***

The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  path\to\my\program\MyProgram.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = Microsoft.SharePoint.Client, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
 (Fully-specified)
LOG: Appbase = file:///path/to/my/program/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyProgram.exe
Calling assembly : CRS.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: path\to\my\program\MyProgram.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: Microsoft.SharePoint.Client, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
LOG: GAC Lookup was unsuccessful.
LOG: Attempting download of new URL file:///path/to/my/program/Microsoft.SharePoint.Client.DLL.
LOG: Assembly download was successful. Attempting setup of file: path\to\my\program\Microsoft.SharePoint.Client.dll
LOG: Entering run-from-source setup phase.
LOG: Assembly Name is: Microsoft.SharePoint.Client, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
LOG: Binding succeeds. Returns assembly from path\to\my\program\Microsoft.SharePoint.Client.dll.
LOG: Assembly is loaded in default load context.

Microsoft.SharePoint.Client, version 16.0.0.0

**BAD: **Doesn't use the redirect defined in the application configuration file **BAD: **Loads the wrong version from the GAC

*** Assembly Binder Log Entry  (2/20/2023 @ 11:12:01 AM) ***

The operation was successful.
Bind result: hr = 0x0. The operation completed successfully.

Assembly manager loaded from:  C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
Running under executable  path\to\my\program\MyProgram.exe
--- A detailed error log follows. 

=== Pre-bind state information ===
LOG: DisplayName = Microsoft.SharePoint.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
 (Fully-specified)
LOG: Appbase = file:///path/to/my/program/
LOG: Initial PrivatePath = NULL
LOG: Dynamic Base = NULL
LOG: Cache Base = NULL
LOG: AppName = MyProgram.exe
Calling assembly : Microsoft.SharePoint.Client.Runtime, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: path\to\my\program\MyProgram.exe.Config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: Microsoft.SharePoint.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
LOG: Found assembly by looking in the GAC.
LOG: Binding succeeds. Returns assembly from C:\Windows\Microsoft.Net\assembly\GAC_MSIL\Microsoft.SharePoint.Client\v4.0_16.0.0.0__71e9bce111e9429c\Microsoft.SharePoint.Client.dll.
LOG: Assembly is loaded in default load context.
WRN: Multiple versions of the same assembly were loaded into one context of an application domain:
WRN: Context: Default | Domain ID: 1 | Assembly Name: Microsoft.SharePoint.Client, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
WRN: Context: Default | Domain ID: 1 | Assembly Name: Microsoft.SharePoint.Client, Version=16.1.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c
WRN: This might lead to runtime failures.
WRN: It is recommended that you remove the dependency on multiple versions, and change the app.config file to point to the required version of the assembly only.
WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information.

Summary

  • Any thoughts?
  • Where else can I check for things that could be causing this?
  • Why doesn't the redirect work for Microsoft.SharePoint.Client but it does for Microsoft.SharePoint.Client.Runtime v16.1.0.0?
  • Why doesn't the redirect work for Microsoft.SharePoint.Client.Runtime v16.0.0.0?
Michael Harris
  • 189
  • 1
  • 10

1 Answers1

0

I can't answer all 4 of the summary questions in my post above, but I can say what ultimately worked.

Three things:

  1. Put both dependentAssembly nodes inside a singular assemblyBinding
  2. Include culture and publicKeyToken for both assemblyIdentity elements
  3. Remove the patch and build from the versions, keeping only the major and minor.

Old app.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.SharePoint.Client.Runtime" />
        <bindingRedirect oldVersion="0.0.0.0-16.1.23311.12000" newVersion="16.1.23311.12000"/>
      </dependentAssembly>
    </assemblyBinding>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.SharePoint.Client" />
        <bindingRedirect oldVersion="0.0.0.0-16.1.23311.12000" newVersion="16.1.23311.12000"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    ... stuff in here ...
  </entityFramework>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
  </startup>
  <connectionStrings>
    ... stuff in here ...
  </connectionStrings>
</configuration>

New app.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.SharePoint.Client.Runtime" culture="neutral" publicKeyToken="71e9bce111e9429c" />
        <bindingRedirect oldVersion="0.0.0.0-16.1.0.0" newVersion="16.1.0.0"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.SharePoint.Client" culture="neutral" publicKeyToken="71e9bce111e9429c" />
        <bindingRedirect oldVersion="0.0.0.0-16.1.0.0" newVersion="16.1.0.0"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <entityFramework>
    .. stuff in here ...
  </entityFramework>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
  </startup>
  <connectionStrings>
    .. stuff in here ...
  </connectionStrings>
</configuration>
Michael Harris
  • 189
  • 1
  • 10