Migrate Your Windows 8.x App to .NET Native

.NET Native provides static compilation of apps in the Microsoft Store or on the developer's computer. This differs from the dynamic compilation performed for Windows 8.x apps (also previously called Microsoft Store apps) by the just-in-time (JIT) compiler or the Native Image Generator (Ngen.exe) on the device. Despite the differences, .NET Native tries to maintain compatibility with .NET for Windows 8.x apps. For the most part, things that work on the .NET for Windows 8.x apps also work with .NET Native. However, in some cases, you may encounter behavioral changes. This document discusses these differences between the standard .NET for Windows 8.x apps and .NET Native in the following areas:

General runtime differences

  • Exceptions, such as TypeLoadException, that are thrown by the JIT compiler when an app runs on the common language runtime (CLR) generally result in compile-time errors when processed by .NET Native.

  • Don't call the GC.WaitForPendingFinalizers method from an app's UI thread. This can result in a deadlock on .NET Native.

  • Don't rely on static class constructor invocation ordering. In .NET Native, the invocation order is different from the order on the standard runtime. (Even with the standard runtime, you shouldn't rely on the order of execution of static class constructors.)

  • Infinite looping without making a call (for example, while(true);) on any thread may bring the app to a halt. Similarly, large or infinite waits may bring the app to a halt.

  • Certain generic initialization cycles don't throw exceptions in .NET Native. For example, the following code throws a TypeLoadException exception on the standard CLR. In .NET Native, it doesn't.

    using System;
    
    struct N<T> {}
    struct X { N<X> x; }
    
    public class Example
    {
       public static void Main()
       {
          N<int> n = new N<int>();
          X x = new X();
       }
    }
    
  • In some cases, .NET Native provides different implementations of .NET Framework class libraries. An object returned from a method will always implement the members of the returned type. However, since its backing implementation is different, you may not be able to cast it to the same set of types as you could on other .NET Framework platforms. For example, in some cases, you may not be able to cast the IEnumerable<T> interface object returned by methods such as TypeInfo.DeclaredMembers or TypeInfo.DeclaredProperties to T[].

  • The WinInet cache isn't enabled by default on .NET for Windows 8.x apps, but it is on .NET Native. This improves performance but has working set implications. No developer action is necessary.

Dynamic programming differences

.NET Native statically links in code from .NET Framework to make the code app-local for maximum performance. However, binary sizes have to remain small, so the entire .NET Framework can't be brought in. The .NET Native compiler resolves this limitation by using a dependency reducer that removes references to unused code. However, .NET Native might not maintain or generate some type information and code when that information can't be inferred statically at compile time, but instead is retrieved dynamically at runtime.

.NET Native does enable reflection and dynamic programming. However, not all types can be marked for reflection, because this would make the generated code size too large (especially because reflecting on public APIs in .NET Framework is supported). The .NET Native compiler makes smart choices about which types should support reflection, and it keeps the metadata and generates code only for those types.

For example, data binding requires an app to be able to map property names to functions. In .NET for Windows 8.x apps, the common language runtime automatically uses reflection to provide this capability for managed types and publicly available native types. In .NET Native, the compiler automatically includes metadata for types to which you bind data.

The .NET Native compiler can also handle commonly used generic types such as List<T> and Dictionary<TKey,TValue>, which work without requiring any hints or directives. The dynamic keyword is also supported within certain limits.

Note

You should test all dynamic code paths thoroughly when porting your app to .NET Native.

The default configuration for .NET Native is sufficient for most developers, but some developers might want to fine- tune their configurations by using a runtime directives (.rd.xml) file. In addition, in some cases, the .NET Native compiler is unable to determine which metadata must be available for reflection and relies on hints, particularly in the following cases:

  • Some constructs like Type.MakeGenericType and MethodInfo.MakeGenericMethod can't be determined statically.

  • Because the compiler can't determine the instantiations, a generic type that you want to reflect on has to be specified by runtime directives. This isn't just because all code must be included, but because reflection on generic types can form an infinite cycle (for example, when a generic method is invoked on a generic type).

Note

Runtime directives are defined in a runtime directives (.rd.xml) file. For general information about using this file, see Getting Started. For information about the runtime directives, see Runtime Directives (rd.xml) Configuration File Reference.

.NET Native also includes profiling tools that help the developer determine which types outside the default set should support reflection.

There are a number of other individual reflection-related differences in behavior between .NET for Windows 8.x apps and .NET Native.

