自定义.NET可移植类库配置文件?

时间:2013-05-04 16:16:25

标签: .net portable-class-library reflexil

我需要添加和/或修改配置文件,以允许在PCL中共享更多的类和成员(其中许多是内置于框架中的,如Thread.Sleep)。最好的方法是什么?有什么工具可以帮助吗?



PS:我不是在寻求告诉我不要或停止。我想拥有可以在不同环境中共享的一次编译DLL。没有每个平台的二进制文件,没有重新编译,没有ifdef。


以下是我到目前为止所得到的:

要求:

  • 目标环境:Silverlight 5和.NET Framework 4.5。
  • PCL的目的:RIA客户端和ASP.NET服务器(无WCF)的共享基础架构
  • 默认配置文件中缺少什么:XPath,Thread方法,DynamicMethod / ILGenerator
参考装配\ Microsoft \ Framework.NETPortable 下的

PCL配置文件

  • 所有程序集都是存根,并设置了“Retargetable”属性。
  • 所有程序集都有标志= 0x171:0x001已签名,0x100可重定向,并且在AssemblyNameFlags中未定义0x070(似乎无效)
  • 程序集之间的所有引用都具有“Retargetable”属性。
  • 具有Silverlight支持的所有程序集都是版本2.0.5.0。
  • 构建的PCL二进制文件包含每个引用程序集的两个引用(例如:mscorlib 2.0.5.0 retargetable + mscorlib 4.0)

自定义尝试#1

  • 配置文件:Silverlight 5 + .NET Framework 4.5(配置文件24)
  • 将SL5 mscorlib.dll复制到个人资料24
  • 将SL5 mscorlib.dll标记为可重定向(更改为延迟签名)
  • ReSharper:未能解决所有扩展方法,通用类型/值匹配错误
  • 构建:成功,运行:成功

自定义尝试#2

  • 配置文件:Silverlight 5 + .NET Framework 4.5(配置文件24)
  • 将所有SL5 DLL复制到配置文件24
  • 将所有SL5 DLL标记为可重定向(更改为延迟签名)
  • 将SL5 DLL之间的所有引用标记为可重定向
  • ReSharper:未能解决所有扩展方法,通用类型/值匹配错误
  • 构建:成功,运行:成功

自定义尝试#3

  • 配置文件:Silverlight 4 + .NET Framework 4.0.3(配置文件18)
  • 将SL4 mscorlib.dll复制到个人资料18
  • 将SL4 mscorlib.dll标记为可重定向(更改为延迟签名)
  • ReSharper:成功
  • 构建:成功,运行:成功

自定义尝试#4

  • 配置文件:Silverlight 4 + .NET Framework 4.0.3(配置文件18)
  • 将所有SL4 DLL复制到配置文件18
  • 将所有SL4 DLL的.NET运行时版本设置为v4(原始DLL具有该效果未知)
  • 将所有SL4 DLL标记为可重定向(更改为延迟签名)
  • 将SL4 DLL之间的所有引用标记为可重定向
  • ReSharper:成功
  • 构建:成功,运行:成功

自定义尝试#5 继承#4

  • 配置文件:Silverlight 4 + .NET Framework 4.0.3(配置文件18)
  • 将SL4的System.Numerics(包含在其他SL配置文件中)添加到RedistList \ FrameworkList.xml
  • 将SL4的System.Xml.XPath(未包含在任何SL配​​置文件中)添加到RedistList \ FrameworkList.xml
  • 结果:无法从默认PCL引用中解析System.Numerics和System.Xml.XPath
  • 修复:手动引用两个DLL - 无法强制它们重新定位,但由于下面提到的问题,VS无法使用非重定向的System.Numerics或System.Xml.XPath进行编译

注意:

  • 编译错误:“...在未引用的程序集中定义,您必须添加对程序集的引用”。在所有组件都可重新定位后发生,但它们之间的引用之一不会更改为“重定向”

它在某种程度上起作用,但是定制现有引用的DLL或添加新的DLL非常麻烦,在覆盖引用的DLL(如果可能的话)之后也不能轻易验证PCL代码。

2 个答案:

答案 0 :(得分:10)

由于你没有采取 NO 停止作为答案,让我试着解释为什么这是一个坏主意。简短的回答是:如果PCL没有公开API,通常是因为它不能工作。

