在.NET中编译与版本无关的DLL

脚本

我有两个围绕Microsoft Office的包装器,一个用于2003,一个用于2007.由于两个版本的Microsoft Office并行运行“非官方可能”,也不是微软推荐的,我们有两个盒子,一个用Office 2003和另一个使用Office 2007.我们分别编译包装器。 DLL包含在我们的解决方案中,每个框都有相同的签出但Office 2003或2007“卸载”,因此它不会尝试编译该特定的DLL。 如果不这样做将导致编译错误,因为Office COM DLL不可用。

我们使用.NET 2.0和Visual Studio 2008。

事实

由于Microsoft在2007年神秘地改变了Office 2003 API,重命名和更改了一些方法( 叹气 )从而使它们不向后兼容,我们需要两个包装器。 我们为每台构建机器提供了解决方案,并激活了一个Office DLL。 例如:具有Office 2003的计算机已卸载“Office 2007”DLL,因此无法对其进行编译。 另一个盒子是相同的想法,但反过来。 这一切都是因为我们不能在同一个盒子中有2个不同的Office用于编程。 (根据微软,你可以在技术上将两个Office放在一起),但不能用于编程,也不能没有一些问题。

问题

当我们更改应用程序版本(例如从1.5.0.1到1.5.0.2)时,我们需要重新编译DLL以匹配新版本的应用程序,这是自动完成的,因为Office包装器包含在解决方案中。 由于包装器包含在解决方案中,因此它们inheritance了APP版本,但我们必须执行两次,然后将另一个DLL“复制”到创建安装程序的计算机上。 (痛苦……)

是否可以编译一个可以与任何版本的应用程序一起使用的DLL,尽管它“更老”? 我已经阅读了一些关于清单的内容,但我从未与这些内容进行过互动。 任何指针将不胜感激。

这样做的秘密原因是我们没有更改“年龄”中的包装器,微软也没有更改其古老的API,但我们正在重新编译DLL以匹配我们制作的每个版本上的应用程序版本。 我想自动化这个过程,而不是依赖两台机器。

我无法从项目中删除DLL(它们都没有),因为存在依赖项。

我可以创建第三个“主包装器”但尚未考虑过它。

有任何想法吗? 有其他要求相同的人吗?

UPDATE

澄清:

我有一个N项目的解决方案。

“应用程序”+ Office11Wrapper.dll + Office12Wrapper.dll。

两个“包装器”都使用应用程序的依赖关系+解决方案中的其他库(数据层,业务层,框架等)

每个包装器都有相应Office包的引用(2003和2007)。

如果我编译并且没有安装Office 12,则会从Office12Wrapper.dll中找不到Office 2007库的错误。 所以我拥有两台构建机器,一台使用Office 2003,一台使用Office 2007.在每台机器上进行完整的SVN更新+编译后,我们只需在“安装程序”中使用office12.dll就可以将编译器编译为“相同”代码,相同版本“。

注意:Office 2007 Build Machine,Office 2003的Wrapper“已卸载”,反之亦然。

提前致谢。

当.NET程序集解析程序无法在运行时找到引用的程序集时(在这种情况下,它无法找到应用程序链接的特定包装DLL版本),其默认行为是失败并且实质上使应用程序崩溃。 但是,可以通过挂钩AppDomain.AssemblyResolve事件来覆盖此行为。 无论何时找不到引用的程序集,都会触发此事件,并且它使您有机会替换另一个程序集来代替缺少的程序集(前提是它们是兼容的)。 因此,例如,您可以替换自己加载的旧版本的包装器DLL。

我发现这样做的最好方法是在挂钩事件的应用程序的主类上添加一个静态构造函数,例如:

using System.Reflection; static Program() { AppDomain.CurrentDomain.AssemblyResolve += delegate(object sender, ResolveEventArgs e) { AssemblyName requestedName = new AssemblyName(e.Name); if (requestedName.Name == "Office11Wrapper") { // Put code here to load whatever version of the assembly you actually have return Assembly.LoadFile("Office11Wrapper.DLL"); } else { return null; } } } 

通过将它放在主应用程序类的静态构造函数中,可以保证在任何代码尝试访问包装器DLL中的任何内容之前运行它,确保钩子提前到位。

您还可以使用策略文件进行版本重定向,但这往往更复杂。

只是一个想法 – 您可以使用TlbExp创建两个互操作程序集(具有不同的名称和程序集),并使用接口/工厂通过您自己的接口对这两个进行编码吗? 一旦你有了interop dll,你就不需要COM依赖(当然除了测试等)。

TlbImp有一个版本的/ asmversion,所以它可以作为构建脚本的一部分完成; 但我确定你甚至需要这个:只是确保参考(解决方案资源管理器)中的“特定版本”是错误的?

另外 – 我知道它没有帮助,但C#4.0带有dynamic和/或“没有PIA”可能会有所帮助(将来;也许)。

我不确定我是否完全遵循你所说的一切,但让我试试:

听起来你有两个(?)项目的解决方案。 一个是实际的应用程序,另一个是Office API的包装器。 然后,您的应用程序具有对Office API包装器的项目引用。 我以前从来没有为办公室编程,但听起来编程API是一个常见的组件,你只能在一台机器上有一个版本(即2003或2007,而不是两者)。 也许这就是问题所在,但是因为你有一个项目引用,所以首先编译包装器,将其复制到应用程序的bin目录中,然后你的应用程序将链接到包装器的构建版本。 这将导致应用程序的清单在运行时专门请求该包装器的版本。

如果您将包装器放在单独的解决方案中,并添加了对已编译库而不是项目的引用,那么您始终会将应用程序链接到该包装器的版本,并且可以避免此问题。

另一种可能的选择是assembly绑定重定向。 这是更先进的,并伴随着它自己的一系列问题,但你可以在这里阅读它。

或者类似于Marc的想法,您可以提取接口并将一些常见对象拉入Framework库,并针对接口和公共对象对应用程序进行编码。 然后在运行时使用reflection来加载程序集并实例化所需的包装器。

我认为关键是如果可以的话删除项目依赖项。 这听起来像包装器非常稳定并且没有改变,否则你不会要求链接到它的先前版本。

在同一台机器上并排安装Office 2003和2007 绝对是可能的 – 我们甚至在最终用户生产工作站上也在我们的组织中进行。

在该链接文章中,Microsoft建议您不要将其用于实际用途。 但在你的情况下,它似乎只适用于单个构建机器,即你不会在该机器上实际使用任何一个版本的Office。 在这种情况下,我会尝试看看你是否可以进行并排安装工作。

我的假设可能是错的,你试图为每个开发人员的机器执行此操作。 在这种情况下,你应该忽略这个答案:-)

不错的模具! 我只是将基于上述概念的实现集合在一起,并且它工作得非常好:

 static Assembly domain_AssemblyResolve(object sender, ResolveEventArgs args) { string partialName = args.Name.Substring(0, args.Name.IndexOf(',')); return Assembly.Load(new AssemblyName(partialName)); } 

当然还有增强的空间,但这对我有用!