Solved

Strange error compiling a class at runtime

Posted on 2008-10-14
24
5,680 Views
Last Modified: 2013-12-17
Hi all

I am trying to compile a class at runtime and I get this strange error ("System.RuntimeType is inaccessible due to its protection level. Only public types can be processed.")
when I try to serialise my xml input into the newly compiled assembly.

I have attached a rather large code snippet that I use to test my compiler and I keep getting the error

Every method in the customer.cs class is public so Im not sure why Im get this error.

Basically I get a class object from a file stored somewhere on the server

Input is provided via XML from the UI, for this example I simply save the xml to file and loaded it into a Xml document that is then serialized into customer.cs.

Help would most definitely be appreciated
//

//TEST CLASS

//

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Xml;

using System.Xml.Serialization;

using System.CodeDom.Compiler;

using System.IO;
 

namespace MarksCompilerTest

{

    public class Tester

    { 

        public static void Main()

        {

            //declare the name of the new class to create

            string nameSpace = "Customer";

            //get the class object from file

            string Classcs = System.IO.File.ReadAllText(@"C:\Customer.cs");

            //compile the class 

            object Class = Compiler.CompileClass(Classcs, nameSpace);
 

            //get input xml

            XmlDocument doc = new XmlDocument();

            doc.Load(@"C:\customer_1.xml");

            

            //merge input xml into newly compiled class, BANG!! ERROR :'(

            object mergedClass = XML.SaveXMLtoClass(doc, Class);

        }

    }
 

    internal class Compiler

    {        

        static public object CompileClass(string classobj, string nameSpace)

        {

            CompilerResults results = CompileCode(classobj, nameSpace);

            if (results.Errors.Count != 0)

            {

                Exception ex = new Exception("Cannot compile class[" + nameSpace + "]", new Exception(XML.ConvertToXMLString(results.Errors)));

                ex.Source = "Compiler.CompileClass()";

                throw ex;

                return null;

            }

            else

            {

                Type[] type = results.CompiledAssembly.GetTypes();

                return type[0];

            }

        }
 

        private static CompilerResults CompileCode(string source, string nameSpace)

        {

            var providerOptions = new Dictionary<string, string>();

            providerOptions.Add("CompilerVersion", "v3.5");
 

            var provider = new Microsoft.CSharp.CSharpCodeProvider(providerOptions);
 

            CompilerParameters parameters = new CompilerParameters();
 

            // Generate an a class library instead of a executeable

            parameters.GenerateExecutable = false;
 

            // Generate debug information.

            parameters.IncludeDebugInformation = true;
 

            parameters.OutputAssembly = nameSpace;
 

            // Add an assembly reference.

            MarksCompilerTest.Properties.Settings settings = new MarksCompilerTest.Properties.Settings();

            foreach (string assembly in settings.Assemblies)

            {

                parameters.ReferencedAssemblies.Add(assembly);

            }
 

            //Add using statements to source code

            var sourceBuilder = new StringBuilder();

            foreach (string usingStatement in settings.Usings)

            {

                sourceBuilder.AppendLine("using " + usingStatement + ";");

            }

            sourceBuilder.AppendLine(source);

            source = sourceBuilder.ToString();
 

            // Save the assembly as to memory.

            parameters.GenerateInMemory = true;
 

            parameters.OutputAssembly = nameSpace;
 

            // Set the level at which the compiler 

            // should start displaying warnings.

            parameters.WarningLevel = 3;
 

            // Set whether to treat all warnings as errors.

            parameters.TreatWarningsAsErrors = false;
 

            // Set compiler argument to optimize output.

            parameters.CompilerOptions = "/optimize";
 

            

            // Invoke compilation.

            return provider.CompileAssemblyFromSource(parameters, source);
 

        }

    }
 

        internal class XML

        {

            public static string ConvertToXMLString(object obj)

            {

                var memoryStream = new MemoryStream();

                var doc = new XmlDocument();
 

                try

                {

                    XmlSerializer serializer = new XmlSerializer(obj.GetType());

                    XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);

                    serializer.Serialize(xmlTextWriter, obj);

                    memoryStream = (MemoryStream)xmlTextWriter.BaseStream;

                    return UTF8ByteArrayToString(memoryStream.ToArray());

                }