首先,PCL没有自己的API集。 PCL只是暴露了您要定位的给定平台集之间的API交叉点。现在,有些情况下,API级别交集将产生比PCL公开的API更多的API。有几个原因可能是这种情况。

  1. API并非在所有平台上都可用
  2. API可用,但实际上并不起作用
  3. API在不同的程序集中定义
  4. 第一个应该是显而易见的。 PCL本身并不是一个真正的平台,只会暴露其中的内容。因此,我们无法为您提供在您定位的所有平台上实际存在的API。毕竟,我们暴露了交集。

    第二个听起来有点奇怪,但确实发生了。以Windows Phone 7上的文件IO为例。虽然Windows Phone上技术上提供File class,但它记录为

      

    此类型用于支持.NET Compact Framework基础结构   在Silverlight for Windows Phone中,它不适用于您的   应用程序代码。

    您可以说"我在乎什么?"并只是尝试它,但你会发现手机上的安全模型将阻止您访问您正在寻找的文件。因此,在PCL中公开此API将没有任何帮助。事实上,我们的团队认为这实际上会伤害到你,因为它会导致你走上一条不可移植的道路。

    围绕在​​不同程序集中实现的API的第三个问题涉及更多。为了理解为什么这是一个问题,您需要考虑CLR如何处理API。 CLR不具备加载单个类型的概念,例如Java。在.NET中,类型是在程序集中实现的,为了使用它们("加载它们"),您需要加载定义类型的程序集。在封面下,类型引用包括命名空间限定类型名称以及定义类型的程序集。通常,具有相同名称空间限定名称但位于不同程序集中的类型被视为不同。例如,类型MyNamespace.MyType, Assembly1MyNamespace.MyType, Assembly2。请注意,程序集本身也有一个完全限定名称的概念;它包括程序集名称和公钥标记。这允许两家公司生产一种名为" Foo"而不是混淆CLR(假设,当然,它们是用不同的密钥签名的)。因此,本质上,加载类型需要几个步骤:找到定义类型的程序集,加载该程序集,然后加载类型。

    通常,不同的.NET平台对平台程序集使用不同的键,例如mscorlib。现在您可能想知道如何在.NET Framework上使用Silverlight中的类型。原因是CLR具有装配不合理的概念。程序集不允许.NET Framework将对Silverlight的mscorlib的引用视为对桌面版本的引用。这是有效的,因为Silverlight的mscorlib被设计为.NET Framework版本的子集(对于特定的版本组合)。

    虽然这听起来像是弥合所有差异的银弹,但实际上并非如此。随着时间的推移,不同平台选择不同的装配因子。以ICommand为例。它在.NET 4和Silverlight 4中可用。但是,在WPF中,它在PresentationCore.dll中实现,而Silverlight将它放在System.Windows.dll中。要了解PCL在针对.NET 4和Silverlight 4时没有暴露ICommand的原因,让我们看看如果PCL暴露它会发生什么。

    在PCL中,我们必须将ICommnad放入某个程序集中。我们可以选择使用Silverlight程序集或完整框架程序集。无论我们选择哪一个,该类型都不会在另一个平台上解析,因为PresenationCore.dll仅存在于.NET 4中,System.Windows.dll仅存在于Silverlight 4中。

    我们通过允许System.Windows.dll中的ICommand引用在完整框架上成功解决了这个问题。我们是怎么做到的?答案是类型转发。类型转发允许程序集说"我定义类型Foo"。当CLR尝试从该程序集加载类型Foo时,程序集实际上说" no,no - Foo类型实际上是在另一个程序集Bar"中定义的。换句话说,程序集Foo包含类似Bar的版本类型的指针。我们将这些指针称为转发条目。

    这个概念允许我们通过将System.Windows.dll添加到包含实际实现的类型转发的完整框架来解决ICommand不匹配问题。 PCL现在为您提供System.Windows.dll中的ICommand,并且可以确保类型加载请求在.NET Framework和Silverlight上都能成功。但是,这需要至少针对.NET Framework 4.5,因为之前的版本没有类型转发。

    对于应该公开的所有API,我们并未与平台所有者合作缩小差距。我们基本上有两种策略:

    1. 我们要求平台所有者添加缺少的API或键入转发
    2. 我们以带外方式发布便携式实现。例如AsyncHttpClient
    3. 然而,"只是"将它添加到PCL并不起作用。

      编辑:如果您错过了PCL中的某项功能,则可以随时取消阻止。我们的测试人员丹尼尔written a blog post展示了一些您可以使用的技术。

答案 1 :(得分:4)

NO。 STOP。

好的,因为那不是你想听到的,继续自担风险。 :)当然不支持IANAL,因此我不知道许可协议是否允许它。

听起来您现有解决方案的主要问题是您无法选择要添加到便携式配置文件的单个API。为此,您可以在现有的引用程序集上使用ildasm,然后添加所需的API(可能通过从另一个引用程序集上运行ildasm的结果中复制它们),然后使用ilasm创建自己的引用版本带有这些附加API的程序集。

您需要延迟签名和/或禁用强名称密钥验证,以便您按照这种方式修改程序集的密钥。

另一种选择是使用类型转发,如我的回答here中所述。在这种情况下,您最终会将主代码按原样共享,并依赖于每个平台不同的DLL。