使用同一个dll的2个不同版本?

Posted

技术标签:

【中文标题】使用同一个dll的2个不同版本?【英文标题】:Using 2 different versions of the same dll? 【发布时间】:2017-03-10 10:03:36 【问题描述】:

我已获得 2 个预编译的 dll:

Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL

Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL

API 差异示例:

我正在尝试将两者都加载到一个项目中以执行以下操作:

extern alias v10;
extern alias v20;

private static void UpgradeUser()

    // Load old user
    var userOld = new v10::Common.Data.UserData();
    userOld.loadData("user.dat");

    // Create new user
    var userNew = new v20::Common.Data.UserData();

    // Copy properties  
    userNew.FirstName = userOld._firstName;
    userNew.LastName = userOld._lastName;
    userNew.Age = userOld._age;

    // Invoke method from v10 and v20 API
    userOld.version();
    userNew.DisplayVersion();

    if (userNew.GetUserInfo() != userOld.getInfo())
    
        throw new Exception("Discrepencies in upgrade ");
    

    Console.WriteLine("Upgrade done!");

我已将我的项目引用和app.config 设置为以下内容。我还手动将 dll 复制到我的输出文件夹中,匹配 appconfig hrefs

<!-- [Edited: see history for previous version] -->
<Reference Include="Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
  <HintPath>libs\Common.Data.1_0_0_0.dll</HintPath>
  <Aliases>v10</Aliases>
</Reference>

<Reference Include="Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
  <HintPath>libs\Common.Data.2_0_0_0.dll</HintPath>
  <Aliases>v20</Aliases>
</Reference>

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="Common.Data" publicKeyToken="f3b12eb6de839f43" culture="neutral" />
      <codeBase version="1.0.0.0" href="libs\Common.Data.1_0_0_0.dll" />
      <codeBase version="2.0.0.0" href="libs\Common.Data.2_0_0_0.dll" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

我已经成功构建。

但是当我尝试运行它时,我得到一个 MissingMethodException 代表 UserData.loadData

我浏览过多个 *** 帖子、msdn 和 codeproject 文章,但似乎无法让它发挥作用。

Link 1, Link 2, Link 3, Link 4

认为我错过了一个重要的步骤,但不知道是什么,真的需要一些帮助。

[编辑1]

我尝试过单独使用这些 dll,它们可以正常工作。 (消除了混乱。请参阅版本历史以获取屏幕截图)

[编辑2]

我尝试了 Mukesh Kumar 的提议,并将我的 app.config 更改为:

<runtime>
  <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
    <dependentAssembly>
      <assemblyIdentity name="Common.Data" 
                        publicKeyToken="f3b12eb6de839f43" 
                        culture="neutral" />
      <bindingRedirect oldVersion="1.0.0.0"
                       newVersion="2.0.0.0"/>
    </dependentAssembly>
  </assemblyBinding>
</runtime>

但它仍然不起作用。我现在收到FileNotFoundException

[编辑3]

好的,我几乎可以肯定 &lt;bindingRedirect&gt; 不正确,应该改为 &lt;codeBase&gt;

我尝试从 CLI 编译:

csc Program.cs /reference:v10=libs/Common.Data.1_0_0_0.dll /reference:v20=libs/Common.Data.2_0_0_0.dll

而且效果很好。我能够同时使用这两个 API:

但是当我尝试从 Visual Studio 构建它时,它会抱怨 /reference,即使我已经指定了引用别名:

The extern alias 'v10' was not specified in a /reference option

我尝试修改&lt;Reference /&gt; 以包含/排除&lt;SpecificVersion&gt;True&lt;/SpecificVersion&gt;,但没有任何效果。

我找到了这个post,解决方案是删除并重新添加路径。使用该解决方案,Visual Studio 构建良好,但我又回到了System.MissingMethodException

感觉我快要搞定了,但并不完全。如何让 Visual Studio 正确构建?

