The essence of the question is this:
I have a fat client. I want to manage the operation of this client from the server. The server implements a control panel using the Command pattern, and the client has an extensible set of functions for executing server commands. See the code below.
Suppose the client (the receiver of commands) has a "Run" function, which we will call from the server:
class Receiver { public int Register { get; private set; } public void Run(char operationCode, int operand) { switch (operationCode) { case '+': Register += operand; break; case '-': Register -= operand; break; case '*': Register *= operand; break; case '/': Register /= operand; break; } } } Control panel code implemented on the server:
//"Invoker" (ΠΠ½ΠΈΡΠΈΠ°ΡΠΎΡ (Π²ΡΠ·ΡΠ²Π°ΡΠ΅Π»Ρ ΠΊΠΎΠΌΠ°Π½Π΄)) class Invoker { private List<Command> commands = new List<Command>(); private int current = 0; public void StoreCommand(Command command) { commands.Add(command); } public void ExecuteCommand() { commands[current++].Execute(); } public void Undo(int levels) { for (int i = 0; i < levels; i++) if (current > 0) commands[--current].UnExecute(); } public void Redo(int levels) { for (int i = 0; i < levels; i++) if (current < (commands.Count - 1)) commands[current++].Execute(); } } //"Command" (ΠΠ°ΠΊΠ°Ρ-ΡΠΎ (Π°Π±ΡΡΡΠ°ΠΊΡΠ½Π°Ρ) ΠΊΠΎΠΌΠ°Π½Π΄Π°) abstract class Command { protected dynamic receiver; public Command(dynamic receiver) { this.receiver = receiver; } public abstract void Execute(); public abstract void UnExecute(); } //"ConcreteCommand" (ΠΠΎΠΌΠ°Π½Π΄Π° (ΡΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅), ΠΊΠΎΡΠΎΡΡΡ ΡΠ΅ΡΠ²Π΅Ρ ΠΎΡΠΏΡΠ°Π²ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡ) class ConcreteCommand : Command { int operand; public ConcreteCommand(Receiver receiver, int operand) : base(receiver) { this.operand = operand; } public override void Execute() { receiver.Run('+', operand); } public override void UnExecute() { receiver.Run('-', operand); } } ----------
Tell me, please, how best to implement a method call (for example, "Run") on the side of a fat client:
Make a distributed application by placing the following code in a plugin (application extensible):
class Receiver : MarshalByRefObject { public int Register { get; private set; } public void Run(char operationCode, int operand) { switch (operationCode) { case '+': Register += operand; break; case '-': Register -= operand; break; case '*': Register *= operand; break; case '/': Register /= operand; break; } } } , and on the server just make a call:
public override void Execute() { receiver.Run('+', operand); } But then, on the client, you will have to dynamically connect this plugin. And this means that you have to use slow, resource-intensive reflection. If this problem is solved by creating the following shared assembly:
class ReceiverRef : MarshalByRefObject { public dynamic Ref { get; set; } } and having connected it once, make the following method calls on the server:
public override void Execute() { ReceiverRef receiverRef = new ReceiverRef(); receiverRef.Ref = receiver; receiverRef.Ref.Run('+', operand); } then there is a need to connect the server to the client when the client connects to the server and informs it of its IP and port number. That is, they will have to be swapped, because (as far as I know) in distributed applications, the code is executed on the server side, and I need this code (command) to be executed by my thick client. But then the constant waiting for the client to connect the server will greatly consume the battery power of the device on which it is installed.
Send the name of the method being called as a string to the client:
class ConcreteCommand : Command { int operand; public ConcreteCommand(Server receiver, int operand) : base(receiver) { this.operand = operand; } public override void Execute() { receiver.Send("Receiver.Run", '+', operand); } public override void UnExecute() { receiver.Send("Receiver.Run", '-', operand); } } , and in plugins to place the necessary methods (I remind you that the client is extensible). But then again there is a need to use reflection (and, multiple).
Your ideas.
Thank you in advance.