                catch (Exception e)

                {

                    return "";

                }

                finally

                {

                    memoryStream.Flush();

                    memoryStream.Close();

                    memoryStream.Dispose();

                }

            }
 

            static private string UTF8ByteArrayToString(Byte[] characters)

            {
 

                UTF8Encoding encoding = new UTF8Encoding();

                String constructedString = encoding.GetString(characters);

                return (constructedString);

            }
 

            public static object SaveXMLtoClass(XmlDocument doc, object Class)

            {

                StringReader stream = null;

                XmlTextReader reader = null;

                try

                {

                    var serializer = new XmlSerializer(Class.GetType());                    

                    stream = new StringReader(doc.InnerXml);

                    reader = new XmlTextReader(stream);

                    return (object)serializer.Deserialize(reader);

                }

                catch (Exception ex)

                {

                    throw;

                    return null;

                }

                finally

                {

                    if (stream != null) stream.Close();

                    if (reader != null) reader.Close();

                }

            }

        }

}
 
 

//

// App config

//

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <configSections>

        <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >

            <section name="MarksCompilerTest.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />

        </sectionGroup>

    </configSections>

    <applicationSettings>

        <MarksCompilerTest.Properties.Settings>

            <setting name="Usings" serializeAs="Xml">

                <value>

                    <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                        xmlns:xsd="http://www.w3.org/2001/XMLSchema">

                        <string>System</string>

                        <string>System.Text</string>

                        <string>System.Xml</string>

                    </ArrayOfString>

                </value>

            </setting>

            <setting name="Assemblies" serializeAs="Xml">

                <value>

                    <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

                        xmlns:xsd="http://www.w3.org/2001/XMLSchema">

                        <string>System.dll</string>

                        <string>System.XML.dll</string>

                    </ArrayOfString>

                </value>

            </setting>

        </MarksCompilerTest.Properties.Settings>

    </applicationSettings>

</configuration>
 
 
 

//

// Customer_1.xml  (INPUT) 

//

<?xml version="1.0" encoding="UTF-8" ?>

<Customer>  

  <FirstName>Mark</FirstName>

  <LastName>Myburgh</LastName>

  <IDNumber>99999999999</IDNumber>

  <DateOfBirth>2000-07-29T02:50:43.2324</DateOfBirth>

  <Email>m@m.co.za</Email>

  <Address>

    <Line1>CODE HELL</Line1>

    <Line2>Crash Street</Line2>

    <Line3></Line3>

    <City>Broken</City>

    <Code>666</Code>

  </Address>

</Customer>
 
 

//

//  Customer.cs (FILE TO BE COMPILED)

//

public class Customer

{
 

  public string FirstName { get; set; }

  public string LastName { get; set; }  

  public string IDNumber { get; set; } 

  public DateTime DateOfBirth { get; set; } 

  public string Email { get; set; }      

  public Address Address { get; set; }

}
 

public class Address

{

    public string Line1 { get; set; }

    public string Line2 { get; set; }

    public string Line3 { get; set; }

    public string City { get; set; }

    public int Code { get; set; }

    public Address() { }

}

Open in new window

0
Comment
Question by:MarkMyburgh
24 Comments
 
LVL 26

Assisted Solution

by:Anurag Thakur
Anurag Thakur earned 50 total points
Comment Utility
are you sure you Customer object is a class
it looks like you are defining an interface - i cannot see any variables which are being set or returned - this class just compiled gives errors

public class Customer
{
  public string FirstName { get; set; }
  public string LastName { get; set; }  
  public string IDNumber { get; set; }
  public DateTime DateOfBirth { get; set; }
  public string Email { get; set; }      
  public Address Address { get; set; }
}
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
Hi Rag
yip it is a class.  In 2008 you don't have to declare private variables for properties anymore :
            public string FirstName { get; set; }      <-- this is how you declare a property in 2008 :D  sweet hey.  I LIKE it a lot :D
