使用同一个 dll 的 2 个不同版本? [英] Using 2 different versions of the same dll?

查看:17
本文介绍了使用同一个 dll 的 2 个不同版本?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我得到了 2 个预编译的 dll:

Common.Data,Version=1.0.0.0,Culture=neutral,PublicKeyToken=f3b12eb6de839f43,processorArchitecture=MSILCommon.Data,版本=2.0.0.0,Culture=neutral,PublicKeyToken=f3b12eb6de839f43,processorArchitecture=MSIL

API 差异示例:

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

extern 别名 v10;外部别名 v20;私有静态无效升级用户(){//加载老用户var userOld = new v10::Common.Data.UserData();userOld.loadData("user.dat");//创建新用户var userNew = new v20::Common.Data.UserData();//复制属性userNew.FirstName = userOld._firstName;userNew.LastName = userOld._lastName;userNew.Age = userOld._age;//从 v10 和 v20 API 调用方法userOld.version();userNew.DisplayVersion();如果 (userNew.GetUserInfo() != userOld.getInfo()){throw new Exception("升级中的差异");}Console.WriteLine("升级完成!");}

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

<!-- [已查看之前版本的历史记录] --><Reference Include="Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL"><HintPath>libsCommon.Data.1_0_0_0.dll</HintPath><别名>v10</别名></参考><Reference Include="Common.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL"><HintPath>libsCommon.Data.2_0_0_0.dll</HintPath><别名>v20</别名></参考><运行时><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><从属程序集><assemblyIdentity name="Common.Data" publicKeyToken="f3b12eb6de839f43"culture="neutral"/><codeBase version="1.0.0.0" href="libsCommon.Data.1_0_0_0.dll"/><codeBase version="2.0.0.0" href="libsCommon.Data.2_0_0_0.dll"/></dependentAssembly></assemblyBinding></运行时>

我已经成功构建.

但是当我尝试运行它时,我收到了 UserData.loadDataMissingMethodException.

我已经阅读了多个 stackoverflow 帖子、msdn 和 codeproject 文章,但似乎无法让它发挥作用.

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

未在/reference 选项中指定外部别名v10"

我尝试修改 以包含/排除 True 没有效果.

我发现了这个

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

运行它时,我收到 MissingMethodException.

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

查看我的第 3 次编辑,通过 CLI 完成后,我已成功编译并运行示例(使用我重命名的 dll + app.config 代码库 href).

我现在的问题是,如何配置我的 csproj,使其构建相同.

解决方案

您需要使用带有 bindingRedirect 的dependentAssembly,但您还需要将 dll 放在不同的文件夹中或使用不同的名称保存.完成此操作后,您需要将以下内容放入您的 app.config 中:

<从属程序集><assemblyIdentity name="myAssembly"publicKeyToken="这里是令牌 dll"文化=中性"/><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
amedll.dll"/><codeBase version="2.0.0.0" href="folder
amedll.dll"/></dependentAssembly></assemblyBinding>

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

<块引用>

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

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

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

为此,您需要捕获事件:

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);公共静态 System.Reflection.Assembly CurrentDomain_AssemblyResolve(对象发送者,ResolveEventArgs args){//调试并检查名称if (args.Name == "MyDllName")return Assembly.LoadFrom("c:\pathdllmidllv1.dll")否则 if(args.Name ="MyDllName2")return Assembly.LoadFrom("c:\pathdllmidllv2.dll");别的返回 Assembly.LoadFrom("");}

I have been given 2 pre-compiled dlls:

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

Example of differences in API:

And I'm trying to load both into a single project to do something like this:

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

I've set up my project references and app.config to the following. I'm also manually copying the dlls into my output folder, matching the appconfig hrefs

<!-- [Edited: see history for previous version] -->
<Reference Include="Common.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f3b12eb6de839f43, processorArchitecture=MSIL">
  <HintPath>libsCommon.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>libsCommon.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="libsCommon.Data.1_0_0_0.dll" />
      <codeBase version="2.0.0.0" href="libsCommon.Data.2_0_0_0.dll" />
    </dependentAssembly>
  </assemblyBinding>
</runtime>

I've gotten insofar as to build successfully.

But when I try to run it, I get a MissingMethodException for UserData.loadData.

I've been through multiple stackoverflow posts, msdn and codeproject articles, but can't seem to get it to work.

Link 1, Link 2, Link 3, Link 4

Think I'm missing an important step but can't figure out what, and could really use some help.

[Edit1]

I've tried using the dlls separately, and they work. (Removed clutter. See version history for screenshots)

[Edit2]

I've tried Mukesh Kumar's proposal, and changed my app.config to:

<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>

But it still does not work. I'm now getting FileNotFoundException.

[Edit3]

Ok, I'm almost certain the <bindingRedirect> is not correct, and should be <codeBase> instead.

I tried compiling from the CLI:

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

And it works fine. I was able to use both APIs at the same time:

But when I try to build it from Visual Studio, it complains about /reference, even though I've already specified the reference alias:

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

I've tried modifying <Reference /> to include/exclude <SpecificVersion>True</SpecificVersion> with no effect.

I found this post, where the solution was to remove and re-add the paths. Using that solution, Visual Studio builds fine, but I'm back to System.MissingMethodException.

Feels like I've almost got it, but not quite. How can I get Visual Studio to build correctly?

[Edit4]

I've tried miguel's method, but still not working.

In this attempt, I've renamed the dlls back to their original names, and store them in different folders instead.

I then updated app.config to do a bindingRedirect as well as codebase.

When running it, I'm getting MissingMethodException.

I wasn't sure what 4- Find the and put in False meant, so I tried all combinations of <Private>, <SpecificVersion>, as well as setting <Reference Include> to FQNs, but none of those combinations work.

Looking at my 3rd edit, I've managed to compile and run the sample successfully (with my renamed dlls + app.config codebase hrefs) when done via the CLI.

My problem now is, how do I configure my csproj, so it builds the same.

解决方案

You need to use a dependentAssembly with bindingRedirect but also you need put dlls in different folder or save with a different name. With this done, you need to put the following in your 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
amedll.dll" />
       <codeBase version="2.0.0.0" href="folder
amedll.dll" />
      </dependentAssembly>
   </assemblyBinding>

With this code should compile and run, but sometimes VS deletes or overwrite the code in the app.config when compiles it. You need to check it in config file of compilation folder. If this succeeds, you can edit the .csproj. For this you must do:

1- Unload the project affected
2- Right click on project
3- Click Edit project
4- Find the <AutoGenerateBindingRedirects> property and set it to False
5- Save changes and reload project

This works for me. In my project, I'm using two versions of Automapper.

Finally, another solution is to use the AppDomain.CurrentDomain.AssemblyResolve build event and load the specific dll.

For that, you need catch the event:

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:\pathdllmidllv1.dll")
    else if(args.Name ="MyDllName2")
        return Assembly.LoadFrom("c:\pathdllmidllv2.dll");
    else
        return Assembly.LoadFrom("");
}

这篇关于使用同一个 dll 的 2 个不同版本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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