I had a need to call some modern code from an old .net framework 4.0 application.
What I came up with is communicating with a console application using named pipes and a JSON based protocol.
Server Code:
using System.IO.Pipes;
namespace core_connector
{
internal class Program
{
static int Main(string[] args)
{
string pipename = "testpipe";
if (args.Length > 0)
{
pipename = args[0];
}
using NamedPipeServerStream pipeServer =
new NamedPipeServerStream(pipename, PipeDirection.InOut, 1);
int threadId = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("Server waiting for client connection on pipe '{0}'", pipename);
pipeServer.WaitForConnection();
Console.WriteLine("Client connected on thread[{0}].", threadId);
try
{
var ss = new PipeProtocol(pipeServer);
ss.WriteObject(new HelloResponse($"Welcome to #{pipename}"));
bool QuitRequest = false;
while (pipeServer.IsConnected && !QuitRequest)
{
Console.WriteLine("Waiting for client...");
var response = ss.ReadPayload();
switch (response.payloadtype)
{
case MessageTypes.Greet:
Thread.Sleep(3 * 1000);
ss.WriteObject(new GreetResponse("Well Met Client"));
break;
case MessageTypes.SumTheseNums:
var req = response.ReadAs<SumTheseNumsRequest>();
var result = req.Number1 + req.Number2;
Thread.Sleep(2 * 1000);
ss.WriteObject(new SumTheseNumsResponse(result));
break;
case MessageTypes.Quit:
Console.WriteLine($"Client Quit");
QuitRequest = true;
break;
default:
break;
}
}
return 0;
}
catch (IOException e)
{
// Catch the IOException that is raised if the pipe is broken
// or disconnected.
Console.WriteLine("ERROR: {0}", e.Message);
return -1;
}
finally
{
pipeServer.Close();
}
}
}
}
Protocol, that is shared between both.
using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;
namespace core_connector
{
public class PipeProtocol
{
private Stream ioStream;
private Encoding streamEncoding;
private BinaryWriter binwriter;
private BinaryReader binreader;
public PipeProtocol(Stream ioStream)
{
this.ioStream = ioStream;
this.streamEncoding = UnicodeEncoding.Unicode;
this.binwriter = new BinaryWriter(ioStream, streamEncoding);
this.binreader = new BinaryReader(ioStream, streamEncoding);
}
private void WritePayload(MessageTypes payloadtype, byte[] outBuffer)
{
this.binwriter.Write((int)payloadtype);
this.binwriter.Write(outBuffer.Length);
this.binwriter.Write(outBuffer);
this.binwriter.Flush();
}
public Payload ReadPayload()
{
var p = new Payload(this.streamEncoding);
p.payloadtype = (MessageTypes)this.binreader.ReadInt32();
var len = this.binreader.ReadInt32();
p.payload = this.binreader.ReadBytes(len);
return p;
}
public class Payload
{
private Encoding streamEncoding;
public MessageTypes payloadtype;
public byte[] payload;
public Payload(Encoding enc)
{
this.streamEncoding = enc;
}
public T ReadAs<T>()
{
var json = streamEncoding.GetString(this.payload);
var ob = JsonConvert.DeserializeObject<T>(json);
return ob;
}
}
public void WriteObject<T>(T ob) where T : MessageBase
{
var json = JsonConvert.SerializeObject(ob);
byte[] outBuffer = streamEncoding.GetBytes(json);
this.WritePayload(ob.MessageType, outBuffer);
}
public TReply RequestReply<TReq, TReply>(TReq ob)
where TReq : RequestBase
where TReply : ResponseBase
{
this.WriteObject(ob);
var payload = this.ReadPayload();
if (payload.payloadtype != ob.MessageType)
{
throw new Exception(string.Format("Unexpected Reply - expected {0} received {1}", ob.MessageType, payload.payloadtype));
}
var resp = payload.ReadAs<TReply>();
return resp;
}
} //PipeProtocol
public enum MessageTypes
{
Hello,
Greet,
SumTheseNums,
Quit
}
public class MessageBase
{
public MessageTypes MessageType { get; set; }
}
public class RequestBase : MessageBase
{
}
public class ResponseBase : MessageBase
{
public bool Success { get; set; } = true;
public string ErrorMsg { get; set; }
}
public class GreetRequest : RequestBase
{
public GreetRequest()
{
this.MessageType = MessageTypes.Greet;
}
}
public class GreetResponse : ResponseBase
{
public string GreetingMessage { get; set; }
public GreetResponse(string msg)
{
this.MessageType = MessageTypes.Greet;
this.GreetingMessage = msg;
}
}
public class HelloResponse : ResponseBase
{
public string HelloMessage { get; set; }
public HelloResponse(string msg)
{
this.MessageType = MessageTypes.Hello;
this.HelloMessage = msg;
}
}
public class QuitRequest : RequestBase
{
public QuitRequest()
{
this.MessageType = MessageTypes.Quit;
}
}
public class SumTheseNumsRequest : RequestBase
{
public int Number1 { get; set; }
public int Number2 { get; set; }
public SumTheseNumsRequest(int Num1,int Num2)
{
this.MessageType = MessageTypes.SumTheseNums;
this.Number1 = Num1;
this.Number2 = Num2;
}
}
public class SumTheseNumsResponse : ResponseBase
{
public int SumResult { get; set; }
public SumTheseNumsResponse(int result)
{
this.MessageType = MessageTypes.SumTheseNums;
this.SumResult = result;
}
}
}
Client code (old .net framework) that starts the new code process and communicates with it.
using core_connector;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Pipes;
using System.Security.Principal;
using System.Threading;
namespace core_connector_client
{
internal class Program
{
static Process StartServer(string pipename)
{
var fn = @"C:\app\core_connector.exe";
Process myProcess = new Process();
bool Debug = false;
if (Debug)
{
myProcess.StartInfo.UseShellExecute = true;
myProcess.StartInfo.CreateNoWindow = false;
}
else
{
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardError = true;
}
myProcess.StartInfo.FileName = fn;
myProcess.StartInfo.Arguments = pipename;
myProcess.Start();
return myProcess;
}
static void Main(string[] args)
{
string pipename = "MEGAPIPE-3K";
var serverProc = StartServer(pipename);
var pipeClient =
new NamedPipeClientStream(".", pipename,
PipeDirection.InOut, PipeOptions.None,
TokenImpersonationLevel.Anonymous);
Console.WriteLine("Connecting to server...\n");
pipeClient.Connect();
var ss = new PipeProtocol(pipeClient as Stream);
Console.WriteLine("Waiting for server...");
var hello_back = ss.ReadPayload().ReadAs<HelloResponse>();
Console.WriteLine($"Server says Hello With '{hello_back.HelloMessage}'");
Console.WriteLine("Greet server");
var greet_resp = ss.RequestReply<GreetRequest, GreetResponse>(new GreetRequest());
Console.WriteLine($"Server says in Greeting '{greet_resp.GreetingMessage}'");
Console.WriteLine("waiting 3 secs");
Thread.Sleep(3 * 1000);
Console.WriteLine("Sum These Numbers");
var sum_resp = ss.RequestReply<SumTheseNumsRequest,SumTheseNumsResponse>(new SumTheseNumsRequest(7,4));
Console.WriteLine("Result:{0}",sum_resp.SumResult);
ss.WriteObject(new QuitRequest());
Console.Write("Cleanup");
pipeClient.Close();
serverProc.Close();
serverProc.Dispose();
Console.Write("Press Enter to continue...");
Console.ReadLine();
}
}
}