Bug 1528 - TypeInitializationException when using classes depending on System.Configuration.ConfigurationManager in packaged MonoMac application
Summary: TypeInitializationException when using classes depending on System.Configurat...
Alias: None
Product: MonoMac
Classification: Desktop
Component: Bindings ()
Version: unspecified
Hardware: Macintosh Mac OS
: Normal blocker
Target Milestone: ---
Assignee: Sebastien Pouliot
Depends on:
Reported: 2011-10-17 06:52 UTC by krt
Modified: 2012-12-12 20:42 UTC (History)
5 users (show)

Is this bug a regression?: ---
Last known good build:

Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.

Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:

Description krt 2011-10-17 06:52:43 UTC
MonoMac linker removes default constructor for System.Configuration.ExeConfigurationHost type.

E.g. WebRequest request = WebRequest.Create("http://google.com"); crashes with such stack trace:

[ERROR] FATAL UNHANDLED EXCEPTION: System.TypeInitializationException: An exception was thrown by the type initializer for System.Net.WebRequest ---> System.Configuration.ConfigurationErrorsException: Error Initializing the configuration system. ---> System.MissingMethodException: Default constructor not found for type System.Configuration.ExeConfigurationHost.
  at System.Activator.CreateInstance (System.Type type, Boolean nonPublic) [0x00000] in <filename unknown>:0 
  at System.Activator.CreateInstance (System.Type type) [0x00000] in <filename unknown>:0 
  at System.Configuration.InternalConfigurationSystem.Init (System.Type typeConfigHost, System.Object[] hostInitParams) [0x00000] in <filename unknown>:0 
  at System.Configuration.InternalConfigurationFactory.Create (System.Type typeConfigHost, System.Object[] hostInitConfigurationParams) [0x00000] in <filename unknown>:0 
  at System.Configuration.ConfigurationManager.OpenExeConfigurationInternal (ConfigurationUserLevel userLevel, System.Reflection.Assembly calling_assembly, System.String exePath) [0x00000] in <filename unknown>:0 
  at System.Configuration.ClientConfigurationSystem.get_Configuration () [0x00000] in <filename unknown>:0 
  --- End of inner exception stack trace ---
  at System.Configuration.ClientConfigurationSystem.get_Configuration () [0x00000] in <filename unknown>:0 
  at System.Configuration.ClientConfigurationSystem.System.Configuration.Internal.IInternalConfigSystem.GetSection (System.String configKey) [0x00000] in <filename unknown>:0 
  at System.Configuration.ConfigurationManager.GetSection (System.String sectionName) [0x00000] in <filename unknown>:0 
  at System.Net.WebRequest..cctor () [0x00000] in <filename unknown>:0
Comment 1 Miguel de Icaza [MSFT] 2011-10-22 21:12:00 UTC
Sebastien, since you have been looking at the linker, would you mind looking at this MMP linker issue?
Comment 2 Sebastien Pouliot 2011-10-23 13:54:04 UTC
Not sure how (even if) this worked before, if it was then this could be related to changes in the 4.0 profile. 

Anyway the machine.config (that gets copied into the .app) references a lot of types and WebRequest calls into System.Configuration to instantiate them. Fixing this specific case brings another, which brings another... and so on (got 5 fixes and still crashing for missing types/.ctor).

Since this is all "string" based this can't be statically detected so we need to either:

a) update the linker to bring all this extra, potentially used, code (like I started to do). Sadly this means larger app size for stuff that's rarely used - i.e. everyone pays for some advanced features almost no one uses;

b) process the machine.config in the linker (it will need to be available at link time) and mark the types required. Much more complex and if we don't have a 'smaller/smarter' machine.config then we'll end up just like 'a';

c) use a customized, minimal machine.config that does not bring anything extra when linking is enabled. That way applications with extra requirements can still use the features and will work (without changes since they won't be linked). That's the easy way where (only) extra power comes at the price of larger app size. 

d) Allow users (MD UI) to provide their own alternate 'machine.config' if their apps requires it, defaulting to 'c' otherwise. This requires 'b' to work too but it's the ultimate solution (i.e. allows linking even with extra features).

e) Catch TypeLoadException where System.Configuration is used (e.g. WebRequest). Not sure if this affects compatibility with MS implementation - but it will hide the error (which can be good or bad) from the developers/users.