Also I'm sure you noticed that there is no references in the class, at runtime I add all the Using referencies before compiling the source code.
            var sourceBuilder = new StringBuilder();
            foreach (string usingStatement in settings.Usings)
            {
                sourceBuilder.AppendLine("using " + usingStatement + ";");
            }
            sourceBuilder.AppendLine(source);
            source = sourceBuilder.ToString();

What i am worred about is that the CompilerResults.Error is not populated, how would one attach onto the compiler stream.  that way i can have a look at the output and see if there is any compile errors.
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
thought i found the error but no i still get the issue.
below find the update customer class

//

//  Customer.cs (FILE TO BE COMPILED)

//

public class Customer

{

 

  public string FirstName { get; set; }

  public string LastName { get; set; }  

  public string IDNumber { get; set; } 

  public DateTime DateOfBirth { get; set; } 

  public string Email { get; set; }      

  public Address Address { get; set; }

  publlic Customer (){}

}

 

public class Address

{

    public string Line1 { get; set; }

    public string Line2 { get; set; }

    public string Line3 { get; set; }

    public string City { get; set; }

    public int Code { get; set; }

    public Address() { }

}

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
Comment Utility
Do it matter that you have a typo?

    publlic Customer (){}
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
lol yeah that just on here i simple copied and pasted the example from above.  my bad.  The code is clean;
 

public class Customer

{

  public string FirstName { get; set; }

  public string LastName { get; set; }  

  public string IDNumber { get; set; } 

  public DateTime DateOfBirth { get; set; } 

  public string Email { get; set; }      

  public Address Address { get; set; }

  public Customer () {}

}
 

public class Address

{

    public string Line1 { get; set; }

    public string Line2 { get; set; }

    public string Line3 { get; set; }

    public string City { get; set; }

    public int Code { get; set; }

