AssemblyResolve事件触发致电时的Assembly.Load(字节()) [英] AssemblyResolve event fires when calling Assembly.Load(byte())

查看:939
本文介绍了AssemblyResolve事件触发致电时的Assembly.Load(字节())的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以,我有一个WPF项目是拉动是由另一个项目中使用,在这里我的工作的DLL。这是依赖乱七八糟的,我一直在使用这项技术在这里:<一href="http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application" rel="nofollow">http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application嵌入的依赖关系到一个单一的可执行文件。

So I have a WPF project that is pulling in dlls that are used by another project here at my job. It's a mess of dependencies, I've been using the technique here: http://www.digitallycreated.net/Blog/61/combining-multiple-assemblies-into-a-single-exe-for-a-wpf-application to embed the dependencies into a single executable.

现在,当我打电话里面的依赖关系的一个具体方法,我打的AssemblyResolve事件。我OnResolveAssembly事件运行时,它找到的组件作为嵌入资源(酷!),并没有返回的Assembly.Load(assembyRawBytes)。如果我(在OnResolveAssembly年初与断点)打F11在这一点上,我得到的另一个的调用到相同的事件。这对同一个程序集太(args.Name是一样的)。

Now, when I'm calling a specific method inside one of the dependencies, I hit the AssemblyResolve event. My OnResolveAssembly event runs, it finds the assembly as an embedded resource (cool!), and does "return Assembly.Load(assembyRawBytes)". If I hit F11 at this point (with a breakpoint at the beginning of OnResolveAssembly), I get another call into the same event. It's for the same assembly too (args.Name is the same).

如果我让这个来看,我打了一个堆栈溢出,因为我似乎从来没有逃脱这个递归调用的事件。

If I let this run I hit a stack overflow, since I can never seem to escape this recursive event calling.

MSDN文档真的不说什么时候能的Assembly.Load除非出现FileNotFoundException或BadImageFormatException失败。

The MSDN docs don't really say when Assembly.Load can fail, except with a FileNotFoundException or BadImageFormatException.

我已经试过脱钩的OnResolveAssembly在之前,我打电话的Assembly.Load的时刻,但我的应用程序死了一个神秘的死亡,甚至在VS它只是的。

I've tried unhooking the OnResolveAssembly at the moment before I call Assembly.Load, but then my application dies a mysterious death, even under VS it just goes poof.

我可能打破一些规则在这里,但是从哪里开始寻找问题的一些想法将受到欢迎。

I'm probably breaking several rules here, but some ideas of where to start looking for problems would be welcome.

我要开始闲逛,在有问题的DLL,看看是否有什么不对的地方(也许这是一个混合装配?)。

I'm going to start poking around in the problematic DLL to see if there are hints about what is wrong with it (maybe it's a mixed assembly?).

下面是我的OnResolveAssembly处理程序:

Here's my OnResolveAssembly handler:

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    AssemblyName assemblyName = new AssemblyName(args.Name);

    string path = assemblyName.Name + ".dll";

    if (assemblyName.CultureInfo.Equals(System.Globalization.CultureInfo.InvariantCulture) == false)
    {
        path = String.Format(@"{0}\{1}", assemblyName.CultureInfo, path);
    }
    using (Stream stream = executingAssembly.GetManifestResourceStream(path))
    {
        if (stream == null)
            return null;

        byte[] assemblyRawBytes = new byte[stream.Length];
        stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
        assemblyDictionary.Add(assemblyName.Name, Assembly.Load(assemblyRawBytes));
        return assemblyDictionary[assemblyName.Name];
    }
}

有关目前,我已经通过我的所有资源进行迭代,并试图对他们的Assembly.Load,并将它们存储在一个字典检索(在OnResolveAssembly活动期间)解决它:

For the time being, I've resolved it by iterating through all of my resources and attempting Assembly.Load on them, and storing them in a dictionary for retrieval (during the OnResolveAssembly event):

[STAThread]
public static void Main()
{
    AppDomain.CurrentDomain.AssemblyResolve += OnResolveAssembly;
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    string[] resources = executingAssembly.GetManifestResourceNames();
    foreach (string resource in resources)
    {
        if (resource.EndsWith(".dll"))
        {
            using (Stream stream = executingAssembly.GetManifestResourceStream(resource))
            {
                if (stream == null)
                    continue;

                byte[] assemblyRawBytes = new byte[stream.Length];
                stream.Read(assemblyRawBytes, 0, assemblyRawBytes.Length);
                try
                {
                    assemblyDictionary.Add(resource, Assembly.Load(assemblyRawBytes));
                }
                catch (Exception ex)
                {
                    System.Diagnostics.Debug.Print("Failed to load: " + resource + " Exception: " + ex.Message);
                }
            }
        }
    }
    App.Main();
}

private static Assembly OnResolveAssembly(object sender, ResolveEventArgs args)
{
    Assembly executingAssembly = Assembly.GetExecutingAssembly();
    AssemblyName assemblyName = new AssemblyName(args.Name);

    string path = assemblyName.Name + ".dll";

    if (assemblyDictionary.ContainsKey(path))
    {
        return assemblyDictionary[path];
    }
    return null;
}

这似乎被现在工作的罚款(以下简称失败的集结号将装载罚款,我的第二个片段),但我很想了解为什么它不能在第一个工作。

It seems be working fine now (the "failing" assembly will load fine in my second snippet), but I'd be interested to learn why it doesn't work in the first.

推荐答案

从byte []加载程序集是结束在.DLL地狱(你走太多的/复杂的依赖关系的地方)的好方法。这里的问题是,虽然您加载的DLL来一个AppDomain它不会自动解决,当你需要它的再次作为依赖类型。 我谈到这个问题就在这里:<一href="http://stackoverflow.com/questions/5548691/assemblyresolve-does-not-fire/5550892#comment32065824_5550892">AssemblyResolve不火

Loading an assembly from byte[] is a good way to end up in .dll hell (the place you go for too many/complex dependencies). Problem here is that although you loaded the dll to an AppDomain it is not automatically resolved, when you need it again for dependent types. I commented on this problem here: AssemblyResolve Does not fire

长话短说,组件加载到不同的上下文的AppDomain内。使用负载的情况下(字节[])不能自动解决组件。

Long story short, Assemblies are loaded into different "contexts" inside of AppDomains. The context used by Load(byte[]) does not resolve Assemblies automatically.

该解决方案跟踪的加载组件并返回加载第二次的已加载的程序集代替。有一个起点,在我回答这个方法: <一href="http://stackoverflow.com/questions/11122052/need-to-hookup-assemblyresolve-event-when-disallowapplicationbaseprobing-true/19702548#19702548">Need DisallowApplicationBaseProbing时联播AssemblyResolve事件=真

The solution is keeping track of the loaded assemblies and returning the already loaded assembly instead of loading it a second time. There is a starting point to this approach in my answer to: Need to hookup AssemblyResolve event when DisallowApplicationBaseProbing = true

但我认为你这样做是正确你的解决方法。

But I think you got it right with your workaround.

BTW。加载程序集两次是一种方式来获得相同的,但不兼容的类型。曾经投的MyType的对象从MyAssembly程序到MyType的距离非常相同的组件,并得到空?

BTW. Loading an assembly twice is a way to get identical but incompatible types. Ever cast an object of MyType from MyAssembly into MyType from the very same assembly and got null?

这是一个温暖的欢迎来到地狱为.dll。

That's a warm "Welcome to .dll hell".

这篇关于AssemblyResolve事件触发致电时的Assembly.Load(字节())的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