Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I send a "Message" to another process in .Net, without using SendMessage?

I have multiple applications running on a single machine. One is doing work and writing logs to disk about what it has done (I'll call this WorkerApp) and another that summarizes support information about the status of WorkerApp along with some more details (I'll call this Dashboard).

From the Dashboard i want to instruct the WorkerApp to take an action (say, "Ping remote services") and I would like the WorkerApp to send the Dashboard the "pong" response when it gets it.

I have seen examples of using the SendMessage, but this seems to be pretty archaic (isn't there anything more standard now in 2016 for between process communications?).

I have very little experience with Akka.Net but the Remoting feature of it seem like a good approach, although setting this up seems a little overkill for what I would like to do.

What is the easiest way currently to go about communicating between two processes in .Net? And is there some examples of this, working on a localmachine?

like image 955
XenoPuTtSs Avatar asked Jun 24 '16 12:06

XenoPuTtSs


3 Answers

I put together an Akka.Net example for this. This is what it looks like.

DashBoard (sends messages)

using System;
using Akka.Actor;
using Akka.Configuration;

namespace DashBoard
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = ConfigurationFactory.ParseString(@"
akka {  
    actor {
        provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
    }
    remote {
        helios.tcp {
            transport-class = ""Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote""
            applied-adapters = []
            transport-protocol = tcp
            port = 0
            hostname = localhost
        }
    }
}
");

            using (var system = ActorSystem.Create("Dashboard", config))
            {
                var server = system.ActorSelection("akka.tcp://WorkerApp@localhost:8081/user/WorkerAppActor");
                while (true)
                {
                    var input = Console.ReadLine();
                    server.Tell(input);
                }
            }
        }
    }
}

WorkerApp (receives messages)

using System;
using Akka.Actor;
using Akka.Configuration;

namespace WorkerApp
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = ConfigurationFactory.ParseString(@"
akka {  
    actor {
        provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
    }
    remote {
        helios.tcp {
            transport-class = ""Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote""
            applied-adapters = []
            transport-protocol = tcp
            port = 8081
            hostname = localhost
        }
    }
}
");

            using (var system = ActorSystem.Create("WorkerApp", config))
            {
                system.ActorOf<WorkerAppActor>("WorkerAppActor");

                Console.ReadLine();
            }
        }
    }

    class WorkerAppActor : TypedActor, IHandle<string>
    {
        public void Handle(string message)
        {
            Console.WriteLine($"{DateTime.Now}: {message}");
        }
    }
}
like image 178
XenoPuTtSs Avatar answered Oct 22 '22 18:10

XenoPuTtSs


Have a look at .Net remoting. It's a bit more modern than SendMessage, but not a whole lot. It's pretty easy to use though. I think the official way to do this these days is probably using WCF, but I'm pretty sure it's just the same under the hood.

.Net remoting supports various channels (Http, TCP), but in your case I'd suggest IPC remoting. It sits on top of named pipes.

Probably easiest if you google (.Net remoting), but the general idea is to define a class in your "server" app derived from MarshalByRefObject. Once you've done that, register it with the remoting infrastructure using RemotingConfiguration.RegisterWellKnownServiceType.

Your client app can then create an instance of the class using Activator.CreateObject and then you're good to go.

One thing to be aware of: it looks like you'll want a callback mechanism - so your Dashboard isn't blocked waiting for your WorkerApp. This is supported in .Net remoting, but you'll need to create two channels - one for the outgoing calls (from Dashboard to WorkerApp) and then another for the incoming callbacks.

Another suggestion: your worker class (the one derived from MarshalByRefObject) will be easier to deal with if exposes an interface as well. Put that interface in a DLL available to both apps and life will be easier.

like image 43
Ian of Oz Avatar answered Oct 22 '22 19:10

Ian of Oz


One suggestion may be to use a database or other persistent storage to create a type of 'Queue' which the dashboard can insert tasks into. This could also store statuses about the tasks which can be updated by the worker process. Although this could be considered 'overkill' it brings a vartiety of benefits such as auditing, historical reporting and server crash/power-off redundancy. It would also probably make scaling up the application in the future easier.

like image 1
Milney Avatar answered Oct 22 '22 18:10

Milney