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

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

问题描述

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

  Common.Data,版本= 1.0.0.0,文化=中性,PublicKeyToken = f3b12eb6de839f43,processorArchitecture = MSIL 

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

API差异示例:





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

 外部别名v10; 
extern别名v20;

private static void UpgradeUser()
{
//加载旧用户
var userOld = new v10 :: Common.Data.UserData();
userOld.loadData( user.dat);

//创建新用户
var userNew =新v20 :: Common.Data.UserData();

//复制属性
userNew.FirstName = userOld._firstName;
userNew.LastName = userOld._lastName;
userNew.Age = userOld._age;

//从v10和v20 API调用方法
userOld.version();
userNew.DisplayVersion();

if(userNew.GetUserInfo()!= userOld.getInfo())
{
抛出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> libs\Common.Data.1_0_0_0.dll< / HintPath>
< Aliases> v10< / Aliases>
< / 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>

我已经成功地构建了。



但是当我尝试运行它时,我得到了 UserData.loadData MissingMethodException





我已经浏览过多个stackoverflow帖子,msdn和codeproject文章,但是似乎无法使其正常工作。



,解决方案是删除并重新添加路径。使用该解决方案,Visual Studio可以很好地构建,但是我又回到了 System.MissingMethodException



感觉就像我已经差不多了,但还不是很清楚。如何使Visual Studio正确构建?



[Edit4]



我尝试了miguel的方法,但仍然无法使用。



在此尝试中,我将dll重命名为其原始名称,并将其存储在其他文件夹中。





然后我更新了app.config以执行此操作



运行它时,我得到 MissingMethodException



我不确定 4-是什么,然后输入False ,所以我尝试了< Private> ,< SpecificVersion> ,以及设置< Reference Include> 转换为FQN,但这些组合均无效。



看着我的第3次编辑,我设法编译并运行了通过CLI成功完成示例后(使用我重命名的dlls + app.config代码库hrefs)。



我现在的问题是,如何配置csproj,以便构建

解决方案

您需要使用带有bindingRedirect的dependentAssembly,但也需要将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-查找< AutoGenerateBindingRedirects> 属性并将其设置为False

5-保存更改并重新加载项目


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



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



为此,您需要捕获事件:

  AppDomain.CurrentDomain.AssemblyResolve + =新的ResolveEventHandler(CurrentDomain_AssemblyResolve); 

公共静态System.Reflection.Assembly CurrentDomain_AssemblyResolve(对象发送者,ResolveEventArgs args)
{
//调试并检查名称
if(args.Name == MyDllName)
返回Assembly.LoadFrom( c:\\pathdll\midllv1.dll)
否则if(args.Name = MyDllName2)
返回Assembly。 LoadFrom( c:\\pathdll\midllv2.dll);
else
return 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>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>

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\namedll.dll" />
       <codeBase version="2.0.0.0" href="folder\namedll.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:\\pathdll\midllv1.dll")
    else if(args.Name ="MyDllName2")
        return Assembly.LoadFrom("c:\\pathdll\midllv2.dll");
    else
        return Assembly.LoadFrom("");
}

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

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