Getting Started with .NET Native
Whether you're writing a new UWP app or migrating an existing Windows 8.x app (previously also called a Microsoft Store app), you can follow the same set of procedures. To create a .NET Native app, follow these steps:
Develop a Universal Windows Platform (UWP) app, and test the debug builds of your app to ensure that it works properly.
Manually resolve missing metadata, and repeat step 3 until all issues are resolved.
Note
If you are migrating an existing Windows 8.x app to .NET Native, be sure to review Migrating Your Windows 8.x App to .NET Native.
Step 1: Develop and test debug builds of your UWP app
Whether you are developing a new app or migrating an existing one, you follow the same process as for any Windows app.
Create a new UWP project in Visual Studio by using the Universal Windows app template for Visual C# or Visual Basic. By default, all UWP applications target the CoreCLR and their release builds are compiled by using the .NET Native tool chain.
Note that there are some known compatibility issues between compiling UWP app projects with the .NET Native tool chain and without it. Refer to the migration guide for more information.
You can now write C# or Visual Basic code against the .NET Native surface area that runs on the local system (or in the simulator).
Important
As you develop your app, note any use of serialization or reflection in your code.
By default, debug builds are JIT-compiled to enable rapid F5 deployment, while release builds are compiled by using the .NET Native pre-compilation technology. This means you should build and test the debug builds of your app to ensure that they work normally before compiling them with the .NET Native tool chain.
Step 2: Handle additional reflection and serialization usage
A runtime directives file, Default.rd.xml, is automatically added to your project when you create it. If you develop in C#, it is found in your project's Properties folder. If you develop in Visual Basic, it is found in your project's My Project folder.
Note
For an overview of the .NET Native compilation process that provides background on why a runtime directives file is needed, see .NET Native and Compilation.
The runtime directives file is used to define the metadata that your app needs at run time. In some cases, the default version of the file may be adequate. However, some code that relies on serialization or reflection may require additional entries in the runtime directives file.
Serialization
There are two categories of serializers, and both may require additional entries in the runtime directives file:
Non-reflection based serializers. The serializers found in the .NET Framework class library, such as the DataContractSerializer, DataContractJsonSerializer, and XmlSerializer classes, do not rely on reflection. However, they do require that code be generated based on the object to be serialized or deserialized. For more information, see the "Microsoft Serializers" section in Serialization and Metadata.
Third-party serializers. Third-party serialization libraries, the most common of which is the Newtonsoft JSON serializer, are generally reflection-based and require entries in the *.rd.xml file to support object serialization and deserialization. For more information, see the "Third-Party Serializers" section in Serialization and Metadata.
Methods that rely on reflection
In some cases, the use of reflection in code is not obvious. Some common APIs or programming patterns aren't considered part of the reflection API but rely on reflection to execute successfully. This includes the following type instantiation and method construction methods:
The Type.MakeGenericType method
The Array.CreateInstance and Type.MakeArrayType methods
The MethodInfo.MakeGenericMethod method.
For more information, see APIs That Rely on Reflection.
Note
Type names used in runtime directives files must be fully qualified. For example, the file must specify "System.String" instead of "String".
Step 3: Deploy and test the release builds of your app
After you've updated the runtime directives file, you can rebuild and deploy release builds of your app. .NET Native binaries are placed in the ILC.out subdirectory of the directory specified in the Build output path text box of the project's Properties dialog box, Compile tab. Binaries that aren't in this folder haven't been compiled with .NET Native. Test your app thoroughly, and test all scenarios, including failure scenarios, on each of its target platforms.
If your app doesn't work properly (particularly in cases where it throws MissingMetadataException or MissingInteropDataException exceptions at run time), follow the instructions in the next section, Step 4: Manually resolve missing metadata. Enabling first-chance exceptions may help you find these bugs.
When you've tested and debugged the debug builds of your app and you're confident that you've eliminated the MissingMetadataException and MissingInteropDataException exceptions, you should test your app as an optimized .NET Native app. To do this, change your active project configuration from Debug to Release.
Step 4: Manually resolve missing metadata
The most common failure you'll encounter with .NET Native that you don't encounter on the desktop is a runtime MissingMetadataException, MissingInteropDataException, or MissingRuntimeArtifactException exception. In some cases, the absence of metadata can manifest itself in unpredictable behavior or even in app failures. This section discusses how you can debug and resolve these exceptions by adding directives to the runtime directives file. For information about the format of runtime directives, see Runtime Directives (rd.xml) Configuration File Reference. After you've added runtime directives, you should deploy and test your app again and resolve any new MissingMetadataException, MissingInteropDataException, and MissingRuntimeArtifactException exceptions until you encounter no more exceptions.
Tip
Specify the runtime directives at a high level to enable your app to be resilient to code changes. We recommend adding runtime directives at the namespace and type levels rather than the member level. Note that there may be a tradeoff between resiliency and larger binaries with longer compile times.
When addressing a missing metadata exception, consider these issues:
What was the app trying to do before the exception?
- For example, was it data binding, serializing or deserializing data, or directly using the reflection API?
Is this an isolated case, or do you believe you'll encounter the same issue for other types?
- For example, a MissingMetadataException exception is thrown when serializing a type in the app's object model. If you know other types that will be serialized, you can add runtime directives for those types (or for their containing namespaces, depending on how well the code is organized) at the same time.
Can you rewrite the code so it doesn't use reflection?
For example, does the code use the
dynamic
keyword when you know what type to expect?Does the code call a method that depends on reflection when some better alternative is available?
Note
For additional information about handling problems that stem from differences in reflection and the availability of metadata in desktop apps and .NET Native, see APIs That Rely on Reflection.
For some specific examples of handling exceptions and other issues that occur when testing your app, see: