尝试将Autofac加载为嵌入式程序集时FileNotFoundException [英] FileNotFoundException when trying to load Autofac as an embedded assembly

查看:219
本文介绍了尝试将Autofac加载为嵌入式程序集时FileNotFoundException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我尝试使用列出的修补程序这里(KB2468871),但它告诉我不需要。



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



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



这是例外:

  System.IO.FileNotFoundException:无法加载文件或程序集System.Core,Version = 2.0.5.0,Culture = neutral,PublicKeyToken = 7cec85d7bea7798e,Retargetable = Yes或其依赖关系之一。该系统找不到指定的文件。 

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

如果有帮助,这里是部分将.csproj文件嵌入到可执行文件中。

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



...这里是EntryPoint类:

 内部静态类EntryPoint 
{
[STAThread]
private static void Main(params string [] args)
{
AppDomain.CurrentDomain.AssemblyResolve + =(sender,e)=> loadEmbeddedAssembly(e.Name);
Bootstrapper.Run(args); //必须在使用嵌入式程序集时调用单独的类
}

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

使用(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);
}
}
}


解决方案

我可以通过在目标为Silverlight的PCL库上使用Assembly.Load(byte [])轻松地重新解决问题,并使用System.Core类型,但这个问题不是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));
}
//其余代码
// ...
}

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


Previous versions of Autofac worked, but since they switched to making it a Portable Class Library it won't load.

I tried applying the fix listed here (KB2468871) but it told me that it was not needed.

The error goes away when I move the Autofac.dll file into the same location as the executable. When it loads it from the external DLL it loads fine.

Why won't it work as an embedded DLL?

Here is the exception:

        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

If it helps, here is the part of the .csproj file that embeds the DLLs into the executable:

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

... and here is the EntryPoint class:

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);
        }
    }
}

解决方案

I could easily repro your problem by using Assembly.Load(byte[]) on a PCL library that targeted Silverlight and used a System.Core type, this problem isn't specific to Autofac. It is a rather evil way to load an assembly, about as bad as Assembly.LoadFile(). Not having a loading context is a recipe for DLL Hell.

The CLR has an unenviable job to do with these PCL library references, it needs to magically map the retargetable assembly references to a real one. In other words, the 2.0.5.0 reference needs to be mapped to the correct one for the runtime version, 4.0.0.0 in your case. It can only do this if it has a good idea what the actual runtime version is, not having a loading context makes that difficult. Clearly it doesn't attempt to do so, it fires the AssemblyResolve event again for the 2.0.5.0 reference.

Which is the solution, remarkable simple in hind-sight. Just intercept the resolve request for the retargetable assembly references and use Assembly.Load() to let the CLR sort it out from the loading context of your AppDomain. Alter your AssemblyResolve event handler like this:

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

This worked well in my test app, I trust it will solve your problem with Autofac as well.

这篇关于尝试将Autofac加载为嵌入式程序集时FileNotFoundException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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