【问题标题】:FileNotFoundException when trying to load Autofac as an embedded assembly尝试将 Autofac 作为嵌入式程序集加载时出现 FileNotFoundException
【发布时间】:2013-09-18 14:13:19
【问题描述】:

以前版本的 Autofac 可以工作,但由于他们切换到使其成为可移植类库,因此无法加载。

我尝试应用列出的修复程序 here (KB2468871),但它告诉我不需要它。

当我将 Autofac.dll 文件移动到与可执行文件相同的位置时,错误消失了。当它从外部 DLL 加载它时,它加载正常。

为什么它不能作为嵌入式 DLL 工作?

这是一个例外:

        System.IO.FileNotFoundException: Could not load file or assembly 'System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e, Retargetable=Yes' or one of its dependencies. The system cannot find the file specified.

        Stack trace: 
           at Autofac.Core.Registration.ComponentRegistration..ctor(Guid id, IInstanceActivator activator, IComponentLifetime lifetime, InstanceSharing sharing, InstanceOwnership ownership, IEnumerable`1 services, IDictionary`2 metadata)
           at Autofac.Core.Container..ctor()
           at Autofac.ContainerBuilder.Build(ContainerBuildOptions options)
           at MyApp.Configuration.Bootstrapper.Run(String[] args) in c:\Dev\MyApp\App\Configuration\Bootstrapper.cs:line 25
           at MyApp.Configuration.EntryPoint.Main(String[] args) in c:\Dev\MyApp\App\Configuration\EntryPoint.cs:line 22

如果有帮助,下面是 .csproj 文件中将 DLL 嵌入可执行文件的部分:

  <Target Name="AfterResolveReferences">
<ItemGroup>
  <EmbeddedResource Include="@(ReferenceCopyLocalPaths)" Condition="'%(ReferenceCopyLocalPaths.Extension)' == '.dll'">
    <LogicalName>%(ReferenceCopyLocalPaths.DestinationSubDirectory)%(ReferenceCopyLocalPaths.Filename)%(ReferenceCopyLocalPaths.Extension)</LogicalName>
  </EmbeddedResource>
</ItemGroup>

...这里是 EntryPoint 类:

internal static class EntryPoint
{
    [STAThread]
    private static void Main(params string[] args)
    {
        AppDomain.CurrentDomain.AssemblyResolve += (sender, e) => loadEmbeddedAssembly(e.Name);
        Bootstrapper.Run(args); // must call separate class when using embedded assemblies
    }

    private static Assembly loadEmbeddedAssembly(string name)
    {
        var container = Assembly.GetExecutingAssembly();
        var path = new AssemblyName(name).Name + ".dll";

        using (var stream = container.GetManifestResourceStream(path))
        {
            if (stream == null)
            {
                return null;
            }

            var bytes = new byte[stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            return Assembly.Load(bytes);
        }
    }
}

【问题讨论】:

  • 看起来您的程序集解析处理程序没有运行。你能证实这一点吗?此外,仅使用设计器将文件添加为资源要容易得多。您可以通过 byte[] 属性 [root namespace].Properties.Resources.SomeEmbeddedFile 访问它。在 MemoryStream 中猛击它并完成它。 GMRS 是老派。
  • @Will 如果程序集解析处理程序没有运行,它将根本无法加载 Autofac。 Autofac 正在加载,它只是试图加载旧版本的 System.Core。当它作为嵌入式资源加载时,似乎程序集的 Retargetable 属性不起作用。当我将 Autofac dll 复制到与 exe 相同的文件夹中时,它确实有效。
  • 哦,明白了。可能与加载上下文有关。它们很难理解,而且根本没有很好的记录。试过自己加载吗?
  • 看起来类似于this question。在 cmets 中,leppie 建议使用 LoadFrom,这似乎对提问者有用。

标签: c# dll embedded-resource


【解决方案1】:

也许问题在于您尝试加载 EmbeddedAssembly 的方式。

我对如何做到这一点知之甚少
但我知道代码项目中的以下示例对我来说很好,所以也许它会对你有所帮助:-)

Load DLL From Embedded Resource

(如果我误解了你的问题,请告诉我,我会删除我的答案)

【讨论】:

    【解决方案2】:

    我可以通过在针对 Silverlight 并使用 System.Core 类型的 PCL 库上使用 Assembly.Load(byte[]) 轻松重现您的问题,这个问题不是 Autofac 特有的。这是加载程序集的一种相当邪恶的方式,与 Assembly.LoadFile() 一样糟糕。没有加载上下文是 DLL Hell 的秘诀。

    CLR 对这些 PCL 库引用的工作并不令人羡慕,它需要神奇地将可重定向的程序集引用映射到真实的引用。换句话说,需要将 2.0.5.0 引用映射到运行时版本的正确引用,在您的情况下为 4.0.0.0。它只有在知道实际运行时版本是什么的情况下才能做到这一点,没有加载上下文会很困难。显然它不会尝试这样做,它会再次为 2.0.5.0 引用触发 AssemblyResolve 事件。

    这是解决方案,事后看来非常简单。只需拦截可重定向程序集引用的解析请求并使用 Assembly.Load() 让 CLR 从 AppDomain 的加载上下文中对其进行排序。像这样更改您的 AssemblyResolve 事件处理程序:

    private static Assembly loadEmbeddedAssembly(string name)
    {
        if (name.EndsWith("Retargetable=Yes")) {
            return Assembly.Load(new AssemblyName(name));
        }
        // Rest of your code
        //...
    }
    

    这在我的测试应用中运行良好,我相信它也可以解决您使用 Autofac 的问题。

    【讨论】:

    猜你喜欢
    • 2012-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多