Assembly policy for non-GAC dlls

  • Thread starter Thread starter Luciano
  • Start date Start date
L

Luciano

Hi,
I'm facing a problem that could be completely resolved using .policy
files, but I could not use GAC in my application.

Basically the app should follow the "Smart Client" guidelines. All the
application plug-ins (implemented as .NET assemblies) should be placed
in a common folder shared among different workstations using remote
folders. So I cannot use the GAC facilities.

Until the plug-ins are implemented as single assembly, all is working
fine. I'm parsing the remote "plugin" folder and load all assemblies
using Assembly.LoadFrom method. I'm using a single AppDomain.

The problem is coming up now that we need to write several multi-
assembly plugins. We basically need to write one or more common core
assemblies (as "infrastructure" for these plugins) that will be
referred by each plugin.
The core assemblies should be versioned and shipped bundled in each
plugin package.

I need to declare backward compatiblity in the core assemblies to:
a) avoid to have multiple version of core assemblies loaded in memory;
b) to efficiently implement an inter-plugin communication layer.

To have this working I need to declare a binding redirect (as in the
app.config file). But I cannot change that .config file because
several application version could be installed on each workstation.
I basically need to use Publisher Configuration File, so each core
assembly could declare redirection from the older compatible versions.

A possible (but unwanted) solution for that is that the applciation
updates its private app.config file once all the plugins are parsed
and all dependencies are collected, and then restart the application
with the correct redirection of the "core" assemblies of the plug-ins
side.

It is possible to avoid that and use .policy files even in a non-GAC
scenario? All the assemblies are strong-named.
Please help!

Thanks in advance,
Luciano
 
Luciano said:
I'm facing a problem that could be completely resolved using .policy
files, but I could not use GAC in my application.
I've had similar problems and policies quite simply don't work for
out-of-GAC assemblies -- I've tried. Though I'm open to some guru proving me
wrong, of course.
Basically the app should follow the "Smart Client" guidelines. All the
application plug-ins (implemented as .NET assemblies) should be placed
in a common folder shared among different workstations using remote
folders. So I cannot use the GAC facilities.

Until the plug-ins are implemented as single assembly, all is working
fine. I'm parsing the remote "plugin" folder and load all assemblies
using Assembly.LoadFrom method. I'm using a single AppDomain.

The problem is coming up now that we need to write several multi-
assembly plugins. We basically need to write one or more common core
assemblies (as "infrastructure" for these plugins) that will be
referred by each plugin.
The core assemblies should be versioned and shipped bundled in each
plugin package.

I need to declare backward compatiblity in the core assemblies to:
a) avoid to have multiple version of core assemblies loaded in memory;
b) to efficiently implement an inter-plugin communication layer.

To have this working I need to declare a binding redirect (as in the
app.config file). But I cannot change that .config file because
several application version could be installed on each workstation.
I basically need to use Publisher Configuration File, so each core
assembly could declare redirection from the older compatible versions.

A possible (but unwanted) solution for that is that the applciation
updates its private app.config file once all the plugins are parsed
and all dependencies are collected, and then restart the application
with the correct redirection of the "core" assemblies of the plug-ins
side.

It is possible to avoid that and use .policy files even in a non-GAC
scenario? All the assemblies are strong-named.

One cheap way to avoid the problem is to remove the strong name. I know this
goes against every guideline Microsoft ever wrote, but let's face it: strong
naming doesn't do you a whole lot of good without the ability to publish
policies. All it buys you is the guarantee that either a some system
administrator has had to have signed off on the redirects, or some
programmer has had to have signed off on rebuilding the application to
ensure it still works with the new versions. These are nice guarantees, but
having a working application at all is nicer still.

With some discipline, the same can be achieved without strong naming. You
can still version assemblies without strong names; the versions are just not
enforced by the runtime. You can manually verify the version numbers for
compatibility if you're so inclined, using the attributes of Assembly.

The other benefit strong naming provides (a guarantee that the assembly was
signed by the right party and not tampered with) is often not important when
you are in full control of the distribution, though it might become a
problem in an ecosystem with third-party publishers.

The distinct *drawback* of strong naming on out-of-GAC assemblies, by the
way, is a startup cost of the runtime having to compute the hash of the
assembly to verify the strong name. It can't cache it like it can with
assemblies in the GAC, because they're not in a trusted location. You'd need
to have a lot of assemblies before this becomes noticeable, but if you're
loading them from remote folders, it might become noticeable sooner.

Finally, it's possible to have your cake and eat it too, but not without
significant cost: if you really, really want to have strong-named, versioned
assemblies without the GAC, you can build your own assembly resolution and
loading logic as part of a custom CLR host. However, hosting the runtime
yourself is not for the faint of heart, and requires a good deal of C++.
 
Jeroen said:
I've had similar problems and policies quite simply don't work for
out-of-GAC assemblies -- I've tried. Though I'm open to some guru proving me
wrong, of course.

Thanks for your confirmation to this problem.
One cheap way to avoid the problem is to remove the strong name. [...]

Thank you for the hint Jeroen.
I'm actually using assembly signature (sn key pair) to recognize if a
plug-in is company-branded or defined by the customer (and in this
case consume a license).
In case of non-strong-named assembly, I should implement a way to
validate a valid signature with a custom cryptographic implementation.
I think this it is the most difficult aspect of this solution.
Finally, it's possible to have your cake and eat it too, but not without
significant cost: if you really, really want to have strong-named, versioned
assemblies without the GAC, you can build your own assembly resolution and
loading logic as part of a custom CLR host. However, hosting the runtime
yourself is not for the faint of heart, and requires a good deal of C++.

This is very very attractive.
We currently are using custom exception handlers (using SEH filters in
an mixed MC++ part of code that host the Application.Run() call).
The valid alternative is to write the main exe application as pure
unmanaged/COM code that host the CLR to manage exceptions and produce
dumps more freely.
In that way we can hook the assembly resolving mechanisms too.

I'll analyze this way when possible, I hope this way is not so hard to
implement.
BTW, at the moment we will implement that brutal quick-and-dirty
solution: update the .config file automatically from the application
itself (restart required).

Many thanks,
Luciano
 
Luciano wrote:
The valid alternative is to write the main exe application as pure
unmanaged/COM code that host the CLR to manage exceptions and produce
dumps more freely.
In that way we can hook the assembly resolving mechanisms too.

I'll analyze this way when possible, I hope this way is not so hard to
implement.

If you decide to go this way (or you're just interested in it in general)
*the* book to read is "Customizing the Microsoft .NET Framework CLR" by
Steven Pratschner (http://www.microsoft.com/MSPress/books/6895.aspx). It's
both necessary and sufficient for this task, and it includes an extensive
example on custom loading assemblies from an aggregate file store (the same
technique used by SQL Server when it's hosting the CLR).
 
Jeroen said:
If you decide to go this way (or you're just interested in it in general)
*the* book to read is "Customizing the Microsoft .NET Framework CLR" by
Steven Pratschner (http://www.microsoft.com/MSPress/books/6895.aspx). It's
both necessary and sufficient for this task, and it includes an extensive
example on custom loading assemblies from an aggregate file store (the same
technique used by SQL Server when it's hosting the CLR).

Thank you very much, just ordered for the company :)
Luciano
 
Back
Top