发送要在C#中在服务器上执行的代码 – 就像Java RMI一样

这是java中的示例代码。

共享接口:

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

任务(这将作为参数传递):

 import java.io.Serializable; public interface Task extends Serializable { public Object execute(); } 

服务器:

 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?) } } 

客户:

 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 } } 

客户主要:

 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?) } } 

如您所见,来自客户端的代码(不仅仅是数据)被转移到服务器并在那里执行,并返回计算结果。 服务器不知道Pi存在,它只知道Task接口。

我需要这样的东西在.net环境中工作(C#,如果它很重要)。 WCF会很好,但我正在寻找最直接的解决方案,因此WCF不是强制性的。 我甚至不确定使用google documetation或解决方案的关键字。

任何帮助将不胜感激。

.NET本身不支持“发送代码”以在另一台计算机上执行。 通常,必要的代码将被编译为程序集并在客户端调用之前预先安装在服务器上。 对于远程处理和WCF都是如此。 您可能有一个双向远程处理情况,服务器通过WCF回调客户端上的方法,但我怀疑这不是您想要的。 我知道在服务器上真正运行动态代码的唯一方法是生成动态代码,将其作为字符串发送到服务器,然后让服务器动态地将其编译到内存中的程序集,然后执行它。 如果您对此感兴趣,请查看我对类似问题的回答:

自动化属性?

但是,在大多数情况下,这并不是我所建议的。 我建议你重新考虑你的设计,首先,看看有没有办法以典型的“.NET方式”做你需要的东西。

Afaik .NET不支持开箱即用 – 您可以进行远程处理,但不会(按原样)让您从服务器上的客户端运行代码。 我认为你必须实现一些东西,将包含你想要执行的代码的DLL传输到服务器,然后可能将该DLL加载到一个单独的AppDomain中(因为你不能卸载dll,除非你将它们加载到一个单独的AppDomain中) ,然后有办法指定要运行的类。

你想要的是.NET Remoting。 这是指向如何从RMI迁移到.NET Remoting的文章的链接。

但根据这篇MSDN文章,这是一项遗留技术,你应该使用WCF。

编辑:

你不能“只是那样”使用WCF获得.NET Remotingfunction。

在这里,您可以阅读有关从.NET Remoting移植到WCF的讨论。 但是如果你根本不知道WCF那么你应该从这里开始。 你可能不会快速得到你的结果:)。

此MSDN页面或多或少具有您描述的这个确切用例。 您只需要修改ServiceContract

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

您可能只需要修改此部分:

  [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; } 

而不是标量值将executeTask方法与您自己的类的参数放在一起。

我不相信.NET有一个内置的解决方案,可以将可执行代码从客户端传输到服务器。 假设安全约束允许,您可以考虑发送可解释的代码,例如Python或JavaScript,这些代码可以分别通过IronPython或IronJS在服务器端执行。 如果需要C#(并且您仍然可以访问源代码),则发送源代码并编译服务器端(通过Roslyn或Mono的评估程序 )。

Interesting Posts