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).
Related
This is my first Topic here and I didn't find any similar Topics so I try to describe my problem as good as I can:
I was ordered by my Company to create a modular C# program to assist our Software Developers with Background tasks. The Programm is composed of a Windows Forms application with a User Interface that calls external DLLs that do the actual work. All These DLLs are written by me aswell and follow certain rules to make them compatible to the Main App. That way I can easily add new funcions to the Programm just by putting the DLL into a predefined Folder. So to say Plug-and-Run
The main program contains a ListBox that shows all available PlugIns and if one get's selected and the "start" button is clicked, the Main program calls the corresponding DLL and Invokes the method "program" that starts the DLLs actual function. Furthermore the Main contains a method "Output" that is supposed to write the result of every PlugIn into a Tab of my TabControl. That way the results of every PlugIn running in separate threads can be viewed independently. The Access to the tab already has a delegate to make it threadsafe. The Information is gathered by invoke from the PlugIn's own "returnOutput" method that simply Returns a List of strings containing the results to the Main.
My Problem now is: How can i implement a Kind of a callback into my PlugIn DLLs so they can order the Main Program to gather the results at any time?
My first idea was to simply add the result as return values to the "program" method itself but that would make the Information only available at the end of the program and some of the Tasks require a "live update" during runtime.
My second idea was to use the delegate for the Control as Parameter and pass it to the PlugIn so the PlugIn DLL could Access the Control on it's own. This idea failed because the DLL doesn't "know" the Main program and can't Access it's Methods or the delegates instance so I am Always missing a reference.
Is there a way to solve my problem? If necessary I can provide Code snippets but the program has already around 800 lines of Code and each PlugIn adds a few hundred more..
Thanks in advance for every answer and sorry for my non-native english :D
Best Regards
Gerrit "Raketenmaulwurf" M.
Edit: I am using SharpDevelop 5.1
Code Snippet for the DLL call:
PlugIn = PlugIns.SelectedItem.ToString();
Assembly PlugInDLL = Assembly.LoadFile(#PlugInOrdner+"\\"+PlugIn+".dll");
Object Objekt = PlugInDLL.CreateInstance("DLL.PlugIn");
MethodInfo Info1 = Objekt.GetType().GetMethod("Programm");
Info1.Invoke(Objekt, new Object[]{Projekt, TIAInstanz});
it basically Looks for a DLL file that has the same Name as the highlighted item in the ListBox
There are many different ways to do this. Some of the suggestions in the comments are really good and implementing them would make a robust and extendable solution.
If you are looking for a quick and easy way to get messages from your plugins, though, then you can pass your callback directly to the plugin as an Action:
public class PluginRunner
{
public class PluginMessageEventArgs
{
public string Text { get; set; }
}
public event EventHandler<PluginMessageEventArgs> PluginMessage;
public void Run( string pluginPath )
{
Assembly PlugInDLL = Assembly.LoadFile(pluginPath);
Object Objekt = PlugInDLL.CreateInstance("DLL.PlugIn");
MethodInfo Info1 = Objekt.GetType().GetMethod("Programm");
Info1.Invoke(Objekt, new Object[] { Projekt, TIAInstanz, new Action<string>(Log) });
}
private void Log(string s)
{
PluginMessage?.Invoke(this, new PluginMessageEventArgs { Text = s });
}
}
so you can use it like:
var path =
Path.Combine(
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
"Plugins",
"MyAwesomePlugin.dll");
var pr = new PluginRunner();
// be aware that your event delegate might be invoked on a plugin's thread, not the application's UI thread!
pr.PluginMessage += (s,e) => Console.WriteLine("LOG: " + e.Text);
pr.Run(path);
then your plugin's Programm method writes its logs:
public void Programm( ProjektClass p0, TIAClass p1, Action<string> log )
{
Task.Run(() =>
{
// do something
log.Invoke("here am I!");
// do something else
log.Invoke("here am I again!");
// do something more
});
}
I must admit, that this is not the ideal way to deal with messaging. There are far better (and, unfortunately, more complicated to implement) solutions out there. This one is fairly simple though. Just don't forget that you receive your message on the same thread that have sent it and avoid deadlocks.
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.
I want to write a helper function start that starts pool threads for me but also adds some code before the actual background processing starts in the very same pool thread. So the background thread must do some extra work. I would call start very often and the extra code might change. So I wanted create a kinda factory for pool threads.
Would that be even possible ? If yes, how would I "inject" code into threads ?
I tried this:
class Program
{
private static void test()
{
Console.WriteLine("hello world");
}
private static void start1(Action param1)
{
ThreadPool.QueueUserWorkItem(o =>
{
// extra work is here
param1.Invoke(); // starts another subthread ?
});
}
private static void start2(WaitCallback param1)
{
ThreadPool.QueueUserWorkItem(param1);
}
static void Main(string[] args)
{
start1(new Action(test));
start2(o => { test(); });
Console.ReadKey();
}
}
ThreadPool.QueueUserWorkItem(o =>
{
ExtraWork();
param1.Invoke();
});
is equivalent to
ThreadPool.QueueUserWorkItem(o =>
{
ExtraWork();
param1();
});
Invoking a delegate does not start a new thread. (Why do you think it might?) So this code works just fine as it is. It will invoke the two functions sequentially.
You cannot add random. net code to run by string value. Unless you play with compiler and take the code, compile it into a DLL then call it with reflection i don't see how it can be done. If that's what you need i am scared to ask how the hell you need to do that.
If you do not require to have random code but specific functions well it's your lucky day. Functions can be pass as parameters. you can also build a list of function to get called in order and do it. That you will need to do more search on that, i haven't done this in years. Or maybe fellow stacker can comment and add link to nice article.
If the code need to be randomly generated and is not forced to be .net, example listing file in directory, opening program. Well you can look into scripting language. Worst case you can build a .vbs (Visual Basic Script) dynamically and run it. Then wait for it to create a text file for the results and read it to know what happened.
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).
I'm writing a windows service application, which will be accessed through .NET Remoting.
The problem is I can't figure out how to access service objects from remotable class.
For example, I've a handler class:
class Service_console_handler
{
public int something_more = 20;
//some code...
TcpChannel serverChannel = new TcpChannel(9090);
ChannelServices.RegisterChannel(serverChannel);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemoteObject), "RemoteObject.rem",
WellKnownObjectMode.Singleton);
//from here on RemoteObject is accessible by clients.
//some more code doing something and preparing the data...
}
And I've a remotable class:
public class RemoteObject : MarshalByRefObject
{
private int something = 10;
public int Get_something()
{
return something;
}
}
Clients can access data in RemoteObect with no problem. But how can I access Service_console_handler object (i.e. to retrieve useful info from something_more)?
Sorry for dumb questions and thanks in advance.
What you want is somehow to access the instance of ServiceConsoleHandler via a RemoteObject instance, which is visible for the client.
For this you need to consider two things: (1) Get control over the object construction of the RemoteObject instance and make it accessible and (2) modify ServiceConsoleHandler so it can be accessed remotely.
(1)
How would you construct a RemoteObject instance in ServiceConsoleHandler, if you don’t need to consider remoting?
I guess you would do something like this:
class ServiceConsoleHandler
{
…
RemoteObject remoteObject = new RemoteObject();
// now assume that you also already have
// modified the RemoteObject class so it can hold
// a reference to your server:
remoteObject.Server = this;
…
}
It would be nice if you could make this object accessible for the client. You can do this by using RemotingServices.Marshal instead of RemotingConfiguration.RegisterWellKnownServiceType:
class ServiceConsoleHandler
{
…
TcpServerChannel channel = new TcpServerChannel(9090);
ChannelServices.RegisterChannel(channel, true);
RemoteObject remoteObject = new RemoteObject();
remoteObject.Server = this;
RemotingServices.Marshal(remoteObject, "RemoteObject.rem");
…
}
(2)
If you execute the code right now and access the remoteObject.Server in the client code you would get some remoting exception, because the class ServiceConsoleHandler cannot be accessed remotely. Therefore you need the add the [Serializable] attribute:
[Serializable]
class ServiceConsoleHandler
{ … }
Reason: Types which should be accessed remotely, need to be marshaled to some special transferrable representation. This way they can be squeezed through the TCP port and transferred via the TCP protocol. Basic data types can by marshaled by the framework, so you don't need to think about them. For custom types you will need to state, how to do this. One way to do this is by subclassing from MarshalByRefObject. That’s exactly what you have already done with RemoteObject. Another way is to mark your custom classes as [Serializable] as shown above.
That’s it. Now you should be able to access the server’s field in the client code. Note that you don’t need your existing code for object activation:
TcpClientChannel channel = new TcpClientChannel();
ChannelServices.RegisterChannel(channel, true);
RemoteObject remoteObject = (RemoteObject)Activator.GetObject(
typeof(RemoteObject), "tcp://localhost:9090/RemoteObject.rem");
Console.WriteLine(remoteObject.Server.SomethingMore);
For me .NET remoting is full of funny surprises and sleepless nights. To counter this, make yourself familiar with the remoting concepts (which are from my point of view poorly documented). Dig into the serialization concept (MarshalByRefObject vs. [Serializable]). If you want to make a production code out of it, think a very good ways to handle remoting exceptions. Also consider multithreading. There could be more than one client using this remote object at once.
Have fun!
Thank you! I very much appreciate thoroughness and clarity of you answer.
Most bizzare thing is that I didn't even know that you can publish object instance. About a dozen simple tutorials I studied proposed RemotingConfiguration.RegisterWellKnownServiceType as only method to do remoting. Stupid me.
Now remoting looks much more useful to me. I just wrote a quick test application and it worked. Thanks again.