3

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.

Liam McInroy
  • 4,339
  • 5
  • 32
  • 53
del-boy
  • 3,556
  • 3
  • 26
  • 39

5 Answers5

2

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.

Martin Ernst
  • 5,629
  • 2
  • 17
  • 14
1

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 :).

Grzegorz W
  • 3,487
  • 1
  • 21
  • 21
  • 1
    Thanks. Since .net remoting is legacy, do you have any links how I can use WCF to accomplish same results? – del-boy May 31 '12 at 12:37
  • I don't have a problem with reading documentation, but I would like to know if sending code from client to server to be executed is possible before I spend hours/days makeing it work. I know basic concepts of WCF, but I am not aware if it supports what I need (and other answers suggests that it is not possible). – del-boy May 31 '12 at 12:56
  • @del-boy : Ok. Now I have a question. You don't care about having the same reference in both applications right? It's not like you need this exact functionality (Sharing objects). You just want client to use interface (and not be forced to reference dll with all implementation) and not care about what's going on on server side. RIght? – Grzegorz W May 31 '12 at 13:41
  • You are right, I don't need same reference, I just want server to execute method on class whose instance I sent as parameter. – del-boy May 31 '12 at 13:58
  • But do you need to send any instance at all? If it's just computation you need you can't simply tell your server to make this computation and return result? After all RMI doesnt do that (send instance). It just simulate it by remotely calling object method. Am I wrong? – Grzegorz W May 31 '12 at 14:05
  • As far sa I know RMI transferes class to the server, creates new instance of that class that is the same as one on client and executes the code (I think serialization is used to transfer instances). But code definen on client will be executed on server and that is what I need (method can reference class fields - so instances on client and servers should have same values). In .net equivalent would be to send assembly (or part of it with class definition) to server and execute it there. – del-boy May 31 '12 at 14:17
1

.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".

Community
  • 1
  • 1
Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
1

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.

Marino Šimić
  • 7,318
  • 1
  • 31
  • 61
  • Are you sure about this? Before aksing a question I did try to follow this tutorial: http://msdn.microsoft.com/en-us/library/ms734712.aspx and replaced scalar value with instance of my class, but i got CommunicationException and suggestion to implement DataContractResolver, but as far as I know data contract can not send code, so I didn't do that. Does NetNamedPipeBinding provide this functionality? Could you provide working example of this? Thanks. – del-boy May 31 '12 at 14:09
  • You can use the specific class on the contract, not an interface type because the serialization is binary. That is all I know about it. – Marino Šimić May 31 '12 at 14:47
0

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).

Barry Wark
  • 107,306
  • 24
  • 181
  • 206
  • Sending interpretable code is other approach that has its flaws, so I didn't want to consider it just yet. I have an idea to send expression tree and compile it on server to delegate too, but I will think about that if this does not work. Thanks... – del-boy May 31 '12 at 14:41