    public Address() { }

}

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
Comment Utility
Hmmm...it looks like you are using auto-implemented properties, which means that the fields are generated at run-time (I believe).  What happens if you use explicitly declared fields for the property (just a test)?
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
:'''(   and there goes that bubble ....
same error
 
but i found a few errors inside the compiled assembly, even though the compiler did not through an error compiling the code:
error 1:
DeclaringMethod = '((System.RuntimeType)(type)).DeclaringMethod' threw an exception of type 'System.InvalidOperationException'

base {System.SystemException} = {"Method may only be called on a Type for which Type.IsGenericParameter is true."}

error 2:
GenericParameterAttributes = '((System.RuntimeType)(type)).GenericParameterAttributes' threw an exception of type 'System.InvalidOperationException'

base {System.SystemException} = {"Method may only be called on a Type for which Type.IsGenericParameter is true."}

error 3:
GenericParameterPosition = '((System.RuntimeType)(type)).GenericParameterPosition' threw an exception of type 'System.InvalidOperationException'

base {System.SystemException} = {"Method may only be called on a Type for which Type.IsGenericParameter is true."}


public class Customer

{

    private string _fn;

    private string _ln;

    private string _ID;

    private DateTime _dob;

    private string _em;

    private Address _add;
 

    public string FirstName 

    {

        get { return _fn; }

        set { _fn = value; }

    }
 

    public string LastName

    {

        get { return _ln; }

        set { _ln = value; }

    }
 

    public string IDNumber

    {

        get { return _ID; }

        set { _ID = value; }

    }
 

    public DateTime DateOfBirth

    {

        get { return _dob; }

        set { _dob = value; }

    }
 

    public string Email

    {

        get { return _em; }

        set { _em = value; }

    }
 

    public Address Address

    {

        get { return _add; }

        set { _add = value; }

    }
 

    public Customer () {}

}
 

public class Address

{

    private string _l1;

    private string _l2;

    private string _l3;

    private string _ct;

    private int _cd;
 

    public string Line1

    {

        get { return _l1; }

        set { _l1 = value; }

    }
 

    public string Line2

    {

        get { return _l2; }

        set { _l2 = value; }

    }
 

    public string Line3

    {

        get { return _l3; }

        set { _l3 = value; }

    }
 

    public string City

    {

        get { return _ct; }

        set { _ct = value; }

    }
 

    public int Code

    {

        get { return _cd; }

        set { _cd = value; }

    }
 

    public Address() { }

}

Open in new window

0
 
LVL 96

Expert Comment

by:Bob Learned
Comment Utility
I believe that I have too narrow of a view to understand your problem (from where I am sitting).
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
hmmm
you could try compile the code on yourside and see what you get.
open a new project
copy and past the class into a new class file
add a config file to the app and copy the config settings from above
create a new file at c:\  call it customer.cs and past the customer class info from above

that should take care of all that needs to be created.
0
 
LVL 96

Expert Comment

by:Bob Learned
Comment Utility
That code compiles just fine, but I am using 2005, and not 2008 (which I don't have at work).
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
do you still get the same error?
I'm just loading up 2005 to determine if i get the same error.
Question tho after compiling the object did the xml seriliasation step work?
 //get input xml
            XmlDocument doc = new XmlDocument();
            doc.Load(@"C:\customer_1.xml");
           
            //merge input xml into newly compiled class, BANG!! ERROR :'(
            object mergedClass = XML.SaveXMLtoClass(doc, Class);

this is the section thats giving me so much grief
0
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
nope same error on 2005 as well.  cannot serialise the xml into the newly compiled class
0
 
LVL 96

Expert Comment

by:Bob Learned
Comment Utility
What is this code testing?  Are you trying to compare the compiled class against the serialized XML file?
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
2 things;
1 :
  compile a class object
2:
    serialize a xml file into the new compiled class object
 
0
 
LVL 96

Assisted Solution

by:Bob Learned
Bob Learned earned 300 total points
Comment Utility
Since your class instance is declared as 'object', there would not be any way that I know of to get the serializer to work.
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
strange thing is;  if i add the class to the projec
and do the following:
{
            //declare the name of the new class to create
            string nameSpace = "Customer";
            //get the class object from file
            //string Classcs = System.IO.File.ReadAllText(@"C:\Customer.cs");
            //compile the class
            //object Class = Compiler.CompileClass(Classcs, nameSpace);
           customer Class = new Customer();

            //get input xml
            XmlDocument doc = new XmlDocument();
            doc.Load(@"C:\customer_1.xml");
           
            //merge input xml into newly compiled class, BANG!! ERROR :'(
            object mergedClass = XML.SaveXMLtoClass(doc, Class);
        }
 
I can serialiase the object no error.  Only when i use the compiled version of the same class do i get the error :(
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
this is the method i'm using to serialize
 public static object SaveXMLtoClass(XmlDocument doc, object Class)
            {
                StringReader stream = null;
                XmlTextReader reader = null;
                try
                {
                    var serializer = new XmlSerializer(Class.GetType());                    
                    stream = new StringReader(doc.InnerXml);
                    reader = new XmlTextReader(stream);
                    return (object)serializer.Deserialize(reader);
                }
                catch (Exception ex)
                {
                    throw;
                    return null;
                }
                finally
                {
                    if (stream != null) stream.Close();
                    if (reader != null) reader.Close();
                }
            }
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
found this might help you out
http://forums.asp.net/t/1323181.aspx
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
ignore my previous post:  I pasted it into the wrong window
0
 
LVL 1

Accepted Solution

by:
MarkMyburgh earned 0 total points
Comment Utility
THIS has to be one of the most painful ball aches I have ever experienced trying to solve this error;
With some help from one of our senior member we found the issue;
have a look at the updated code;
thanks to all... :D
 
Mark

//// UPDATED CODE IN TESTER APP

 public class Tester

    {

        public static void Main()

        {

            //declare the name of the new class to create

            string nameSpace = "Customer";
 

            //get the class object from file

            string source = System.IO.File.ReadAllText(@"C:\Customer.cs");
 

            //compile the class 

            Type type = Compiler.CompileClass(source, nameSpace);
 

            //get input xml

            XmlDocument doc = new XmlDocument();

            doc.Load(@"C:\Customer_1.xml");
 

           object mergedClass = SeriaizationHelper.XmlDeserialize(doc, type);
 

            Console.WriteLine(type.GetProperty("IdNumber").GetValue(mergedClass,null).ToString());
 

            Console.Read();

        }

    }
 

    internal class SeriaizationHelper

    {

        public static object XmlDeserialize(XmlDocument doc, Type t)

        {

            MemoryStream stream = new MemoryStream();
 

            doc.Save(stream);
 

            stream.Position = 0;
 

            return new XmlSerializer(t).Deserialize(stream);

        }

        public static XmlDocument XmlSerialize(Customer customer, Type t)

        {

            XmlDocument doc = new XmlDocument();

            MemoryStream stream = new MemoryStream();
 

            new XmlSerializer(t).Serialize(stream, customer);
 

            stream.Position = 0;
 

            doc.Load(stream);
 

            return doc;

        }

    

    }
 
 

// UPDATED CUSTOMER CLASS

using System;

using System.Xml;

using System.Xml.Serialization;

using System.IO;
 

[Serializable()]

public class Customer

{

    private string _firstName;

    private string _lastName;

    private string _idNumber;

    private DateTime _dateOfBirth;

    private string _email;

    private Address _address;
 

    [XmlElement]

    public string FirstName

    {

        get { return _firstName; }

        set { _firstName = value; }

    }
 

    [XmlElement]

    public string LastName

    {

        get { return _lastName; }

        set { _lastName = value; }

    }
 

    [XmlElement]

    public string IdNumber

    {

        get { return _idNumber; }

        set { _idNumber = value; }

    }
 

    [XmlElement]

    public DateTime DateOfBirth

    {

        get { return _dateOfBirth; }

        set { _dateOfBirth = value; }

    }
 

    [XmlElement]

    public string Email

    {

        get { return _email; }

        set { _email = value; }

    }
 

    [XmlElement]

    public Address Address

    {

        get { return _address; }

        set { _address = value; }

    }
 

    public Customer () {
 

        Address = new Address();

    }

}
 

[Serializable()]

public class Address

{

    private string _line1;

    private string _line2;

    private string _line3;

    private string _city;

    private int _code;
 

    [XmlElement]

    public string Line1

    {

        get { return _line1; }

        set { _line1 = value; }

    }

    [XmlElement]

    public string Line2

    {

        get { return _line2; }

        set { _line2 = value; }

    }
 

    public string Line3

    {

        get { return _line3; }

        set { _line3 = value; }

    }

    [XmlElement]

    public string City

    {

        get { return _city; }

        set { _city = value; }

    }

    [XmlElement]

    public int Code

    {

        get { return _code; }

        set { _code = value; }

    }
 

    public Address() { }

}
 
 

//UPDATED XML CLASS

<?xml version="1.0"?>

<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <FirstName>John</FirstName>

  <LastName>Doe</LastName>

  <IdNumber>551022 5435 099</IdNumber>

  <DateOfBirth>2008-10-17T15:52:18.890625+02:00</DateOfBirth>

  <Email>foo@com.com</Email>

  <Address>

    <Line1>Line 1</Line1>

    <Line2>Line 2</Line2>

    <Line3>Line 3</Line3>

    <City>Some Place</City>

    <Code>1102</Code>

  </Address>

</Customer>

Open in new window

0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
Managed to resolve the error.  Thanks all for your assistance.
save coding
0
 
LVL 1

Author Comment

by:MarkMyburgh
Comment Utility
Managed to resolve error.  Thanks all for your assistance and input
save coding
0
 

Expert Comment

by:Shahnaseem
Comment Utility
I have seen your comments to solve the problem, but if you could specifically tell us what you have done to solve the problem it will be great.
0

Featured Post

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

This article describes relatively difficult and non-obvious issues that are likely to arise when creating COM class in Visual Studio and deploying it by professional MSI-authoring tools. It is assumed that the reader is already familiar with the cla…
Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Excel styles will make formatting consistent and let you apply and change formatting faster. In this tutorial, you'll learn how to use Excel's built-in styles, how to modify styles, and how to create your own. You'll also learn how to use your custo…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

762 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

8 Experts available now in Live!

Get 1:1 Help Now