[编辑4]

我试过 miguel 的方法,但还是不行。

在这次尝试中,我将 dll 重命名为原来的名称,并将它们存储在不同的文件夹中。

然后我更新了 app.config 以执行 bindingRedirect 以及代码库。

运行它时,我得到MissingMethodException

我不确定4- Find the and put in False 是什么意思,所以我尝试了&lt;Private&gt;&lt;SpecificVersion&gt; 的所有组合,以及将&lt;Reference Include&gt; 设置为FQN,但这些组合都不起作用。

查看我的第三次编辑,当通过 CLI 完成时,我已经成功编译和运行示例(使用我重命名的 dlls + app.config 代码库 hrefs)。

我现在的问题是,我如何配置我的 csproj,所以它的构建是一样的。

【问题讨论】:

您能发布 StackTrace 吗? 您可以尝试从配置中删除 &lt;runtime&gt; 部分(您不应该需要它)并将 global 别名添加到您的程序集中。不确定它是否会有所作为,但我一直这样做没有问题,而且我总是添加全局命名空间,比如"global,v10" 找不到该方法的原因是它可能试图使用错误的程序集。为什么loadDataCommon.Data.UserDa.. 以红色突出显示?这是一个更清晰的错误,对吗?它说什么? @caesay,是的,这是一个更清晰的错误Cannot resolve symbol 'loadData',尽管 VS 构建成功。 dll 已重命名,这就是我在 appconfig.xml 中添加runtime 元素的原因。没有它,我会得到一个FileNotFoundException - Could not load file or assembly 'Common.Data... 奇怪。也许您可以尝试将您从 Main 调用的 DLL 以其正常名称导入与可执行文件相同的文件夹中,或者编译您自己的一对 DLL 以检查库中是否存在问题。 【参考方案1】:

您需要将依赖程序集与 bindingRedirect 一起使用,但您还需要将 dll 放在不同的文件夹中或以不同的名称保存。完成此操作后,您需要在 app.config 中添加以下内容:

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
  <dependentAssembly>
        <assemblyIdentity name="myAssembly"
                          publicKeyToken="here token dll"
                          culture="neutral" />
       <bindingRedirect oldVersion="0.0.0.0-1.0.0.0" newVersion="1.0.0.0" />
       <bindingRedirect oldVersion="1.0.0.1-2.0.0.0" newVersion="2.0.0.0" />
       <codeBase version="1.0.0.0" href="folder\namedll.dll" />
       <codeBase version="2.0.0.0" href="folder\namedll.dll" />
      </dependentAssembly>
   </assemblyBinding>

使用此代码应该可以编译和运行,但有时 VS 会在编译时删除或覆盖 app.config 中的代码。您需要在编译文件夹的配置文件中检查它。如果成功,您可以编辑 .csproj。为此,您必须这样做:

1- 卸载受影响的项目 2-右键单击项目 3- 单击编辑项目 4- 找到 &lt;AutoGenerateBindingRedirects&gt; 属性并将其设置为 False 5- 保存更改并重新加载项目

这对我有用。在我的项目中,我使用了两个版本的 Automapper。

最后,另一种解决方案是使用AppDomain.CurrentDomain.AssemblyResolve 构建事件并加载特定的dll。

为此,您需要捕捉事件:

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)

    //debug and check the name
    if (args.Name == "MyDllName")
        return Assembly.LoadFrom("c:\\pathdll\midllv1.dll")
    else if(args.Name ="MyDllName2")
        return Assembly.LoadFrom("c:\\pathdll\midllv2.dll");
    else
        return Assembly.LoadFrom("");

【讨论】:

