ApiInformation 是否不尊重应用程序目标版本 [英] Does ApiInformation not respect the app target version

查看:13
本文介绍了ApiInformation 是否不尊重应用程序目标版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象以下设置:

UWP 库:
最小版本:10240
目标版本:16299

UWP Library:
MinVersion: 10240
TargetVersion: 16299

此库在运行时检查 UniversalApiContract 版本 5 是否存在.
如果是,它将使用新的 NavigationView 控件.

This library checks at runtime if the UniversalApiContract Version 5 is present.
If yes, it will use the new NavigationView control that.

UWP 应用:
最小版本:10240
目标版本:10240

UWP App:
MinVersion: 10240
TargetVersion: 10240

此应用引用了 UWP 库项目.
当我在安装了 Windows 10 版本 16299 的计算机上运行此应用程序时,会发生以下情况:
UWP 库在运行时检查 api 合同.因为我有最新版本的 Windows 10,所以它存在.
然后它尝试创建 NavigationView 控件,并且我收到一个 TypeLoadException 和消息 Could not find Windows Runtime type 'Windows.UI.Xaml.Controls.NavigationView'.

This app references the UWP Library project.
When I run this app on my Computer, which has Windows 10 Version 16299 installed, the following happens:
The UWP Library checks at runtime for the api contract. As I have the newest version of Windows 10, yes it is present.
Then it tries to create the NavigationView control, and I get a TypeLoadException with the message Could not find Windows Runtime type 'Windows.UI.Xaml.Controls.NavigationView'.

什么?为什么?ApiInformation 类是否不尊重正在运行的应用程序的目标版本?

What? Why? Does the ApiInformation class not respect the target version of the running app?

我可以做些什么来解决这个问题?
我认为 ApiInformation 是避免这种情况的方法,但显然不是?!

What can I do to work around this issue?
I thought ApiInformation was the way to avoid this, but apparently not?!

这是一个展示错误的 Github 存储库:
https://github.com/haefele/ApiInformationTargetVersionFail

Here is a Github repository showcasing the error:
https://github.com/haefele/ApiInformationTargetVersionFail

如果您将 MyApp 项目的目标版本设置为 16299,则一切正常.

If you set the target-version of the MyApp project to 16299, everything works fine.

推荐答案

[Edit May 29 2018]

ApiInformation<的方法/code> type 基于磁盘上 WinRT 元数据的简单查找——如果元数据存在,则调用成功.这使点亮"成为可能.新平台上的新功能,而无需增加最低版本.但重要的是,ApiInformation 对 API 的实现一无所知:有时它可能会丢失(例如在操作系统的早期Insider"构建中),有时它可能会丢失由于怪癖",可能无法正常工作(见下面的例子).由于 JIT 和 .NET Native 工具链的工作方式,.NET 也有不同的世界观.

The methods of the ApiInformation type are based on a trivial lookup of the WinRT metadata on disk -- if the metadata is there, the call succeeds. This enables "light-up" of new features on new platforms without increasing your minimum version. What's important though is that ApiInformation knows nothing about the implementation of the API: sometimes it might be missing (eg on early "Insider" builds of the OS) and sometimes it might not work due to "quirks" (see example below). .NET also had a different view of the world due to the way the JIT and .NET Native toolchains work.

这可能会导致问题...

This can cause problems...

.NET 应用程序使用Union WinMD"概念.这是 Windows SDK 中存在的所有已知类型(包括扩展 SDK)的联合,对应于应用的 MaxVersionTested 设置.如果您在下层平台上运行应用程序,ApiInformation 会告诉您 API 不存在,但 .NET 仍然可以基于 Union WinMD 的 JIT 方法并执行一些反射任务.如果您真的尝试调用 API(因为您忘记了 ApiInformation 检查),您将在运行时收到 MissingMethodException,因为该 API 并不真正存在.

.NET apps use a concept of a "Union WinMD" which is the union of all known types (including Extension SDKs) that exist in the Windows SDK that corresponds to the MaxVersionTested setting of the app. If you're running the app on a down-level platform, ApiInformation will tell you the API doesn't exist, but .NET can still JIT methods based on the Union WinMD and perform some reflection tasks. If you actually try and call the API (because you forgot the ApiInformation check) you will get a MissingMethodException at runtime because the API doesn't really exist.

