This is Xamarin's bug tracking system. For product support, please use the support links listed in your Xamarin Account.
Bug 1528 - TypeInitializationException when using classes depending on System.Configuration.ConfigurationManager in packaged MonoMac application
: TypeInitializationException when using classes depending on System.Configurat...
Status: RESOLVED FIXED
Product: MonoMac
Classification: Desktop
Component: Bindings
: unspecified
: Macintosh Mac OS
: Normal blocker
: ---
Assigned To: Sebastien Pouliot
:
:
:
:
  Show dependency treegraph
 
Reported: 2011-10-17 06:52 EDT by krt
Modified: 2012-12-12 20:42 EST (History)
5 users (show)

See Also:
Tags:
Test Case URL:
External Submit: ---


Attachments

Description krt 2011-10-17 06:52:43 EDT
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 2011-10-22 21:12:00 EDT
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 EDT
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 EDT
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 EDT
Ok, I've rewritten my code using NSUrlConnection. Now I have this exception in
System.Xml.Serialization.XmlSerializer constructor.
Comment 5 Miguel de Icaza 2011-10-24 18:03:18 EDT
Sebastien,

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 EDT
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.dll
+ System.Configuration.ExeConfigurationHost [1]

System.dll
+ 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 EDT
Krt,

> 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 EDT
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 2012-03-14 11:20:15 EDT
Sebastien,

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.

Miguel
Comment 12 Sebastien Pouliot 2012-03-14 11:59:25 EDT
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 EDT
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 EDT
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 2012-03-14 17:37:24 EDT
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 EDT
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 EST
The new MMP included in Xamarin.Mac solve this issue (and many similar ones).

Note You need to log in before you can comment on or make changes to this bug.