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

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.

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.

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

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

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.

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

Related

COM/ActiveX DLL to consume WCF service

I am trying to extend an application which supports COM/ActiveX objects. The COM dll needs to send some data to other system on local network for further processing and actions.
I have tested a basic WCF Host-Client setup and it works fine from console client to console host. But now I need to send data through a client in com-visible dll.
This is the code of the dll :
namespace Client
{
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]
[ComVisible(true)]
public interface ISend
{
[DispId(1)]
bool SendData(string msg);
}
[ClassInterface(ClassInterfaceType.None), Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"), ProgId("Client.Send")]
[ComVisible(true)]
public class Send : ISend
{
static BasicHttpBinding binding = new BasicHttpBinding();
static EndpointAddress endpoint = new EndpointAddress(new Uri("http://192.168.1.6:8000/WCFHost/Service/GetData"));
GetDataClient client = new GetDataClient(binding, endpoint);
[ComVisible(true)]
public bool SendData(string msg)
{
try
{
if (client.getData(msg))
{
client.Close();
return true;
}
else
{
client.Close();
return false;
}
}
catch (Exception e)
{
client.Abort();
return false;
}
}
}
}
The dll works fine as a reference but cannot create object through target application(It has the functionality to access COM/ActiveX objects). When I try to access the dll by :
obj = CreateObject ("Client.Send");
obj.SendData("Hello")
It says :
COM/object handle is null
on second line nothing more!
I created a com-visible dll in similar way using Remoting to achieve this and it worked like a charm. But now its not working as a WCF Client.
It would be really appreciated if someone could point out what I am doing wrong.
I had moved to Remoting where this was not a problem, but I was suggested to stay away from it and achieve this through WCF.
P.S : I am new to C# so please excuse any stupid mistakes.
COM does not support static methods, see here for further details. You'll need to remove the static keyword from the class in order to let your client create an instance. This will also allow you to implement the interface, which is not possible for static classes.
As a side note, your code shouldn't even compile, since the static modifier on an interface is illegal. Remove it as well, then recompile and re-register your DLL.

Remoting SecurityException from dll

I need to test old legacy remoting service.
The code comes with ready to use client side which means I have an object that takes care of all the channeling implementation.
When connecting to this client from executable - everything is good and works great, but when trying to do the same operation using dll (nunit is the test framework) SecurityException is thrown whenever I'm trying to query the service.
Why there is difference using dll code over executable?
This is the error message:
Type System.Runtime.Remoting.ObjRef and the types derived from it
(such as System.Runtime.Remoting.ObjRef) are not permitted to be
deserialized at this security level.
needless to say I have no access to the server side code, but it is .Net 4.5 (although remoting) and the test code is also .Net 4.5, and I must mention I run the code on the same machine
This is the code generates the client side channel
public class RemoteClient
{
public static RemoteClient GenerateClient()
{
SetupHttpChannelAndBuildUrl();
cm_remote obj = null;
try
{
obj = (cm_remote) Activator.GetObject(typeof (cm_remote_base), url);
obj.DoSomething();
return obj;
}
catch (Exception e)
{
...
}
}
private static SetupHttpChannelAndBuildUrl()
{
...
}
public void DoSomethig()
{
...
}
}
and this is the both dll and exe code triggering the functionality:
public RemoteClient GetRemoteClient()
{
return RemoteClient.GenerateClient();
}
from exe it returns instance of RemoteClient, from dll returns null

One DLL with two implementations for two applications

