Frage

I want to be able to communicate between a Server-Application and a Client-Application. Both applications are written in C#/WPF. Interfaces are located in a separate DLL where both applications have a reference to it.

In the interface-dll is the IDataInfo-Interface which looks like:

public interface IDataInfo
    {
        byte[] Header { get; }
        byte[] Data { get; }
    }

The Server-Application calls the client by the following code:

Serializer<IDataInfo> serializer = new Serializer<IDataInfo>();
IDataInfo dataInfo = new DataInfo(HEADERBYTES, CONTENTBYTES);
Process clientProcess = Process.Start("Client.exe", serializer.Serialize(dataInfo));

The Client-Applications gets the message from the server by:

Serializer<IDataInfo> serializer = new Serializer<IDataInfo>();
IDataInfo dataInfo = serializer.Deserialize(string.Join(" ", App.Args));

The Serializer-Class is just a generic class which uses the Soap-Formatter to serialize/deserialze. The code looks like:

public class Serializer<T>
{
    private static readonly Encoding encoding = Encoding.Unicode;

    public string Serialize(T value)
    {
        string result;
        using (MemoryStream memoryStream = new MemoryStream())
        {
            SoapFormatter soapFormatter = new SoapFormatter();
            soapFormatter.Serialize(memoryStream, value);
            result = encoding.GetString(memoryStream.ToArray());
            memoryStream.Flush();
        }
        return result;
    }

    public T Deserialize(string soap)
    {
        T result;
        using (MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(soap)))
        {
            SoapFormatter soapFormatter = new SoapFormatter();
            result = (T)soapFormatter.Deserialize(memoryStream);
        }
        return result;
    }
}

Until here everything works fine. The server creates the client and the client can deserialize it's argument to the IDataInfo-Object.

Now I want to be able to send a message from the server to a running client. I Introduced the IClient-Interface in the Interface-DLL with the method void ReceiveMessage(string message);

The MainWindow.xaml.cs is implementing the IClient-Interface.

My Question is now how can I get the IClient-Object in my server, when I just have the Process-Object. I thought about Activator.CreateInstance, but I have no clue how to do this. I'm pretty sure that I can get the IClient by the Handle of the Process, but I don't know how.

Any idea?

War es hilfreich?

Lösung

As the other posts mention a common way is to create a service, too keep it more simple I would consider a look at ServiceStack. AFAIK ServiceStack is used on stackoverflow

There also as course about it on pluralsight

ServiceStack is really easy to host in any .net dll (without iis and so on) and doesn't have the configuration complexity of WCF.

Also endpoints are available as SOAP and REST without the need to configure anything

For Example this defines a hello world service

public class HelloService : IService<Hello>
{
    public object Execute(Hello request)
    {
        return new HelloResponse { Result = "Hello, " + request.Name };
    }
}

Here an example of the client code:

var response = client.Send<HelloResponse>(new Hello { Name = "World!" });
Console.WriteLine(response.Result); // => Hello, World

You can find more complex examples and walk-throughs at: ServiceStack.Hello

Andere Tipps

Communication that between multi processed have many waies to implement. Like socket, fileMapping, share memory, windows 32 message and so on.

Maybe sample way is you can use WCF.

There are many ways to do inter process communication,
but if you are looking for a quick and easy solution you may want to look at ZeroMQ.
WCF is also an option but it might be overkill in your situation.

You can find more information about ZeroMQ here: http://www.zeromq.org/ And you can install it into your project using NuGet.

A quick example with a server and a client:

The server listens for connections, expects a string, reverses the string and returns it:

public class Server
{
    public Server()
    {

    }

    public void Listen()
    {
        Task.Run(() =>
        {
            using (var context = new Context())
            {
                //Open a socket to reply
                using (var socket = context.Socket(SocketType.REP))
                {
                    socket.Bind("tcp://127.0.0.1:32500");
                    while (true)
                    {
                        //Again you could also receive binary data if you want
                        var request = socket.Recv(Encoding.UTF8);
                        var response = ReverseString(request);
                        socket.Send(response, Encoding.UTF8);
                    }
                }
            }
        });
    }

    private string ReverseString(string request)
    {
        var chars = request.ToCharArray();
        Array.Reverse(chars);
        return new string(chars);
    }
}

The client connects to the server (in this case the same machine):

public class Client
{
    public Client()
    {

    }

    public string ReverseString(string message)
    {
        using (var context = new Context())
        {
            //Open a socket to request data
            using (var socket = context.Socket(SocketType.REQ))
            {
                socket.Connect("tcp://127.0.0.1:32500");

                //Send a string, you can send a byte[] as well, for example protobuf encoded data
                socket.Send(message, Encoding.UTF8);

                //Get the response from the server
                return socket.Recv(Encoding.UTF8);
            }
        }
    }
}

To test it, the program might look like this:

public class Program
{
    public static void Main()
    {
        new Program();
    }

    public Program()
    {
        var server = new Server();
        server.Listen();

        var client = new Client();

        var input = String.Empty;

        while (input != "/quit")
        {
            input = Console.ReadLine();
            Console.WriteLine(client.ReverseString(input));
        }
    }

}

It's easy and it gets the job done.

Another alternative is to use named pipes for IPC: http://www.codeproject.com/Tips/492231/Csharp-Async-Named-Pipes

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top