Opened 12 years ago

Closed 10 years ago

Last modified 10 years ago

#12 closed Bug (fixed)

Loading third-party plugin assemblies is impossible

Reported by: Thomas Schmid Owned by: coredevs
Priority: Must have Milestone:
Component: General Keywords:
Cc:

Description (last modified by Matthäus Wander)

It is not possible to distribute and load a plugin assembly into a nightly or stable build.

Every plugin references CrypPluginBase. CrypPluginBase is rebuilt with each plugin build and the version increases. A new plugin therefore references a new CrypPluginBase version (though nothing has changed) and won't be loaded in any nightly build, because the nightly build has a different CrypPluginBase version. Without the exact version of CrypPluginBase the plugin does not load.

Example error log message: CRC, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Could not load file or assembly 'CrypPluginBase, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

Change History (16)

comment:1 Changed 12 years ago by Arno Wacker

Priority: Should be doneImportant

comment:2 Changed 11 years ago by Matthäus Wander

Publisher Configuration Files (http://msdn.microsoft.com/en-us/library/aa375682(VS.85).aspx), or more specifically the bindingRedirect property, do not seem to solve the problem.

With bindingRedirect a new assembly version may replace an old assembly in order to ensure downward compatibility. However the new plugin is not bound to an older CrypPluginBase, but to a newer one. Thus, the nightly builds require upward compatibility. Except from being a poor solution (looking in the future is error-prone), it is not possible because we cannot name future version numbers.

Last edited 11 years ago by Matthäus Wander (previous) (diff)

comment:3 Changed 11 years ago by Matthäus Wander

Description: modified (diff)
Priority: ImportantMust have
Summary: Publisher Configuration FilesLoading third-party plugin assemblies is impossible
Type: Open taskBug

comment:4 Changed 11 years ago by Matthäus Wander

Description: modified (diff)

comment:5 Changed 11 years ago by Matthäus Wander

Other solution proposals:

  • We manually increase the version of CrypPluginBase only if something has been changed. Error-prone, as developer may forget to increase version number. Will still break compatibility if there actually is a change in CrypPluginBase, thus requiring the use of Publisher Configuration Files. Hard to maintain.
  • We remove the CrypPluginBase project from the solution and reference a CrypPluginBase assembly. If there are changes in the CrypPluginBase, the developer commits the new assembly. Automatic versioning can be used, so the developer will not forget to update the version number. Will still break with every new CrypPluginBase version, even with minor bug fixing versions.
  • Is it possible to embed the CrypPluginBase content into the plugin assembly? No.
  • We could disable strong names again. Though this looks like a step back, we actually do not need strong naming as we do not use the Global Assembly Cache. For security purposes we have the Software Publisher Certificate enabled.
Last edited 11 years ago by Matthäus Wander (previous) (diff)

comment:6 Changed 11 years ago by Matthäus Wander

Tested the following approach successfully:

  • Add strong name key (SNK) from build process to CrypPluginBase in trunk
  • Add the following information to the CrypStartup.exe.config in nightly build installation:
 <dependentAssembly>
   <assemblyIdentity name="CrypPluginBase" publicKeyToken="95429f90c3a66dd4" culture="neutral" />
   <bindingRedirect oldVersion="2.0.0.0-3.0.0.0" newVersion="2.0.2058.1" />
 </dependentAssembly>

While some plugin built from trunk binds against any version of CrypPluginBase, the runtime engine will instead load version 2.0.2058.1 which is deployed in the nightly build. This way trunk developers can distribute their plugin assemblies in binary. Others can load these plugins in their nightly build installation.

This approach has the following disadvantages:

  • Trunk developers need access to strong name key, therefore the key is public (does this hurt?)
  • Still no mechanism considered to force version incompatibility when functional updates occur (but can be implemented by manually using fixed version numbers instead of range and automatic versioning)
  • Need to set newVersion attribute programmatically in build process (no biggy, though)

comment:7 Changed 10 years ago by Matthäus Wander

(In [2337]) * added strong name signing to CrypCore and CrypPluginBase (refs #12)

  • this is not a security feature, it is a compatibility feature
  • copied SNK key from Build directory

comment:8 Changed 10 years ago by Matthäus Wander

(In [2338]) prepared update of App.config in build process (refs #12)

comment:9 Changed 10 years ago by Matthäus Wander

(In [2339]) prepared update of App.config in build process (refs #12)

comment:10 Changed 10 years ago by Matthäus Wander

(In [2340]) prepared update of App.config in build process (refs #12)

comment:11 Changed 10 years ago by Matthäus Wander

(In [2341]) added binding redirect placeholder to CrypWin app.config, see #12

comment:12 Changed 10 years ago by Matthäus Wander

Chosen solution: activated Strong Name signing in trunk on CrypPluginBase and CrypCore. It is not required to turn on signing on each plugin as these are loaded dynamically and the dynamic loader seems not to care about whether the plugin assembly has a strong name or not. The SNK which is currently in use is a copy of Build/Build/CT2_Key.snk and is already public anyway. We may want to replace it in future (there's no point in doing it now because plugins apparently don't need to have a strong name). The build sets newVersion attribute automatically when building a new setup.

Again, please keep in mind: the strong name signing key (SNK) is currently public.

comment:13 Changed 10 years ago by Matthäus Wander

Resolution: fixed
Status: newclosed

(In [2342]) Modified setup to set bindingRedirect attribute. This closes #12.

comment:14 Changed 10 years ago by Matthäus Wander

The current solution to this ticket is rather a hacky workaround. Here are some thoughts about a better solution attempt:

Nach Lesen von 1 und 2 denke ich, wir benutzen das Attribut AssemblyVersion falsch (was als Konsequenz zu #12 geführt hat -- mittlerweile durch nen Hack behoben). Hier mein Vorschlag:

  • AssemblyVersion: Fix eingestellte Versionsnummer, z.B. 2.0 oder

2.0.0.0. Das Ändern dieser Versionsnummer bricht alte Referenzen auf die Assembly -> Neukompilieren erforderlich. Wird manuell durch den Entwickler angepasst, wenn es größere Änderungen gibt, die das externe Interface stark betreffen (alternativ: wird gar nicht angepasst solang wir bei Version 2.0 sind). Die gewöhnlichen Plugins brauchen das gar nicht anpassen.

  • AssemblyFileVersion: Automatisch generierte Versionsnummer, wo die

SvnRevision drin steht, also unser zur Zeit gängiges 2.0.2490.1 (major.minor.svnrevision.dayrevision). Diese Versionsnummer ist rein informativ für die Entwickler und Benutzer, muss aber das Format "a.b.c.d" einhalten. Kein direkter Bezug zur AssemblyVersion.

  • AssemblyInformationalVersion: informativer und beliebiger String, z.B.

unser Name "CrypTool 2.0 (Beta 3 - Build 2490.1)".

Die .NET 4 Runtime macht es so ähnlich (AssemblyVersion steht fix auf 4.0.0.0, auch bei Hotfixes).

comment:15 Changed 10 years ago by Matthäus Wander

Switched to new solution attempt in r2664 and r2667.

  • AssemblyVersion 2.0.0.0
  • AssemblyFileVersion 2.0.xxxx.y (xxxx = svn revision, y = build revision)

If you're using the CT2 Plugin Template, please update it.

comment:16 Changed 10 years ago by Matthäus Wander

Milestone: CrypTool 2.0 RELEASE
Note: See TracTickets for help on using tickets.