I have a DLL with some classes and methods. And two applications using it.
One admin-application that needs almost every method and a client-application that only needs parts of the stuff. But big parts of it are used by both of them. Now I want make a DLL with the admin stuff and one with the client stuff.
Duplicating the DLL and edit things manually everytime is horrible.
Maybe conditional compiling helps me but I dont know how to compile the DLL twice with different coditions in one solution with the three projects.
Is there a better approach for this issue than having two different DLLs and manually editing on every change?
In general, you probably don't want admin code exposed on the client side. Since it's a DLL, that code is just waiting to be exploited, because those methods are, by necessity, public. Not to mention decompiling a .NET DLL is trivial and may expose inner-workings of your admin program you really don't want a non-administrator to see.
The best, though not necessarily the "easiest" thing to do, if you want to minimize code duplication, is to have 3 DLLs:
A common library that contains ONLY functions that BOTH applications use
A library that ONLY the admin application will use (or else compile it straight into the application if nothing else uses those functions at all)
A library that ONLY the client application will use (with same caveat as above)
A project that consists of a server, client, and admin client should likely have 3-4 libraries:
Common library, used by all 3
Client library, used by client and server
Admin library, used by server and admin client
Server library, used only by server (or else compile the methods directly into the application)
Have you considered using dependency injection on the common library, some form of constructor injection to determine the rules that need to be applied during execution.
Here's a very simple example:
public interface IWorkerRule
{
string FormatText(string input);
}
internal class AdminRules : IWorkerRule
{
public string FormatText(string input)
{
return input.Replace("!", "?");
}
}
internal class UserRules : IWorkerRule
{
public string FormatText(string input)
{
return input.Replace("!", ".");
}
}
public class Worker
{
private IWorkerRule Rule { get; set; }
public Worker(IWorkerRule rule)
{
Rule = rule;
}
public string FormatText(string text)
{
//generic shared formatting applied to any consumer
text = text.Replace("#", "*");
//here we apply the injected logic
text = Rule.FormatText(text);
return text;
}
}
class Program
{
//injecting admin functions
static void Main()
{
const string sampleText = "This message is #Important# please do something about it!";
//inject the admin rules.
var worker = new Worker(new AdminRules());
Console.WriteLine(worker.FormatText(sampleText));
//inject the user rules
worker = new Worker(new UserRules());
Console.WriteLine(worker.FormatText(sampleText));
Console.ReadLine();
}
}
When run you'll produce this output.
This message is *Important* please do something about it?
This message is *Important* please do something about it.

How to keep an object “persistent” in a C# dll?