我试过这个(见Edit4),但还是得到了相同的MissingMethodException。我很确定&lt;codeBase /&gt; 就足够了(Edit3)。我只是不知道如何配置我的 csproj,所以它模仿 csc CLI 编译。 @jsjslim 我在您的 app.config 代码中看到 BindingRedirect 的版本不正确,您需要将 bindingRedirect 定义为 ´´ ´´ 当我说'4-找到并放入False'时,我想说设置属性 为 False 感谢编辑。是&lt;AutoGenerateBindingRedirect&gt;false&lt;/&lt;AutoGenerateBindingRedirect&gt; 为我解决了问题。尽管 VS 和 Resharper 都抱怨过,但构建成功并按预期运行。 对于网站,href 应以“bin\”开头,例如 @miguel - 但是如何在 Visual Studio 中添加 2 个对同名 dll(但不同版本)的引用?当我尝试这样做时(通过“添加引用”>“浏览”),我得到“无法添加对 'aaa.dll 的引用”。项目中已存在对组件“aaa”的引用。”【参考方案2】:

缺少适合我需要的完整答案,我决定以AssemblyResolve 的方式捐赠我的解决方案,以使用两个 dll 并从文件加载相关文件,使用反射来解析类型。对于这个演示,我创建了两个名为 MathFuncs 的 dll,尝试调用它们的 Add.add 函数将在两种不同的实现中解析。要查看不同的结果,请在值 1 和 2 之间切换版本整数:

public static int version = 1;
    public static void Main(string[] args)
    
        AppDomain.CurrentDomain.AssemblyResolve += Program.CurrentDomain_AssemblyResolve;
        version = 1;
        Type a = Type.GetType("MathFuncs.Add, MathFuncs, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
        MethodInfo methodInfo = a?.GetMethod("add");
        object result = null;
        if (methodInfo != null)
        
            object[] parametersArray = new object[] 1, 2;
            result = methodInfo.Invoke(Activator.CreateInstance(a, null), parametersArray);
        

        if (result != null)
        
            Console.WriteLine((int)result);
        
        else
        
            Console.WriteLine("failed");
        

        Console.Read();
    


    public static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    
        FileInfo fi = null;
        if (version == 1)
        
            fi = new FileInfo("C:\\Users\\ohbitton\\Desktop\\MathFuncs\\MathFuncs.dll");
        
        else
        
            fi = new FileInfo("C:\\Users\\ohbitton\\Desktop\\MathFuncs2\\MathFuncs.dll");
        
        return Assembly.LoadFrom(fi.FullName);

    

要获取 Type.GetType 的命名空间的完整名称,您可以使用 powershell :

([system.reflection.assembly]::loadfile("C:\Users\ohbitton\Desktop\MathFuncs\MathFuncs.dll")).FullName

【讨论】:

【参考方案3】:

尝试将您的配置详细信息如下所示。

 <dependentAssembly>
            <assemblyIdentity name="myAssembly"
                              publicKeyToken="32ab4ba45e0a69a1"
                              culture="neutral" />
            <bindingRedirect oldVersion="1.0.0.0"
                             newVersion="2.0.0.0"/>
  </dependentAssembly>

这里你可以为你提供dll旧版本和新版本。你可以关注这个article 和this。

希望这会对你有所帮助。

【讨论】:

感谢您的回复。不幸的是,它仍然无法正常工作。使用&lt;bindingRedirect&gt; 时,我得到FileNotFoundException。请注意,在我的帖子中,PublicKeyToken 是相同的,API 已更改,并且我尝试同时使用这两个 API,而不使用反射(以免丢失智能感知和编译时检查)。我已更新我的问题以包含更多信息。

以上是关于使用同一个dll的2个不同版本?的主要内容,如果未能解决你的问题,请参考以下文章

如何使应用程序与 2 个不同版本的 DLL 一起工作

如何使用 MSBuild 引用不同版本的 dll

我如何解决Nuget DLL地狱-无论我做什么VS都坚持认为dll版本与软件包中的版本不同

在运行时加载 2 个版本的程序集

3rd 方库是指不同版本的 log4net.dll

使用 C++ 应用程序加载 dll