我在这个领域进行了相当广泛的工作,并且一直发现您需要围绕范围内和范围外的确切内容设置一些界限。想要最大的可扩展性是有风险的,但这一切都是有代价的。这个成本要么是编译时,以约定、最佳实践的形式,也许还有自动构建检查——或者它会是一个复杂的运行时。
要解决您列出的选项:
绑定重定向只是实现解决方案的部分工具。它们将允许您的程序“滑动”一个 DLL 版本来代替另一个版本,但是,它不会神奇地解决方法更改时发生的问题。缺少方法异常?这里你可能没有的东西是依赖链。
您可以看到,虽然应用程序将依赖项“A”视为版本 1 对象,但在内部它正在从更高版本创建一些东西,该版本被传递回应用程序并转换为 v1.0 - 导致异常。这可能很难处理——这只是风险之一。
在构建中保持合约程序集版本相同这可以优雅地工作,但是,它只是将复杂性从构建时推迟到运行时。您需要努力确保您的更改不会破坏跨版本的兼容性。更不用说随着您的应用程序老化,您将在这些合同中收集很多您想要弃用的声明。最终,这个文件将变得庞大、繁琐并且让开发人员感到困惑——这甚至还没有考虑到您拥有的所有实体合约!
我不太确定您所说的这个是什么意思,以及它如何涵盖您的问题空间。
您可以采取的另一种方法(我们这样做)是为“SDK”的每个主要版本创建一个新合同。这具有一些政治优势,因为它在一段时间内修复了主要功能,这意味着我们可以将功能请求保持在合理的预期水平,并且超出此范围的任何内容(需要新一代合同)都将推迟到“下一个主要版本” '。但是,这确实需要在设计功能时尽职尽责——在编写合同时要深谋远虑,这样你就可以预先考虑最明显的要求——但我真的觉得无论如何这都是不言而喻的......它们被称为“合同”因为某种原因。每个新合同都将存在于版本命名空间(Company.Product.Contracts.v1_0、Company.Product.Contracts.v1_1)中。
我不会链接我的合同(每个新版本的合同都继承最后一个)。这样做会让您回到保持版本号相同的问题,如果不完全破坏链条,您永远无法完全摆脱功能。
当您的插件加载时,它可以询问主机它支持什么级别的功能(合同版本) - 如果它是旧的主机/较新的插件方案:或者,对插件进行编程以减少其运行时功能以处理较少的主机功能,或者干脆拒绝加载。无论如何,您可能应该执行这些检查,因为没有魔法可以让您的插件利用主机中根本不存在的功能!Microsoft 的 MAF 框架试图通过使用 shim 基础结构来实现这一点,但对于大多数人来说,它会导致大量的复杂性。
因此,您需要考虑的一些事项是:
- 确定您的可扩展性要求!您想要完成的一切都将花费您进行持续维护。
- 想想你将如何弃用功能
- 不要忘记您的合约将包含实体以及逻辑合约,这些与逻辑合约的考虑略有不同,因为它们通常被传递得更多。
- 仔细考虑是否在编译时而不是运行时更好地执行每个兼容性检查(反之亦然)
- 版本编号!程序集版本号非常适合运行时行为,文件版本号可以帮助您在版本控制中将 DLL 跟踪回源 - 充分利用它们!
- 如果您正在执行自定义 DLL 解析,请使用 app.config 来定义您的自定义 DLL 位置,而不是程序集解析事件。配置方法更容易预测,而且,嘿,它是在易于阅读的 Xml 中声明的!Fusion Log Viewer 还将很好地报告您的 DLL 在探测链中的插入位置,而 assembly-resolve 事件将隐藏您在代码中的所有逻辑和规则。唯一真正的缺点是使用 app.config 意味着更改不会生效,直到您的应用程序重新读取配置文件(通常是应用程序重新启动),但如果您正在对插件进行 AppDomain 隔离,您甚至可以解决这个问题。
与您的“core.dll”问题有关...我认为,对您来说,这是一个相对简单的问题。您的核心合同 DLL 中的所有内容都应该存在于版本命名空间下(参见上文,Company.Product.v1_0 等),因此您的 DLL 还包含版本号实际上是有意义的。这将消除您的 DLL 在部署到 bin 文件夹时相互覆盖的问题。不要依赖 GAC - 从长远来看,这将是一个痛苦。令人遗憾的是,开发人员似乎总是忘记 GAC 会覆盖所有内容,这可能会成为调试的噩梦——它还会影响您在权限方面的部署方案。
如果您确实需要保持 DLL 名称相同 - 您可以在您的应用程序中创建一个“本地 gac”,这将使您能够以一种不会相互覆盖的方式存储您的 DLL,但仍然可以通过运行时。查看 app.config 中的“绑定重定向”(在此处查看我的答案)。这可以与应用程序 bin 文件夹下的“伪 GAC 文件夹结构”结合使用。然后,您的应用程序将能够找到所需的任何版本的 DLL,而无需任何自定义程序集解析代码逻辑。我将使用您的应用程序部署所有以前支持的 core.dll 版本。如果您的应用程序升级到版本 9,并且您决定同时支持版本 7 和 8 的插件,那么您只需要包含 Core.7.dll、Core.8.dll 和 Core.9.dll。您的插件加载逻辑应该检测对旧版本 Core 的依赖关系,并提醒用户插件不兼容。
这个话题有很多,如果我想到与您的事业相关的其他任何事情,我会回来查看...