I have written a dll in C#, offering a class for use. The dll is called by a C program that I have written. (It’s a plugin to some program. I have to write the plugin’s code in C, but I want to use the functionality of .NET, therefore the dll).
In the dll, I want to open up a stream and do other stuff that should be persistent between two calls to the dll. That is represented in the following code by the private member Connector.
namespace myCSharpDll
{
// the c++ program calls this methods
public interface IAccess
{
double Initialize();
double Timestep(double time, double[] values);
...
}
// E is the beginning of another program my dll should connect to, therefore the names
public class EAccess : IAccess
{
// EConnector is another class I defined in the same dll
private EConnector Connector;
public double InitializeE()
{
Connector = new EPConnector();
}
public double Timestep(double time, double[] values)
{
return Connector.Connect();
}
When I make a call to InitializeE() and later one to Timestep() the Connector oject points to NULL.
What do I have to do that when I call Timestep() from my C code, that I can access the before created instance of Connector?
I probably search in the wrong direction at all. Any tips are appreciated.
If I am not wrong you want to maintain a single object throughout the use of dll in c. If that is the case try something similar to singleton pattern.
http://en.wikipedia.org/wiki/Singleton_pattern
What singleton emphazises is you create only single object for a class and use it to perform all the work you need. Basically you might need a function that does something like this,
public class EAccess : IAccess
{
private static EConnector Connector
public EConnector getConnector(){
if(Connector == null){
Connector = new EConnector();
}
return Connector;
}
public double Timestep(double time, double[] values)
{
return getConnector().Connect();
}
};
Even though this is not the traditional way of doing things using singleton but I think it still does the work. I may be wrong. Please correct me if I have misunderstood something.
Thanks SLaks for asking for my C/C++ code. That is where the problem was located. It was simpler than I thought. I found the mistake while putting together the code to show you.
I know that C and C++ is not the same, the plugin structure is just a little weird. Most of the code was generated by a wizard. I just had to fill in my code. It's a cpp file, but the code seems to be C. Well, I think that is off topic.
Here it is, I extraced the most important lines.
// the dll is connected via COM, using the type library file that regasm generated
#import "[path]\myCSharpDll.tlb" raw_interfaces_only
using namespace myCSharpDll;
static void OnActivate (IfmDocument, Widget);
//off topic: this are the weird lines the wizard put in my way
#ifdef __cplusplus
extern "C"
#endif /* __cplusplus */
// when the plugin is called by the host program, this function is called
static void OnActivate (IfmDocument pDoc, Widget button)
{
InitializeIntermediate(pDoc);
Timestep1(...);
}
static void InitializeIntermediate(IfmDocument pDoc)
{
// Initialize COM.
HRESULT hr = CoInitialize(NULL);
IEPAccessPtr pIEPAccess(__uuidof(EPAccess));
double result = -1;
pIEPAccess->InitializeEP (&result);
...
}
static void Timestep1(...)
{
IEPAccessPtr pIEPAccess(__uuidof(EPAccess));
double result = -1.1;
pIEPAccess->Timestep (...);
...
// now I get a wrong result back here, because this call leads to nowhere as
// the connector object in the dll is void
}
I realized that I am requesting a second instance with that line
IEPAccessPtr pIEPAccess(__uuidof(EPAccess));
So I changed that pointer to one single instance and everything is fine. Thanks for your comments!

Remote executing of Action<> or Func<> objects

I wanted to transfer (and execute) an Action or Func object from a C# client to a C# server application using WCF.
Here's my code:
[ServiceContract]
interface IRemoteExecuteServer
{
[OperationContract]
void Execute(Action action);
}
class RemoteExecuteServer : IRemoteExecuteServer
{
public void Execute(Action action)
{
action();
}
}
Servercode:
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(typeof(RemoteExecuteServer), new Uri("net.tcp://localhost:8000")))
{
host.AddServiceEndpoint(typeof(IRemoteExecuteServer), new NetTcpBinding(), "RES");
host.Open();
Console.WriteLine("Server is running!");
Console.WriteLine("Press any key to exit...");
Console.ReadKey(true);
host.Close();
}
}
}
Clientcode:
class Program
{
static void Main(string[] args)
{
IRemoteExecuteServer server = new ChannelFactory<IRemoteExecuteServer>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8000/RES")).CreateChannel();
server.Execute(delegate()
{
Console.WriteLine("Hello server!");
});
}
}
When executing the line "server.Execute" I get a CommunicationException.
Does anyone know how to fix this error?
Thanks for your help!
I would think of two solutions, both being pretty crazy in their nature. Mainly because your request of sending code to server for execution is nothing people do every day (and I think noone ever did something like that).
DLL solution:
Compile your code into separate DLL. Send this DLL as stream to server. Load some class with interface using reflection on server from this DLL. Then you can run code in created class.
Code solution:
Basicaly same as first one, but instead of sending precompiled DLL, you just send your code as string and then use programatic C# compiler to compile and run that code.
But you still cant extract your code from any function. And remember Action is nothing more than delegate (reference) for hard-coded function in your assembly.
I want to be able to use a lambda expression to specify a range of values to return over a wcf service
is a similar question i asked.
I link you too it as eric lippert showed how such a solution would be possible.
However its a decent amount of work.
There may be existing solutions out there, I know not. (There are some pretty nifty run-time byte-code injection/manipulation tools available, so...)
But given sufficient permissions (and level of trust! -- that's a big one) one can compile-on-the-fly and/or send various self-evaluation expressions across the network (this is different than sending byte-code, per-se, although that could theoretically be done if the byte-code or an equivalent can be extracted).
The approaches above wouldn't be sending an Action<...>, which would require byte-code extraction for serialization (including capturing the context, if any), but rather something like Compiling C# on the Fly which you can follow to an interesting discussion and finally find CodeDOM.
On the other hand, LINQ "gets about" the issue of byte-code extraction/de-compilation with the use of Expression trees. Note that it doesn't send over byte-code, but rather uses this method to allow remote execution of expression trees (a common one being an SQL query).

Categories

Resources