如果您在较低版本的应用程序中包含较高版本的 .NET 库,然后尝试在较高版本的操作系统版本上运行它,则会出现不同的问题.在这种情况下,ApiInformation 将成功,因为该类型存在于系统元数据中,但 .NET 将在运行时抛出一个 MissingMethodException,因为该类型在系统元数据中不存在用于构建应用程序的 Union WinMD.

A different problem can occur if you include a higher-versioned .NET library inside a lower-versioned app and then try to run it on the higher-versioned build of the OS. In this case, ApiInformation will succeed because the type exists in the system metadata, but .NET will throw a MissingMethodException at runtime because the type didn't exist in the Union WinMD used to build the app.

重要提示:这是基于应用的目标版本(又名MaxVersionTested),而不是库!

Important: This is based on the Target Version (aka MaxVersionTested) of the app, not the library!

如果您构建应用程序的发布版本,您甚至会看到 .NET Native 工具链在输出"窗口中显示如下警告:

If you build a release version of the app, you will even see the .NET Native toolchain display a warning such as this in the Output window:

warning : ILTransform : warning ILT0003: 由于缺少方法SomeNewType.NewMethod()",方法Foo.Bar()"将始终抛出异常.可能缺少一个程序集.

除了使用与库相同的目标版本构建应用程序(以便它可以解析所有引用)之外,没有其他好的方法可以解决此问题.

There is no good way around this, other than to build your application with the same target version as the library (so that it can resolve all the references).

您可能会遇到的另一个问题是当您的应用(或它使用的库)使用来自未来"的 API 时在列为应用程序的 MaxVersionTested 的操作系统中不存在.许多 API 可以使用,但有些 API 无法使用,因为与应用运行的模拟旧模式不兼容.

Another problem you can encounter is when your app (or a library it consumes) use APIs "from the future" that didn't exist in the OS listed as the MaxVersionTested of the app. Many of the APIs will work, but some don't due to incompatibilities with the simulated legacy mode the app is running in.

想象一下,X 版操作系统仅支持黑白应用,其中背景始终为白色,文本、图形等始终为黑色.应用程序是使用这种基本假设构建的 - 包括具有每像素仅分配 1 位的图形缓冲区,或者从不担心文本不可见,因为背景和前景色是相同的.一切都很好.

Imagine that version X of the OS only supported black-and-white apps, where the background is always white and text, graphics, etc. are always black. Apps are built using this underlying assumption - including having graphics buffers that allocate only 1-bit-per-pixel, or never worrying about text being invisible because the background and foreground colours are the same. Everything is fine.

现在操作系统的 Y 版出来了,它支持彩色图形(例如,每像素 8 位).伴随着这个新功能而来的是一对新的 API,SetForegroundColor()SetBackgroundColor(),让你可以选择你想要的任何颜色.任何询问 ApiInformation 这两个新 API 是否存在的应用(或库)都将在操作系统的版本 Y 上成功,以及任何具有 MaxVersionTested 的应用> 至少 Y 可以成功使用它们.但出于兼容性原因,它们无法在仅针对版本 X 的应用程序中工作,因为它不知道颜色存在.它们的图形缓冲区大小错误,它们的文本可能变得不可见,等等.因此,在面向 X 的应用程序中使用 API 时,这些 API 将在运行时失败,即使操作系统具有支持它们的元数据(和实现).

Now version Y of the OS comes out, and it supports colour graphics (say, 8-bits-per-pixel). Along with this new feature comes a pair of new APIs, SetForegroundColor() and SetBackgroundColor() that let you choose whatever colour you want. Any app (or library) that asks ApiInformation whether these two new APIs exists will succeed on version Y of the OS, and any app with a MaxVersionTested of at least Y can use them successfully. But for compatibility reasons they cannot work in an app that only targeted version X because it has no idea colours exist. Their graphics buffers are the wrong size, their text might become invisible, and so on. So the APIs will fail at runtime when used in an X-targeted app, even though the OS has the metadata (and the implementation) to support them.

不幸的是,今天没有很好的方法来处理这种情况,但这种情况相对较少.它等效于使用 LoadLibrary/GetProcAddress(或使用反射的旧版 .NET 库)来发现来自未来"的 API 的旧版 Win32 库.

Unfortunately there is no good way of handling this situation today, but it is a relatively rare occurrence. It is equivalent to a legacy Win32 library using LoadLibrary / GetProcAddress (or a legacy .NET library using reflection) to discover APIs that are "from the future."

这篇关于ApiInformation 是否不尊重应用程序目标版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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