'c' and 'e' are much alike right now (unless we want to do 'd' later). 'c' requires an update to the MonoMac addin, while 'e' requires an update to Mono. FWIW I don't think 'a' (fixing mmp to include everything) is the right solution (and also requires a MonoMac adding update).

note: this does not affect the MOBILE profile since it's not using System.Configuration, however MonoMac uses the full framework.

Meanwhile a workaround (beside turning off the linker) is to manually edit/replace the machine.config that is bundled into the .app (that might require re-signing the .app for the appstore) and remove the (very likely) unneeded stuff related to system.net.
Comment 3 krt 2011-10-24 06:35:57 UTC
Sorry, I don't understand what should I remove from machine.config to get WebRequest working. I removed every config section where system.net was mentioned. Still no luck, same exception.
Comment 4 krt 2011-10-24 07:26:34 UTC
Ok, I've rewritten my code using NSUrlConnection. Now I have this exception in System.Xml.Serialization.XmlSerializer constructor.
Comment 5 Miguel de Icaza [MSFT] 2011-10-24 18:03:18 UTC

I think we should process the machine.config and look for the well-known nodes that can cause more code to be brought in and bring those types as requested.   

Our default until MonoDevelop gets a UI for it would be to consume the machine.config that comes with Mono.   Later we can teach the MonoDevelop IDE that if a machine.config file is included as content on the project, we link against that one instead.

So we end up doing these changes:

1. Extend MMP to parse machine.config and pass the information to the linker.
2. Extend MMP to allow a machine.config to be specified
3. Extend the MonoDevelop add-in to pass a specific machine.config if one is added as Content to MMP
4. Add a machine.config template to the MonoMac templates with the 4.0 contents with most features commented out.

Could you look at #1 and I can look at the other 3?
Comment 6 Sebastien Pouliot 2011-10-24 19:30:29 UTC
Sure, I can do #1 and #2 too since I'll need that to test the change anyway.

Out of curiosity I continued the build/fail loop to see what the linker static analysis "missed" (i.e. what we need to provide in another way). For WebRequest support the linker must keep around the following:

+ System.Configuration.ExeConfigurationHost [1]

+ System.UriTypeConverter [1]
+ System.ComponentModel.BooleanConverter [1]
+ System.ComponentModel.CollectionConverter [1]
+ System.ComponentModel.EnumConverter [1]
+ System.ComponentModel.StringConverter [1]
+ System.ComponentModel.TimeSpanConverter [1]
+ System.Net.Configuration.DefaultProxySection
+ System.Net.Configuration.HttpWebRequestElement [1]
+ System.Net.Configuration.Ipv6Element [1]
+ System.Net.Configuration.NetSectionGroup
+ System.Net.Configuration.PerformanceCountersElement [1]
+ System.Net.Configuration.ProxyElement [1]
+ System.Net.Configuration.ServicePointManagerElement [1]
+ System.Net.Configuration.SettingsSection
+ System.Net.Configuration.SocketElement [1]
+ System.Net.Configuration.WebProxyScriptElement [1]
+ System.Net.Configuration.WebRequestModulesSection
+ System.Net.Configuration.WebRequestModuleElementCollection [1]
+ System.Net.Configuration.WebRequestModuleElement [1]

Sadly a lot of the above is not part of the machine.config itself (all types marked with [1]) so parsing machine.config won't be enough. We'll likely need to bring a lot of extra code "just in case" and/or spend more time to teach the linker to bring what's required (likely both).

That also the _optimal_ case, including everything referenced in machine.config (we can't single out every feature) will result in a larger list of types.

The good news is that the parsing itself does not look too hard.
Comment 7 Sebastien Pouliot 2011-10-24 19:33:03 UTC

> Ok, I've rewritten my code using NSUrlConnection. Now I have this exception in
> System.Xml.Serialization.XmlSerializer constructor.

Please fill a separate bug report (and include a test case) otherwise we'll mix up the issue(s) and fix(es) - been there, done that a few times ;-) Thanks!
Comment 10 Sebastien Pouliot 2012-03-14 09:15:27 UTC
I'm testing a general workaround (that will be useful in other cases too) where `mmp` gets a new option `-xml=file` that allow people to provide extraneous definition files to the linker (it's something I've been planning for MT, I'll likely "sideport" that feature soon).

With the correct .xml file (which tells the linker to keep everything in the System.*.Configuration namespaces in several assemblies) I can build and execute (without missing types) a WebRequest. So far so good (but needs more testing).

