Buildstarted
Buildstarted

Reputation: 26689

AppDomain.CurrentDomain.AssemblyResolve possible issues with trust or other gotcha's I should be aware of

I'm currently using the following code:

AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
    var name = args.Name + ".dll";
    using (var input = Assembly.GetExecutingAssembly()
                               .GetManifestResourceStream(name)) {
        Assembly dll = input != null
            ? Assembly.Load(input.ToArray())
            : null;

        return dll;
    }
};

In all instances locally it seems to work just fine, however one client is having trouble loading the included dlls (they do not have source code access).

Are there any trust issues or gotchas that I should be aware of when using this type of dynamic dll loading?

Medium Trust issues don't seem to be an issue, however our resulting dll requires Full Trust anyway. I guess it might come down to Security Permissions or something.

Update

After going through the docs, again, I noticed a single line that I skipped over before and I think it's related to my problem.

"Beginning with the .NET Framework 4, the ResolveEventHandler event is raised for all assemblies, including resource assemblies. In earlier versions, the event was not raised for resource assemblies. If the operating system is localized, the handler might be called multiple times: once for each culture in the fallback chain."

Whereas in 3.5 it wasn't. I'll post an updated when I confirm.

Upvotes: 2

Views: 3276

Answers (1)

csharptest.net
csharptest.net

Reputation: 64218

Well, not having any details it's hard to diagnose; however, I would suggest a few changes to the code above:

  1. args.Name is actually a full assembly name, not just a simple name, but can contain versions etc. Passing this value to the constructor of AssemblyName parses just the simple name. I doubt this is the issue your experiencing.

  2. You should propagate the current domains evidence when loading the assembly bits. This may be the issue your seeing in the field, but then again maybe not.

  3. Don't use executing assembly, access the correct assembly containing the resource via an explicit reference to a type contained in that assembly. Just replace 'THIS_CLASS' in the example below. This is my best guess as to the root cause of the issue your having.

  4. You should go ahead and cache the results of this method into a global dictionary. Why? You can be called to load the same assembly multiple times and for each time you are called you must return the same instance of the assembly. Your example loads the assembly again and again.

  5. Add detailed logging, log what assembly your looking for, the resource name your trying to load, the assembly your loading it from, if the stream is null, the result of the Load() method, etc.

    static Dictionary<String, Assembly> _assemblies = new Dictionary<String, Assembly>(StringComparer.OrdinalIgnoreCase);
        AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
        {
            Assembly dll;
            var name = new AssemblyName(args.Name).Name + ".dll";
            if(!_assemblies.TryGetValue(name, out dll))
            {
                Assembly res = typeof(THIS_CLASS).Assembly;
                using (var input = res.GetManifestResourceStream(name))
                {
                    if (input == null)
                    {
                        LogWrite("Assembly {0} does not contain {1}", res, name);
                        return null;
                    }
                    if (null == (dll = Assembly.Load(input.ToArray(), AppDomain.CurrentDomain.Evidence)))
                    {
                        LogWrite("Assembly {0} failed to load.", name);
                        return null;
                    }
                    LogWrite("Loaded assembly {0}.", name);
                    _assemblies[name] = dll;
                    return dll;
                }
            }
            return dll;
        };
    

Upvotes: 8

Related Questions