In .NET Native:

  • Private reflection over types and members in the .NET Framework class library is not supported. You can, however, reflect over your own private types and members, as well as types and members in third-party libraries.

  • The ParameterInfo.HasDefaultValue property correctly returns false for a ParameterInfo object that represents a return value. In .NET for Windows 8.x apps, it returns true. Intermediate language (IL) doesn't support this directly, and interpretation is left to the language.

  • Public members on the RuntimeFieldHandle and RuntimeMethodHandle structures aren't supported. These types are supported only for LINQ, expression trees, and static array initialization.

  • RuntimeReflectionExtensions.GetRuntimeProperties and RuntimeReflectionExtensions.GetRuntimeEvents include hidden members in base classes and thus may be overridden without explicit overrides. This is also true of other RuntimeReflectionExtensions.GetRuntime* methods.

  • Type.MakeArrayType and Type.MakeByRefType don't fail when you try to create certain combinations (for example, an array of byref objects).

  • You can't use reflection to invoke members that have pointer parameters.

  • You can't use reflection to get or set a pointer field.

  • When the argument count is wrong and the type of one of the arguments is incorrect, .NET Native throws an ArgumentException instead of a TargetParameterCountException.

  • Binary serialization of exceptions is generally not supported. As a result, non-serializable objects can be added to the Exception.Data dictionary.

Unsupported scenarios and APIs

The following sections list unsupported scenarios and APIs for general development, interop, and technologies such as HTTPClient and Windows Communication Foundation (WCF):

General development differences

Value types

  • If you override the ValueType.Equals and ValueType.GetHashCode methods for a value type, don't call the base class implementations. In .NET for Windows 8.x apps, these methods rely on reflection. At compile time, .NET Native generates an implementation that doesn't rely on runtime reflection. This means that if you don't override these two methods, they will work as expected, because .NET Native generates the implementation at compile time. However, overriding these methods but calling the base class implementation results in an exception.

  • Value types larger than 1 megabyte aren't supported.

  • Value types can't have a parameterless constructor in .NET Native. (C# and Visual Basic prohibit parameterless constructors on value types. However, these can be created in IL.)

Arrays

  • Arrays with a lower bound other than zero aren't supported. Typically, these arrays are created by calling the Array.CreateInstance(Type, Int32[], Int32[]) overload.

  • Dynamic creation of multidimensional arrays isn't supported. Such arrays are typically created by calling an overload of the Array.CreateInstance method that includes a lengths parameter, or by calling the Type.MakeArrayType(Int32) method.

  • Multidimensional arrays that have four or more dimensions aren't supported; that is, their Array.Rank property value is four or greater. Use jagged arrays (an array of arrays) instead. For example, array[x,y,z] is invalid, but array[x][y][z] isn't.

  • Variance for multidimensional arrays isn't supported and causes an InvalidCastException exception at run time.

Generics

  • Infinite generic type expansion results in a compiler error. For example, this code fails to compile:

    class A<T> {}
    
    class B<T> : A<B<A<T>>>
    {}
    

Pointers

  • Arrays of pointers aren't supported.

  • You can't use reflection to get or set a pointer field.

Serialization

The KnownTypeAttribute(String) attribute isn't supported. Use the KnownTypeAttribute(Type) attribute instead.

Resources

The use of localized resources with the EventSource class isn't supported. The EventSourceAttribute.LocalizationResources property doesn't define localized resources.

Delegates

Delegate.BeginInvoke and Delegate.EndInvoke aren't supported.

Miscellaneous APIs

  • The TypeInfo.GUID property throws a PlatformNotSupportedException exception if a GuidAttribute attribute isn't applied to the type. The GUID is used primarily for COM support.

  • The DateTime.Parse method correctly parses strings that contain short dates in .NET Native. However, it doesn't maintain compatibility with certain changes in date and time parsing.

  • BigInteger.ToString ("E") is correctly rounded in .NET Native. In some versions of the CLR, the result string is truncated instead of rounded.

HttpClient differences

In .NET Native, the HttpClientHandler class internally uses WinINet (through the HttpBaseProtocolFilter class) instead of the WebRequest and WebResponse classes used in the standard .NET for Windows 8.x apps. WinINet doesn't support all the configuration options that the HttpClientHandler class supports. As a result:

  • Some of the capability properties on HttpClientHandler return false on .NET Native, whereas they return true in the standard .NET for Windows 8.x apps.

  • Some of the configuration property get accessors always return a fixed value on .NET Native that is different than the default configurable value in .NET for Windows 8.x apps.

Some additional behavior differences are covered in the following subsections.

Proxy

The HttpBaseProtocolFilter class doesn't support configuring or overriding the proxy on a per-request basis. This means that all requests on .NET Native use the system-configured proxy server or no proxy server, depending on the value of the HttpClientHandler.UseProxy property. In .NET for Windows 8.x apps, the proxy server is defined by the HttpClientHandler.Proxy property. On .NET Native, setting the HttpClientHandler.Proxy to a value other than null throws a PlatformNotSupportedException exception. The HttpClientHandler.SupportsProxy property returns false on .NET Native, whereas it returns true in the standard .NET Framework for Windows 8.x apps.

Automatic redirection

The HttpBaseProtocolFilter class doesn't allow the maximum number of automatic redirections to be configured. The value of the HttpClientHandler.MaxAutomaticRedirections property is 50 by default in the standard .NET for Windows 8.x apps and can be modified. On .NET Native, the value of this property is 10, and trying to modify it throws a PlatformNotSupportedException exception. The HttpClientHandler.SupportsRedirectConfiguration property returns false on .NET Native, whereas it returns true in .NET for Windows 8.x apps.