I'll also look at using custom machine.config files to see if we can minimize the extra types being included (the apps are much larger than before to please System.Configuration reflection-happy design).

Right now the biggest issue is that MD monomac addin UI does not let you provide extra options to mmp (e.g. this one or others, like the -i18n option) so this fix is not very helpful until some UI enhancements are made.
Comment 11 Miguel de Icaza [MSFT] 2012-03-14 11:20:15 UTC

I am not sure I understand what the contents of the xml file are, is this a machine.config formatted file, and based on this, it brings the types that are needed based on the definitions there, or is it something else?

UI-wise, Jeff Stedfast is doing a rewrite of the UI that is needed.

Comment 12 Sebastien Pouliot 2012-03-14 11:59:25 UTC
XML == descriptors files, the linker is largely driven by them [1]. However `mmp` does not let users provide their own custom files. This limits how end-users can workaround issues (such as this one) since adding [Preserve] attributes won't work on SDK assemblies (like System.dll).

> is this a machine.config formatted file, and based on this, it brings the types that are needed based on the definitions there

Not yet. machine.config does not provide enough data, i.e. adding the types founds inside it is *very* incomplete since System.Configuration has too many parts that depends on reflection (based on context and, only partially, on machine.config). This means that using the "default" (4.0) machine.config requires us to bring a lot of extra types "just in case" (that's what my .xml files does, I'll attach it once the changes are cleaned up / committed).

The next step is providing a new, cleaned-up machine.config (w/mmp) that will minimize (goal: to avoid) the need of using custom .xml files. That should cover more than 90% of the cases and keep the application size down (close to the one we have now).

Then we can try to be "smarter" and automagically add the required System.Configuration types (for people that needs the default, or their own custom, machine.config). That will likely take a few iterations to get right (possibilities are nearly endless) but with --xml it will be easy to quickly provide workaround for them.

c.c. Jeff for comment #10

[1] https://github.com/mono/mono/tree/master/mcs/tools/linker/Descriptors
Comment 13 Jeffrey Stedfast 2012-03-14 12:13:21 UTC
Sebastien: ah, thanks for the Cc.

Once this is implemented in mmp, can you reassign to me to add the UI? thanks.
Comment 14 Sebastien Pouliot 2012-03-14 12:59:43 UTC
Jeff, it will take a while to go thru all the things (i.e. don't wait fir it ;-) but there's already bugs #2291 (general title but asking for --i18n) and #1650 (more general for extra arguments) opened for this.
Comment 15 Miguel de Icaza [MSFT] 2012-03-14 17:37:24 UTC
What I was thinking was perhaps creating a mapping that would basically know how to map a given dependency in machine.config to the types that are needed.

So "foobar" in in the config file would map from possibly one to hundreds of types, without the user having to dig into which types he need by trial and error and having to add types once per crash iteration.
Comment 16 Sebastien Pouliot 2012-03-14 20:20:17 UTC
You can see the xml files (step 1) as just that, (dumb) mappings :-) and they do does not need to be user-created, e.g. we can supply them (like the basic descriptors) for most common cases (the WebRequest case if the #1, not sure we even have a #2 right now) instead of per-xml element. 

Smarter mappings are the third step but for several reasons I'd like to avoid hitting that case as much as possible, e.g.

* there's a lot of mappings to create, both "xml to type" and "type to type" and the trigger logic (i.e. does that xml section means something for this application);

* the mappings will need to be reviewed/updated with new Mono releases (new features and bug fixes);

* the mappings will need to be duplicated with new FX versions (new/different entries/types);

So that's a lot of time to invest, both now and later, for covering potentially very few cases.

Also I can't name an application that requires a custom machine.config file (i.e. that will really benefit from the above) and that means applications are using the default machine.config. 

The one we provide today, mono/4.0/machine.config, is meant to cover every kind of usage (from console to web apps). That's an overkill for many applications and it requires a lot of extra code that's rarely needed (that's mostly what my current .xml files does).

But a new smaller machine.config (step 2) aligned with the linker defaults (i.e. no custom xml file) should cover the majority of the cases (for a fraction of the time to implement/maintain step 3). Since all steps are in the same direction we can, as time permit, do #1, #2 and, if there's a demand, #3.
Comment 17 Sebastien Pouliot 2012-12-12 20:42:59 UTC
The new MMP included in Xamarin.Mac solve this issue (and many similar ones).