.NET Source Code Integration
With the recent open sourcing of parts of .NET, we want to bring the best pieces of .NET to Mono, and contribute the cross platform components of Mono to the .NET efforts.
This document describes the strategies that we will employ.
We are tracking the most recent development at GitHub task.
Microsoft is open sourcing .NET in two ways:
.NET Core: a re-imagined version of .NET that is suitable to be deployed alongside web apps and places a strong focus on a new set of assemblies and APIs based on the PCL 2.0 profile. This is a full open source project, with Microsoft taking contributions and developing in the open.
Parts of the .NET Framework: these are parts of the .NET framework as it ships on Windows, and the API that Mono has been implementing over the years. The version published here is a snapshot of the .NET Framework source code. While Microsoft is publishing the source code, they are not actively developing this tree in the open, nor are they taking patches.
This section lists a set of issues to keep in mind while bringing the Microsoft .NET source code into Mono, and what we need to keep in mind as we upgrade the code.
The list of issues below identifies the constraints that we have to bring .NET code into Mono.
Mono’s Platform Specific Code
In numerous instances, Mono contains platform specific code which is currently missing from .NET. There are a wide variety of features like this. Some examples include:
System.Environmentclass which provides a platform-specific set of locations for applications to lookup certain well known file system locations.
Registryclass which provides an abstraction that maps to Windows APIs or a file backed implementation on Unix.
Mono’s Classes with Tight Runtime Integration
Some of the APIs in the .NET framework are bound to have tight dependencies on their runtime implementation. Just like Mono’s implementation does.
There are cases where we might want to take on the extra challenge of doing the runtime integration work (for example, switching from our barely maintained decimal support, to Microsoft’s version would be a win). In other cases, the amount of work is not worth doing the changes, like the support for
Mono ships a mobile API profile which is designed to be a lightweight API profile and is used in mobile devices, game consoles and the Mono for Unreal Engine project.
The Mobile Profile basically removes some of the heavier .NET dependencies from the system. It mostly deals with removing
System.Configuration dependencies from our class libraries.
In the long term, we want to adopt a .NET-Core like approach, where we have a thin layer of platform/VM specific APIs, and we allow users to use Mono in the same way that .NET core can be used, without the large libraries/profiles.
Mono Classes are Linker Friendly
Some of the class libraries in Mono have been designed to keep the result linker-friendly, an important piece of functionality required by our Android and iOS deployments.
This comes in the form of removing some runtime weak association with a strong association, or teaching our linker and class libraries of connections between certain classes and their requirements. Many of those links would likely exist in .NET as well, but we would need to ensure that we do not regress when incorporating code here.
Base Class Libraries Bootstrapping
The bootstrapping of the core libraries is not exactly fun. Microsoft has cyclic dependencies on various assembly groups. For example
System.Core are build referencing each other’s types. Another cluster includes the
Mono currently has a multi-stage build process to create these libraries that have cyclic dependencies. Bringing new code from Microsoft is possible, but for each class that we bring, we might need to adjust the cyclic dependency build.
The distribution does not include the resouces for some of the code. These manifest themselves as references to a class called “SR”.
We are going to need to autogenerate those.
Limited Man Power
We have limited manpower, so when bringing code from .NET, we need to pick our battles.
The pieces of Mono that have been used the most are of higher quality than the pieces that have not been used very much, or have not been maintained for a long time.
It is best to focus our efforts on the high-value targets in the .NET class libraries than to bring things that are known to work well in Mono and are well tested.
Some .NET Code might not be complete
Some of the .NET code that we are getting might not be complete, it might be missing resources, strings, build files and might not be trivially buildable. So it is important that when you submit a pull request, the patch builds completely.
Performance/Memory side effects
This is mostly a non-issue, but we might find cases where Mono class libraries have been fine-tuned for use in the Mono runtime and bringing the equivalent code from Microsoft might regress our performance or make us allocate more memory.
Some items to watch out for:
Code Access Security checks: these are likely present in .NET, and they do not exist in Mono. They are relatively expensive to perform, and Mono does not even implement it correctly. So we would need to ifdef out all the CAS-related support when importing the code.
Object Disposed: Mono did not always faithfully implement the object disposed pattern. This is a pattern where objects that implement
ObjectDisposedExceptionwhenever an object’s Dispose method was called, but a member of that instance was called. This requires extra testing that Mono currently does not have in a few places. It might not matter, but we might want to watch out for this.
Enumeration Validation: .NET tends to validate the values of enumeration passed to its functions. Mono does not do this, so we might have a performance impact when we bring some of the code.
Code Access Security Checks is probably the one that we should be worried about, as it is completely useless in Mono.
The Microsoft source code contains many different kinds of compiler defines that are used for conditional compilation. Whenever we are importing code from Microsoft, we need to perfom an audit and determine which features we want to take.
In general, we will be integrating code from the Reference Source release, as this contains the API that is closest to Mono.
We are tracking the task assignements on Trello.
Later on, when we implement Mono Core, we will instead contribute the VM/OS specific bits to .NET Core.
We need to come up with an integration plan that will maximize the benefits to Mono and our users with the least amount of engineering effort. While in an ideal world we could bring some 80-90% of the code over, this is a major effort with many risks involved. We will prioritize the work to focus on what would give us the most benefits upfront for the Mono community, and leave the more complex/harder difficult bits for later.
Giving Mono a big boost from the start
When bringing code to Mono, we can bring code in the following ways:
- Entire assemblies
- Entire classes
- Blended Work
- Individual members
We should port entire assemblies when our assembly is known to be very buggy, in bad shape, or just completely broken.
Immediate candidates for this include:
- WCF - almost immediately
- System.Web - almost immediately
Medium term candidates include:
- System.Configuration - possible, but requires careful examination
Long term candidates include:
- XML stack
We would port entire classes when a class or a family of classes is known in Mono to be buggy, poorly maintained or a source of problems.
Candidates for this include:
These are libraries of high quality code and whose Mono counterpart might be known to have limitations, bugs or problems. But yet, the Microsoft implementation contains dependencies on native libraries that do not exist across all platforms.
- HTTP client stack
… this was done by Pull Request #4893 and similar PRs.
System.Data.*- Microsoft’s impementation has many dependencies on native code that need to be refactored to be cross platform.
We will find some of this code in a few places. There are places in Mono that while pretty good overall, might have some known bugs and limitations. The binding functionality in System.Reflection is an example of a method that works, but might have bugs and mistakes on the edges.
Porting and Regressions
Whenever we bring .NET code to replace Mono code, there might be cases where we introduce a regression of some kind: functionality, performance or we bring in a behavior that is incompatible with the idioms that Mono users have used for a long time.
In general, when porting code to Mono, we should make sure that Mono’s test suite continues to pass, and that no regressions are introduced. If a regression is introduced, we need to file a bug and track this particular problem.
Very popular, mostly bug-free APIs: skip
Mono’s core is in very good shape, and there will be very little value in bringing the .NET implementation to Mono. It would consume valuable engineering time to replace good code with another piece of good code, while also paying the price of potential regressions.
Empowering Third Parties
There are certain pieces of code that are going to be difficult to do, but if we do them, we can assist third parties that do not know as much about Mono’s internals or our build process to contribute.
Dealing with System.Configuration
In general, the idiom that we will use when porting code that involves
System.Configuration that we want to support both in the full profile mode and the Mobile Profile mode will be roughly:
- Comment out the public class that subclasses
- Keep the
SettingsSectionInternalclass around, since so much code depends on it.
- ifdef-out the constructor that depends on
System.Configurationfrom this class that uses
System.Configuration, and replace it instead with hardcoded values that we obtain from running the code in .NET and obtaining the default values.
- Add the
partialclass modifier to the
- Provide a constructor in the partial class in Mono to setup the default values.
- Track each setting, so that we can later decide if we want to provide a C# API to change these values.
Source Code Style
When making changes, try to keep the style of the original project. If you are making changes to .NET’s code, use their style. When making changes to Mono, use our style.
We believe that we can mostly make few changes to the upstream code and mostly use either
partial classes and split a few things to achieve portability.
.NET Core and Mono
We want to contribute some of the cross platform code from Mono, as well as chunks that we port from the .NET Framework Reference Source to the .NET Core effort.
We will update this page with information as the porting process at Microsoft evolves and we can volunteer some of our/their code back to the .NET Core effort.