-
Notifications
You must be signed in to change notification settings - Fork 214
Understanding multi targetting and NetStandard
Consider the following programming metaphor - NetStandard is an interface and platforms such as net45, monoandroid8.0, netcoreapp are implementations of this interface. This means that the platform (e.g. net45) can have more public APIs than netstandard.
Our libraries are built against multiple frameworks, at the time of writing, these are:
- netstandard1.3;
- net45;
- uap10.0;
- MonoAndroid8.1;
- Xamarin.iOS10;
- netcoreapp1.0
When we build the package, msbuild runs a foreach loop on the platforms above. It builds a distinct DLL for each of them. If you have a look at a nupkg (just rename it to zip and look inside the archive), you'll see this.
It's actually NuGet that figures out which DLL is needed for a specific application. You can use this tool to simulate NuGet.
The compatiblity matrix, i.e. which platform implements which netstandard is outlined here. Consider that MSAL library is built against the frameworks described above and I take a dependency on MSAL from a library built against....
Library that depends on MSAL | NuGet uses MSAL built for... |
---|---|
net45 | |
net46 | |
netstandard1.1 | |
netstandard2.0 | |
netcore2.0 | |
Xamarin.iOS 10 | |
Xamarin.Mac 3.0 | |
PCL | |
Windows 8.0 |
Library that depends on MSAL | NuGet uses MSAL built for... |
---|---|
net45 | net45 |
net46 | net45 |
netstandard1.1 | Error |
netstandard2.0 | netstandard1.3 |
netcore2.0 | netcore1.0 |
Xamarin.iOS 10 | Xamarin.iOS 10 |
Xamarin.Mac 3.0 | netstandard1.3 |
PCL | Error |
Windows 8.0 | Error |
Note that all of the platforms are backwards compatible, like concentric circles, e.g,:
netstandard1.3 extends netstandard1.2 extends netstandard1.1 etc. net461 extends net46 extends net45 etc.
You might be wondering why would anyone build an app / library against netstandard instead of net45, netcore etc? There seem to be 2 scenarios for this:
- Libraries like Newtonsoft.Json want to reach as many developers as possible, so they are built against netstandard1.0, which means they are compatible with everything
- Xamarin.XForm apps propose a code sharing scheme with a common DLL built against netstandard and entry-point DLLs built against iOS, UWP and Android. So for example I can deserialize some json in the common DLL and store in a platform specific store in UWP, iOS and Android.
Since netstandard is an interface, it cannot function on its own, i.e. all the methods in all the classes in netstandard.dll do nothing or throw exceptions. When an application, for example net45, takes a dependency on a netstandard library, the developer codes against these empty / exception throwing methods. But at runtime, these methods are typeforwarded to an actual implementation.
For example you might write Environment.GetEnvironmentVariable() in your netstandard library, and this will be typeforwarded to the actual implementation of getting env variables in .netcore, iOS, android, uwp etc.
When we develop multi-framework code, like ADAL and MSAL, we have 2 mechanisms of writing platform specific code:
- We use precompilation flags, e.g. #if ANDROID #if iOS etc. Similarly we exclude entire files / folders based on platform in the csproj file
- We define common interfaces like IWebUi and provide platform specific implementations
The structure is similar to the diagram below - a common.dll has all the common code and actual libraries have the platform specific code:
|Common.DLL (netstandard2.0)| ---> |MSAL|
|UWP.DLL|, |iOS.DLL|, |Android.DLL| --> |Common.DLL|
At build time, Visual Studio will tell you that you can use any API from the netstandard1.3 MSAL. This is because Common.dll is built against netstandard2.0 and MSAL is built against a bunch of stuff including netstandard1.3.
At run time, .NET will actually use the UWP (or iOS or Android) MSAL library, depending on what application you run.
As such, if in MSAL you define a piece of public API as:
#if NETSTANDARD1_3
public void Foo() {...}
#endif
You'll be able to take a dependency on Foo from the XForms app, but at runtime you'll get a method not implemented exception.
So a safer way to write code in libraries like MSAL is:
public void Foo()
{
#if NETSTANDARD1_3
throw new PlatformNotSupportedException();
#endif
#elif WINDOWS_APP
// uwp implementation or exception
#else
// other implementations ...
#endif
}
This way the public entry point is available in XForms at build time and will be replaced by the proper implementation at runtime.
- Home
- Why use ADAL.NET?
- Register your app with AAD
- AuthenticationContext
- Acquiring Tokens
- Calling a protected API
- Acquiring a token interactively
- Acquiring tokens silently
- Using Device Code Flow
- Using Embedded Webview and System Browser in ADAL.NET and MSAL.NET
- With no user
- In the name of a user
- on behalf of (Service to service calls)
- by authorization code (Web Apps)
- Use async controller actions
- Exception types
- using Broker on iOS and Android
- Logging
- Token Cache serialization
- User management
- Using ADAL with a proxy
- Authentication context in multi-tenant scenarios
- Troubleshooting MFA in a WebApp or Web API
- Provide your own HttpClient
- iOS Keychain Access