how about (from an older post):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#I @"C:\Program Files\FSharp-1.9.7.8\\bin\"
#r "FSharp.Compiler.CodeDom"
#r "FSharp.PowerPack.Linq"
#r "System.Core.dll"

open Microsoft.FSharp.Compiler.CodeDom
open System.Reflection
open Microsoft.FSharp.Quotations

let provider = new FSharpCodeProvider()
let eval exp =
    let source = "module foo let main() = \n " + exp
    let parms = System.CodeDom.Compiler.CompilerParameters(GenerateExecutable = false, GenerateInMemory = true)
    let compilerResults = provider.CompileAssemblyFromSource(parms, [| source |])
    let assembly = compilerResults.CompiledAssembly
    let foo = assembly.GetType("foo")
    let main = foo.GetMethod("main")
    main.Invoke(obj(),[||]) :?> 'outp  
By on 3/16/2010 6:10 AM ()

Thanx, Mau, for reply )

Proposed code is not complicated... It means that fsc.exe invoked behind the scenes - is it right? How I can pass some not primitive object from my app to the main? Is it hard to get errors?

I will look documentation for details...

By on 3/16/2010 6:46 AM ()

Gen, the code Mau suggested will work perfectly, but you should be aware that every time you recompile the code in the textbox, you'll be loading a new assembly into your process. If you have a long lived application and you frequently recompile the code (which I assume you do, since you have to recompile if incorrect code was typed into the textbox), you'll have a pretty nasty resource leak on your hands.

The issue is that individual assemblies cannot be unloaded once you load them. AppDomains provide that kind of functionality, but are somewhat more heavyweight and cross-domain communication uses remoting (objects which you call remotely need to be MarshalByReference or MarshalByValue, and classes that you send accross must be serializable)

The posted example can be extended in a way that you load each assembly into a separate appdomain, execute the code, and then unload the appdomain (or perhaps recycle the appdomain after a certain number of temporary assemblies have been loaded into it). That way you avoid growing your process into a blob of 100s of temporary assemblies.

By on 3/18/2010 11:09 AM ()

@tomf:

glad to know that.

A some what related question. Instead of executing some F#/C# stuff on the fly, would it be easier to load a IronPython/IronRuby session and execute that(then exit) ?

The usual issues are :

1. how to sandbox it so it cannot run System.File... etc.

2. how to prevent DOS (like endless do nothing loop)

3. how to pass certain context into the session, and also get things out.

I have worked with lua in the past for this kind of usage and other than (2), it is quite doable. Not sure how under .NET

By on 3/18/2010 2:15 PM ()

1. Is already quite tricky. I guess the only way would be to analyise the code graph using heuristics. However, this will be always a "best effort" security, as there is no means to guarantee that someone won't come up with a novel way to execute arbitrary code.

2. Using appdomains would shield your process from malicious code to a certain degree. If an exception is thrown, it will only bring down the separate appdomain, not your entire process. You could perhaps also monitor how long a task is running and abort the thread if it exceeds a specific value.

3. As I wrote, you can communicate with objects in a different appdomain quite easily, you just have to observe a few limitations imposed by remoting.

An academic approach to #2 would be analysing the algorithm (I think computability theory deals with this). As far as I know there is no easy way to do it, since an algorithm can become non-deterministic simply by waiting for external input. The moment you add a Console.ReadLine() to your program, its execution time cannot be measured in a realistic way because it can take an arbitrarily long time for the input to arrive.

By on 3/19/2010 5:42 AM ()

Is this method ok to use on any end-user system w/ or w/o a dev. environment installed?

I'm wondering if there are any licensing implications with 3rd-party libraries. I know there are some for-pay libs are expected to be used by "hard"-compiled artifacts, and not allowed to be coded by the end-users, or different prices apply for "dynamic" use. If end-users can code "derivitive works" of their own, does this effect GPL-style licenses in any way?

By on 3/19/2010 3:30 PM ()

I'm trying to get external referneces working, but the I'm unable to "open" my external (F#) assembly in the compiled code, or reference the module prefix explicity in the code.

1
2
3
4
5
6
7
8
9
10
11
let externs = new System.Collections.Specialized.StringCollection() 
externs.Add <| typeof<MyType>.Assembly.GetName().CodeBase  // this includes "file:"
externs.Add <| @"D:\MyAssembly.dll"  // this doesn't 
externs.Add <| @"garbage"  // there's no warning here
parms.ReferencedAssemblies = externs
let compilerResults = provider.CompileAssemblyFromSource( parms, [| source |])
if compilerResults.Errors.HasErrors then
    failwith <| "Compile error: \n" + compilerResults.Errors.[0].ErrorText
else
    let assembly = compilerResults.CompiledAssembly

Note that in third extern, I've passed garbage, but there's no compile error, so it looks like my externs aren't even getting looked at. Is there something else I need to do for the extern asseblies to be loaded?

thanks

By on 3/21/2010 12:03 PM ()

Okay, this was an oldie but goodie...

1
2
 
parms.ReferencedAssemblies = externs

Should have been:

1
2
 
parms.ReferencedAssemblies.AddRange <| List.toArray externs

parms.ReferencedAssemblies is pre-allocated and not settable - if I'd used "<-" it would have failed, so I was left with the old assign-vs-test operator problem. (Was just working on a c# project...)

I would have noticed but the wavy blue underline for the warning was invisible w/my background now that it's dark and I turned the gamma down -- anyone know how to change this color on VS2010RC? - I tried Warning and Warning Line w/no effect.

By on 3/21/2010 1:45 PM ()

The usual issues are :

1. how to sandbox it so it cannot run System.File... etc.

2. how to prevent DOS (like endless do nothing loop)

3. how to pass certain context into the session, and also get things out.

I have worked with lua in the past for this kind of usage and other than (2), it is quite doable. Not sure how under .NET

Interesting. I'm curious: do u know what the 'state of the art' is for (2) ?

By on 3/19/2010 3:25 AM ()

Gen,
-the compiler should be run in the same process (i.e., fsc.exe is not started).
-you can retrieve errors from the compilationResults object.
-u can pass extra arguments by either 1. declaring them as parameters of the main function in the source string and then passing them through the array given as 2nd param of the invoke in the last line or 2. handling the "exp" code.

By on 3/16/2010 10:39 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper