0

Take the following C# code

namespace lib.foo {
  public class A {
    public A (int x) {}
    public int GetNumber() { return calculateNumber(); }
    private int calculateNumber() { return lib.bar.B.ProduceNumber(); }
    public void irrelevantMethod() {}
  }
}
namespace lib.bar {
  public class B {
    public static int ProduceNumber() { return something; }
    public void IrrelevantMethod() {}
  }
}

I want to produce an assembly that contains the functionality of lib.foo.A.GetNumber(), store it, and later load it dynamically and then execute it.
In order for that to work, I'd need a program that can trace all the required dependencies (listed below), and emit them - including their implementation(!) - in one assembly for storage.

 * lib.foo.A(int)
 * lib.foo.A.getNumber()
 * lib.foo.A.calculateNumer()
 * lib.bar.B.ProduceNumber()

Can it be done? How?

In case anyone is wondering, I want to build a system where machine A tells machine B (using WCF) what to do. Since serializing delegates is impossible, my plan is to

1) transport an assembly from machine A to B,

2) load the assembly on machine B,

3) have machine A instruct machine B to invoke the desired method, which is implemented in this new assembly.

Saravanan
  • 7,637
  • 5
  • 41
  • 72
derabbink
  • 2,419
  • 1
  • 22
  • 47
  • keep all "transportable code" in source form, this way you don't need to "recover" it via reflection... and you can transport it to be compiled anywhere you like... – Yahia May 30 '13 at 14:47
  • 1
    Then why not use unloadable plugins? So machine B can always load/unload them and all you need is a plugin host which is able to do that stuff (invoke a plugin's method by name). – Marcel N. May 30 '13 at 14:55
  • 1
    That sounds sensible: transporting the entire assembly (and its dependencies) from machine A to B, load it in an AppDomain and invoke the method by name. – derabbink May 30 '13 at 15:08

1 Answers1

2

Note - this isn't really an answer, more of a nitpicking correction (of sorts)..

When you say "Since serializing delegates is impossible", this isn't strictly true, although I would NOT recommend doing it. This example code effectively "serializes" a delegate:

void Main()
{
    Func<int,int> dlgt = FuncHolder.SomeMethod;
    var ser = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
    byte[] buffer;
    using(var ms = new MemoryStream())
    {
        ser.Serialize(ms, dlgt);
        buffer = ms.ToArray();
    }
    Console.WriteLine("{0} was serialized to {1} bytes", dlgt.GetType().Name, buffer.Length);
    using(var ms = new MemoryStream(buffer))
    {
        dynamic whatzit = ser.Deserialize(ms);
        whatzit(1);
    }
}

[Serializable]
public struct FuncHolder
{
    public static int SomeMethod(int i)
    {
        Console.WriteLine("I was called with {0}, returning {1}", i, i+1);
        return i+1;
    }
}

Output:

Func`2 was serialized to 978 bytes
I was called with 1, returning 2

I must emphasize, however, that you probably shouldn't do this. :)

As for the original question:

I'd be very careful about transporting and executing arbitrary code, especially in a production environment; the potential for security breaches is considerable, mainly via injection routes. If you were to take, for example, one of the above suggestions and just blast over the source to execute dynamically, there's little stopping someone from injecting who-knows-what into your "Give me code to run" service.

You'd really need to spell out your exact needs here to really come up with a "good" solution, as there are multiple ways to accomplish the same basic idea:

  • as mentioned, pass actual source code to the service to load/compile/execute, potentially in a "sandbox" for some aspect of security/protection

  • distribute all executable code paths in a shared plugin/assembly which is pushed by some trusted process to all remote servers, and reduce your executor code to a single "DoWork" method invocation (i.e., wrap all the details inside the plugin)

  • Cobble together a rough DSL or other type of pseudo-language, restricted in what it can/can't do, and pass that source around.

  • rely on .NET remoting: actually go remotely call the methods in the assembly on a remote object via proxy.

JerKimball
  • 16,584
  • 3
  • 43
  • 55
  • I agree with your general security concerns, but my system will run on a physically isolated network. The proposed system will be used for testing a distributed app black-box-style; transported code contains testing instructions. – derabbink May 30 '13 at 16:57