This was a problem, because the .Net 3.5 code could compile code at run time targeting either 2.0 or the 3.5 framework. Since the services written in 1.1 required an assembly to be compiled in 1.1, it could not load the assembly that was being generated.
A bit of research and the use of .Net Reflector tool, provided the solution.
Lets start with the code that will compile an assembly at runtime using code written in a text file targeting .Net 3.5 framework.
Dim Compiler As VBCodeProvider = Nothing
Dim pvdr As CodeDomProvider
Dim CompilerParams As CompilerParameters
Dim CompileResults As CompilerResults
Public Function CompileCode() As String
Dim strReturn As String = ""
Try
CompilerParams = New CompilerParameters
With CompilerParams
.TreatWarningsAsErrors = False
.WarningLevel = 4
.GenerateInMemory = False
.IncludeDebugInformation = True
Dim References() As String = {"System.dll",
"System.Data.dll", "Microsoft.VisualBasic.dll"}
.ReferencedAssemblies.AddRange(References)
.OutputAssembly = "C:\Projects\ThisIsATestDLL.dll"
End With
Dim provOpt = New Dictionary(Of String, String)
provOpt.Add("CompilerVersion", "v3.5")
Compiler = New VBCodeProvider(provOpt)
CompileResults = Compiler.CompileAssemblyFromFile(CompilerParams,
"C:\RandD\VS08\TestClassLib\Test.vb")
If CompileResults.Errors.HasErrors Then
For Each Err As CodeDom.Compiler.CompilerError In
CompileResults.Errors
strReturn &= Err.ErrorText & "
@Line: " & Err.Line & vbCrLf
Next
End If
Catch ex As Exception
Throw New Exception(ex.Message, ex)
End Try
Return strReturn
End Function
That is the key. If we switch this to
provOpt.Add("CompilerVersion", "v2.0")
Our code will compile in version 2.0 framework.
What we want is to comile in 1.1. It is not as simple as changing the version to say "v1.1". That wont work. To understand how to accomplish this, we have to look at the code of VBCodeProvider's constructor. I used the .Net reflector to take a look at this.
The CodeDOMCompiler code does the following
If version is 3.5 then
look at the environment variables. If environment variables COMPLUS_InstallRoot and COMPLUS_Version is not present then compile code to default 3.5 version. Else read those environment variable versions to do the compile.
If the version is not 3.5 then it is defaulted to 2.0.
As you can see, the only two values that can be passed to the VBCodeProvider's constructor is "v3.5" or "v2.0".
So in order to compile the assembly in 1.1, we will introduce the env variables in code.
Imports System.CodeDom
Imports System.CodeDom.Compiler
Public Class CodeCompiler
Dim Compiler As VBCodeProvider = Nothing
Dim pvdr As CodeDomProvider
Dim CompilerParams As CompilerParameters
Dim CompileResults As CompilerResults
Public Function CompileCode() As String
Dim strReturn As String = ""
Try
CompilerParams = New CompilerParameters
With CompilerParams
.TreatWarningsAsErrors = False
.WarningLevel = 4
.GenerateInMemory = False
.IncludeDebugInformation = True
Dim References() As String = {"System.dll",
"System.Data.dll", "Microsoft.VisualBasic.dll"}
.ReferencedAssemblies.AddRange(References)
.OutputAssembly = "C:\Projects\ThisIsATestDLL11.dll"
End With
'You can put these values in the config file if you dont want to 'hard code it.
Environment.SetEnvironmentVariable("COMPLUS_InstallRoot",
"C:\WINDOWS\Microsoft.NET\Framework")
Environment.SetEnvironmentVariable("COMPLUS_Version",
"v1.1.4322")
Dim provOpt = New Dictionary(Of String, String)
provOpt.Add("CompilerVersion", "v3.5")
Compiler = New VBCodeProvider(provOpt)
CompileResults = Compiler.CompileAssemblyFromFile(CompilerParams,
"C:\RandD\VS08\TestClassLib\Test.vb")
If CompileResults.Errors.HasErrors Then
For Each Err As CodeDom.Compiler.CompilerError In
CompileResults.Errors
strReturn &= Err.ErrorText & "
@Line: " & Err.Line & vbCrLf
Next
End If
Catch ex As Exception
Throw New Exception(ex.Message, ex)
End Try
Return strReturn
End Function
End Class
The lines of code
Environment.SetEnvironmentVariable("COMPLUS_InstallRoot", "C:\WINDOWS
\Microsoft.NET\Framework")
Environment.SetEnvironmentVariable("COMPLUS_Version",
"v1.1.4322")
does the trick. It foxes the .Net code into believing that we have 3.5 version to be compiled, but since we introduce the env variables before calling the VBCodeCompiler's constructor, it will read the env variables and compile the code in 1.1. It's that simple.
These env variable setting is only for that current code and once the code runs out of scope, the env variables are not persisted.
I had posted this solution on www.experts-exchange.com too.. Hope it helps someone!
Enjoy!
No comments:
Post a Comment