del-boy
del-boy

Reputation: 3654

Send code to be executed on server in C# - like Java RMI

This is example code in java.

Shared interfaces:

import java.rmi.Remote;
import java.rmi.RemoteException;

public interface Compute extends Remote {
  public Object executeTask(Task t) throws RemoteException;
}

Task (this will be passed as parameter):

import java.io.Serializable;

public interface Task extends Serializable {
  public Object execute();
}

Server:

import java.rmi.Naming;
import java.rmi.RMISecurityManager;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;

public class ComputeEngine extends UnicastRemoteObject implements Compute {

  public ComputeEngine() throws RemoteException {
    super();
  }

  public Object executeTask(Task t) {
    return t.execute();
  }

  public static void main(String[] args) {
    setRmiCodebase();
    System.setSecurityManager(new RMISecurityManager());
    try {
      Compute engine = new ComputeEngine();
      Naming.rebind("//localhost:1099/Compute", engine);
      System.out.println("ComputeEngine started.");
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private static void setRmiCodebase() {
    String codebase = System.getProperty("java.rmi.server.codebase");
    if (codebase != null)
      return;
    // set codebase based on location of this clsas (is it in jar or filesistem?)
  }

}

Client:

import java.math.BigDecimal;
/**
* Calculates Pi to arbitrary number of digits:
*/
public class Pi implements Task {

  public Pi(int digits) {
    this.digits = digits;
  }

  public Object execute() {
    return computePi(digits);
  }

  public static BigDecimal computePi(int digits) {
    // compute Pi
  }

}

Client main:

import java.math.BigDecimal;
import java.rmi.Naming;
import java.rmi.RMISecurityManager;

public class ComputePi {

  public static void main(String[] args) {
    setRmiCodebase();
    System.setSecurityManager(new RMISecurityManager());
    try {
      Compute comp = (Compute)Naming.lookup("//localhost:1099/Compute");
      Pi task = new Pi(100);
      BigDecimal pi = (BigDecimal)comp.executeTask(task);
      System.out.println(pi);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
  }

  private static void setRmiCodebase() {
    String codebase = System.getProperty("java.rmi.server.codebase");
    if (codebase != null)
      return;
    // set codebase based on location of this clsas (is it in jar or filesistem?)
  }
}

As you can see, code (not just data) from client is transfered to server and executed there and result of computation is returned. Server does not know that class Pi exists, it only knows about Task interface.

I need something like this to work in .net environment (C# if it is important). WCF would be nice, but I am looking for the most straightforward solution, so WCF is not compulsory. I am not sure even what keyword to use to google documetation or solution for this.

Any help will be appreciated.

Upvotes: 3

Views: 1857

Answers (5)

Marino Šimić
Marino Šimić

Reputation: 7342

This MSDN page has more or less this exact use case you described. You just need to modify the ServiceContract

http://msdn.microsoft.com/en-us/library/system.servicemodel.netnamedpipebinding.aspx

You would probably only need to modify this part:

 [ServiceContract(Namespace = "http://UE.Samples")]
    public interface ICalculator
    {
        [OperationContract]
        double Add(double n1, double n2);
    }

    // Service class which implements the service contract.
    public class CalculatorService : ICalculator
    {
        public double Add(double n1, double n2)
        {
            return n1 + n2;
        }

Instead of scalar values put your executeTask method with parameter of your own class there.

Upvotes: 1

Steven Doggart
Steven Doggart

Reputation: 43743

.NET does not natively support "sending code" to be executed on another computer. Typically the necessary code would be compiled to assemblies and pre-installed on the server before it is called by the client. This is true of both remoting and WCF. You could have a two-way remoting situation where the server calls back to a method on the client via WCF, but I suspect this is not what you want. The only way I'm aware of to really run dynamic code on the server is to generate dynamic code, send it to the server as a string, and then have the server compile it to an in-memory assembly on the fly and then execute it. If you are interested in doing so, take a look at my answer to a similar question:

Autovivified properties?

However, it's not exactly something I would suggest in most cases. I would suggest you rethink your design, first, to see if there is any way to do what you need in a typical ".NET way".

Upvotes: 1

Barry Wark
Barry Wark

Reputation: 107754

I don't believe .NET has a built-in solution for transferring executable code from client to server. Assuming the security constraints allow it, you might consider sending interpretable code such as Python or JavaScript which could be executed server-side via IronPython or IronJS respectively. If C# is a requirement (and you still have access to the source code), sending the source and compiling server-side (via Roslyn or the Mono's evaluator).

Upvotes: 0

Grzegorz W
Grzegorz W

Reputation: 3517

What You want is .NET Remoting. Here's link to article showing how to migrate from RMI to .NET Remoting.

But according to this MSDN article this is a legacy technology and You should use WCF.

Edit:

You can't "just like that" get .NET Remoting functionality with WCF.

Here you can read discussion about porting from .NET Remoting to WCF. But if you don't know WCF at all You shoud start here. And You probably won't get your results fast :).

Upvotes: 1

Martin Ernst
Martin Ernst

Reputation: 5679

Afaik .NET doesn't support this out of the box - you can do remoting but that won't (as is) let you run code from the client on the server. I think you would have to implement something that transfers the dll containing the code you want to execute to the server, and then probably load that dll in a separate AppDomain (because you can't unload dll's unless you load them into a separate AppDomain), and then have a way to specify the class to run.

Upvotes: 2

Related Questions