Automatic decompression

.NET for Windows 8.x apps allows you to set the HttpClientHandler.AutomaticDecompression property to Deflate, GZip, both Deflate and GZip, or None. .NET Native only supports Deflate together with GZip, or None. Trying to set the AutomaticDecompression property to either Deflate or GZip alone silently sets it to both Deflate and GZip.

Cookies

Cookie handling is performed simultaneously by HttpClient and WinINet. Cookies from the CookieContainer are combined with cookies in the WinINet cookie cache. Removing a cookie from CookieContainer prevents HttpClient from sending the cookie, but if the cookie was already seen by WinINet, and cookies weren't deleted by the user, WinINet sends it. It isn't possible to programmatically remove a cookie from WinINet by using the HttpClient, HttpClientHandler, or CookieContainer API. Setting the HttpClientHandler.UseCookies property to false causes only HttpClient to stop sending cookies; WinINet might still include its cookies in the request.

Credentials

In .NET for Windows 8.x apps, the HttpClientHandler.UseDefaultCredentials and HttpClientHandler.Credentials properties work independently. Additionally, the Credentials property accepts any object that implements the ICredentials interface. In .NET Native, setting the UseDefaultCredentials property to true causes the Credentials property to become null. In addition, the Credentials property can be set only to null, DefaultCredentials, or an object of type NetworkCredential. Assigning any other ICredentials object, the most popular of which is CredentialCache, to the Credentials property throws a PlatformNotSupportedException.

Other unsupported or unconfigurable features

In .NET Native:

Interop differences

Deprecated APIs

A number of infrequently used APIs for interoperability with managed code have been deprecated. When used with .NET Native, these APIs may throw a NotImplementedException or PlatformNotSupportedException exception, or result in a compiler error. In .NET for Windows 8.x apps, these APIs are marked as obsolete, although calling them generates a compiler warning rather than a compiler error.

Deprecated APIs for VARIANT marshaling include:

UnmanagedType.Struct is supported, but it throws an exception in some scenarios, such as when it is used with IDispatch or byref variants.

Deprecated APIs for IDispatch support include:

Deprecated APIs for classic COM events include:

Deprecated APIs in the System.Runtime.InteropServices.ICustomQueryInterface interface, which isn't supported in .NET Native, include:

Other unsupported interop features include:

Rarely used marshaling APIs:

Platform invoke and COM interop compatibility

Most platform invoke and COM interop scenarios are still supported in .NET Native. In particular, all interoperability with Windows Runtime (WinRT) APIs and all marshaling required for the Windows Runtime is supported. This includes marshaling support for:

However, .NET Native doesn't support the following:

Using reflection to invoke a platform invoke method isn't supported. You can work around this limitation by wrapping the method call in another method and using reflection to call the wrapper instead.

Other differences from .NET APIs for Windows 8.x apps

This section lists the remaining APIs that aren't supported in .NET Native. The largest set of the unsupported APIs is the Windows Communication Foundation (WCF) APIs.

DataAnnotations (System.ComponentModel.DataAnnotations)

The types in the System.ComponentModel.DataAnnotations and System.ComponentModel.DataAnnotations.Schema namespaces aren't supported in .NET Native. These include the following types that are present in .NET for Windows 8.x apps:

Visual Basic

Visual Basic isn't currently supported in .NET Native. The following types in the Microsoft.VisualBasic and Microsoft.VisualBasic.CompilerServices namespaces aren't available in .NET Native:

Reflection Context (System.Reflection.Context namespace)

The System.Reflection.Context.CustomReflectionContext class isn't supported in .NET Native.

RTC (System.Net.Http.Rtc)

The System.Net.Http.RtcRequestFactory class isn't supported in .NET Native.

Windows Communication Foundation (WCF) (System.ServiceModel.*)

The types in the System.ServiceModel.* namespaces aren't supported in .NET Native. These include the following types:

Differences in serializers

The following differences concern serialization and deserialization with the DataContractSerializer, DataContractJsonSerializer, and XmlSerializer classes:

Visual Studio differences

Exceptions and debugging

When you're running apps compiled by using .NET Native in the debugger, first-chance exceptions are enabled for the following exception types:

Building apps

Use the x86 build tools that are used by default by Visual Studio. We don't recommend using the AMD64 MSBuild tools, which are found in C:\Program Files (x86)\MSBuild\12.0\bin\amd64; these may create build problems.

Profilers

  • The Visual Studio CPU Profiler and XAML Memory Profiler don't display Just-My-Code correctly.

  • The XAML Memory Profiler doesn't accurately display managed heap data.

  • The CPU Profiler doesn't correctly identify modules, and displays prefixed function names.

Unit Test Library projects

Enabling .NET Native on a Unit Test Library for a Windows 8.x app project isn't supported and causes the project to fail to build.

See also