Assemblies.config files: Difference between revisions

From OPC Labs Knowledge Base
 
 
(8 intermediate revisions by the same user not shown)
Line 1: Line 1:
This article describes the role of the '''assemblies.config''' file in QuickOPC.


<small>Note: The mechanism described here applies to QuickOPC 2022.2 or later.</small>
= Background =
When NuGet packages are referenced in .NET Framework, and their dependency packages are pulled in (recursively), it is often the case that different packages end up referencing different versions of the same assembly. Since only a single version of an assembly can be loaded, assembly version redirection (binding redirection) is used to redirect references to different versions of an assembly to a single compatible version. Assembly binding redirections can be specified in .NET Framework configuration files, per-application or machine-wide. In order for this mechanism to function properly, a full set of NuGet packages used by the application must be known. When building an application, common build tools (such as Visual Studio) provide a way to automatically determine the "transitive closure" of the assembly binding redirections needed for the application, and are capable of generating the application configuration file with all necessary assembly binding redirections for you.
= The problem =
In some cases, the full transitive closure of assembly binding redirections cannot be determined by the mechanism described above. There are various scenarios in which this can happen, but they generally fall into two categories:
* You are using a development tool that does not support generating the assembly binding redirections.
* Situations in which the full set of referenced NuGet packages/assemblies is not known upfront (such as dynamic loading).
Consider, for example, a set of COM components (which can be QuickOPC) developed in .NET Framework and dependent on various NuGet packages. These components reside in .NET assemblies which are registered for COM interop. When a COM application creates and uses a COM object from one of these assemblies, the code in the COM component needs to load the dependent assemblies, and at that moment the assembly binding redirections must be correctly in place. But, because the top-level application (executable) is not something that was actually built with the NuGet packages (it only references the COM components), the top-level application will not have the proper binding redirections in its configuration file, and there will eventually be an assembly loading failure.
In order to make the application work, it would normally be necessary to place the assembly binding redirections to the application configuration file, or to the machine-wide configuration file. This can be done, but has various issues:
* The developer of the assemblies must actually somehow provide the information about the necessary assembly binding redirects.
* Because it is not made automatically, there is a chance that the application won't work by itself. Manual, error-prone step is needed.
* Access to the application configuration file might be impractical or restricted. For example, the top-level application might simply be a language interpreter (such as for VBScript), which is part of the operating system.
* Similarly, modifying the machine-wide configuration file, while possible in principle, might have unwanted consequences on other applications, and can be impossible due to security policy reasons.
= The solution =
A partial solution to the above problem is provided using the '''assemblies.config''' file. The file is in format of .NET Framework configuration files, and contains the assembly binding redirections for a particular set if assemblies. The '''assemblies.config''' file is placed alongside the assemblies (i.e. in the same directory). Our assemblies are coded in special way which makes sure that before any assemblies that may need version redirection are loaded, the '''assemblies.config''' file is read, and the binding redirections from this file are made effective for any subsequent assembly loading. Note: Binding redirections specified by the standard assembly and machine-wide configuration files are resolved (applied) first and (if they succeed) have thus precedence.
We generate the '''assemblies.config''' file for QuickOPC components and provide it alongside the assemblies, making it possible for COM applications (and some other usages such as from PowerShell) to use the components seamlessly, without a need to explicitly configure the assembly binding redirections. The current implementation does not yet make a proper transitive closure of redirections for multiple assembly sets, as there is no need for it.
= More =
Related reading:
* [https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/ Configure apps by using configuration files]
* [https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/ Configuration file schema for .NET Framework]
* [https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/assemblybinding-element-for-runtime <assemblyBinding> Element for <runtime>]
* [https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/runtime/bindingredirect-element <bindingRedirect> Element]
* [https://docs.microsoft.com/en-us/dotnet/framework/configure-apps/redirect-assembly-versions Redirecting assembly versions]


TBD
[[Category:Configuration]] [[Category:Low-Level Configuration]]
[[Category:Configuration]] [[Category:Low-Level Configuration]]

Latest revision as of 12:42, 17 October 2023

This article describes the role of the assemblies.config file in QuickOPC.

Note: The mechanism described here applies to QuickOPC 2022.2 or later.

Background

When NuGet packages are referenced in .NET Framework, and their dependency packages are pulled in (recursively), it is often the case that different packages end up referencing different versions of the same assembly. Since only a single version of an assembly can be loaded, assembly version redirection (binding redirection) is used to redirect references to different versions of an assembly to a single compatible version. Assembly binding redirections can be specified in .NET Framework configuration files, per-application or machine-wide. In order for this mechanism to function properly, a full set of NuGet packages used by the application must be known. When building an application, common build tools (such as Visual Studio) provide a way to automatically determine the "transitive closure" of the assembly binding redirections needed for the application, and are capable of generating the application configuration file with all necessary assembly binding redirections for you.

The problem

In some cases, the full transitive closure of assembly binding redirections cannot be determined by the mechanism described above. There are various scenarios in which this can happen, but they generally fall into two categories:

  • You are using a development tool that does not support generating the assembly binding redirections.
  • Situations in which the full set of referenced NuGet packages/assemblies is not known upfront (such as dynamic loading).

Consider, for example, a set of COM components (which can be QuickOPC) developed in .NET Framework and dependent on various NuGet packages. These components reside in .NET assemblies which are registered for COM interop. When a COM application creates and uses a COM object from one of these assemblies, the code in the COM component needs to load the dependent assemblies, and at that moment the assembly binding redirections must be correctly in place. But, because the top-level application (executable) is not something that was actually built with the NuGet packages (it only references the COM components), the top-level application will not have the proper binding redirections in its configuration file, and there will eventually be an assembly loading failure.

In order to make the application work, it would normally be necessary to place the assembly binding redirections to the application configuration file, or to the machine-wide configuration file. This can be done, but has various issues:

  • The developer of the assemblies must actually somehow provide the information about the necessary assembly binding redirects.
  • Because it is not made automatically, there is a chance that the application won't work by itself. Manual, error-prone step is needed.
  • Access to the application configuration file might be impractical or restricted. For example, the top-level application might simply be a language interpreter (such as for VBScript), which is part of the operating system.
  • Similarly, modifying the machine-wide configuration file, while possible in principle, might have unwanted consequences on other applications, and can be impossible due to security policy reasons.

The solution

A partial solution to the above problem is provided using the assemblies.config file. The file is in format of .NET Framework configuration files, and contains the assembly binding redirections for a particular set if assemblies. The assemblies.config file is placed alongside the assemblies (i.e. in the same directory). Our assemblies are coded in special way which makes sure that before any assemblies that may need version redirection are loaded, the assemblies.config file is read, and the binding redirections from this file are made effective for any subsequent assembly loading. Note: Binding redirections specified by the standard assembly and machine-wide configuration files are resolved (applied) first and (if they succeed) have thus precedence.

We generate the assemblies.config file for QuickOPC components and provide it alongside the assemblies, making it possible for COM applications (and some other usages such as from PowerShell) to use the components seamlessly, without a need to explicitly configure the assembly binding redirections. The current implementation does not yet make a proper transitive closure of redirections for multiple assembly sets, as there is no need for it.

More

Related reading: