MessagePack RPC C# - Server side - c#

I have a problem when trying to consume a server implementation of MessagePack RPC. I wrote one implementation for client and one for server based on a Python code provided by my company's client.
The server implementation should be consumed by Python, but as far as I see that won't be a problem.
Server implementation:
public class Program
{
static void Main(string[] args)
{
try
{
DefaultServiceTypeLocator def = new DefaultServiceTypeLocator();
ServiceTypeLocator ser = def;
def.AddService(new Methods().GetType());
var services = ser.FindServices();
var configuration = new RpcServerConfiguration();
IPAddress ipAddress = GetIp();
configuration.BindingEndPoint = new IPEndPoint(ipAddress, 8089);
Console.WriteLine(new IPEndPoint(ipAddress, 8089).ToString());
using (var server = new RpcServer(configuration))
{
server.Start();
Console.ReadKey();
}
}
catch (Exception ex)
{
Console.Write(ex);
Console.ReadKey();
}
}
[MessagePackRpcServiceContractAttribute]
public class Methods
{
[MessagePackRpcMethodAttribute]
public int hello0()
{
Console.WriteLine("hello0");
return 0;
}
}
Client implementation:
public class Program
{
static void Main(string[] args)
{
try
{
var configuration = new RpcClientConfiguration();
IPAddress ipAddress = GetIp();
using (dynamic proxy = new DynamicRpcProxy(new IPEndPoint(ipAddress, 8089), configuration))
{
dynamic res = proxy.hello0();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.ReadKey();
}
}
private static IPAddress GetIp()
{
string myHost = System.Net.Dns.GetHostName();
IPAddress myIP = null;
for (int i = 0; i <= System.Net.Dns.GetHostEntry(myHost).AddressList.Length - 1; i++)
{
if (System.Net.Dns.GetHostEntry(myHost).AddressList[i].IsIPv6LinkLocal == false)
{
if (System.Net.Dns.GetHostEntry(myHost).AddressList[i].AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
myIP = System.Net.Dns.GetHostEntry(myHost).AddressList[i];
}
}
return myIP;
}
}
My client can't connect to my server, it can't see the methods over there. The error is: "operation does not exist".
Anyone has any clue?
Thank you!!

Well after many tries and many help from friends, I finally managed to fix the issue.
First of all you have to download the Message Pack RPC solution here and create your new project (server or client) inside this solution. In my case the server didn’t work when I created a new solution and referenced the dlls, only inside the whole project. The client worked only referencing the dlls.
Implementation for the Server Side:
internal class Program
{
public static void Main(string[] args1)
{
var config = new RpcServerConfiguration();
config.BindingEndPoint = new IPEndPoint(IPAddress.Loopback, 8089);
config.PreferIPv4 = true;
config.IsDebugMode = true;
//UseFullMethodName is a property that if it is false allows you in the CLIENT to call the methods only by it's name, check example further.
config.UseFullMethodName = false;
var defaultServiceTypeLocator = new DefaultServiceTypeLocator();
//Methods is the class I created with all the methods to be called.
defaultServiceTypeLocator.AddService(typeof(Methods));
config.ServiceTypeLocatorProvider = conf => defaultServiceTypeLocator;
using (var server = new RpcServer(config))
{
server.Start();
Console.ReadKey();
}
}
[MessagePackRpcServiceContract] //Define the contract to be used
public class Methods
{
[MessagePackRpcMethod] //Define the methods that are going to be exposed
public string Hello()
{
return "Hello";
}
[MessagePackRpcMethod]
public string HelloParam(string i)
{
return "Hello " + i;
}
}
 
Implementation for the Client Side:
static void Main(string[] args)
{
using (var target = CreateClient())
{
//var result1 = target.Call("Hello:Methods:0", null); /*if in the server the property UseFullMethodName is true, or not defined as false (default is true) you have to call the method on the server using *methodname:class:version**/
var result2 = target.Call("Hello", null); //Parameter is null
var result3 = target.Call("HelloParam", “Mariane”);//Method with parameter
}
}
public static RpcClient CreateClient()
{
return new RpcClient(new IPEndPoint(IPAddress.Loopback, 8089), new RpcClientConfiguration() { PreferIPv4 = true });
}
I hope this is clear and help you guys to fix it. Don’t forget to set the methods as public on the server. Thanks to https://github.com/yfakariya /msgpack-rpc-cli/issues/6 that answered my question. Really special thanks to #DanielGroh that spent some time with me trying to fix it and Gilmar Pereira which has no profile here but is a great developer and helped me a lot (https:// www. facebook .com/ gilmarps?fref=ts).

Related

What is the equivalent of Kotlin WebSocketSession object in c#?

For a few months now I have been using the ktor framework to create servers that expose rest calls and communication via webSockets. For now I have always used clients using kotlin as a programming language (or Android App, or App Desktop).
Specifically, I had a class that was injected with the HttpClient object (from the documentation = Asynchronous client to perform HTTP requests).
Within this class I have 4 methods:
start the session: instantiate the WebSocketSession object (Represents a web socket session between two peers)
send Frame
receives Frame
close the session
In Ktor my class is something that looks a lot like this:
class WebSocketServiceImpl(
private val client: HttpClient
){
private var socket: WebSocketSession? = null
//1)
suspend fun initSession(username: String): Resource<Unit>{
socket = client.webSocketSession {
url("ws://xxx.xxx.xxx.xxx:xxxx/myRoute?username=$username")
}
//2)
suspend fun send(myObj: MyObj) {
try {
val myObjSerialized = Json.encodeToString(myObj)
socket?.send(Frame.Text(myObjSerialized ))
} catch (e: Exception) {
e.printStackTrace()
}
}
//3)
fun observePrintableMessages(): Flow<MyObj> {
return try {
socket?.incoming
?.receiveAsFlow()
?.filter { it is Frame.Text }
?.map {
val myObjString = (it as? Frame.Text)?.readText() ?: ""
val printableMessageDto = Json.decodeFromString<MyObj>(myObjString)
} ?: flow { }
} catch (e: Exception) {
e.printStackTrace()
flow { }
}
}
//4)
suspend fun closeSession() {
socket?.close()
}
}
From the C # documentation instead, I found these examples on how to use Client-side WebSockets:
//1)
const exampleSocket = new WebSocket("wss://www.example.com/socketserver", "protocolOne");
//2)
exampleSocket.send("Here's some text that the server is urgently awaiting!");
//3)
exampleSocket.onmessage = (event) => {
console.log(event.data);
}
//4)
exampleSocket.close();
Admitted and not granted that the methods I found in C # really work, to make the WebSocket object used in C # be equivalent to the WebSocketSession object in Kotlin is enough for me to do so? :
public void initSession(string username)
{
exampleSocket = new WebSocket($"wss://www.example.com/socketserver?username={username}", "");
}
Or is it some other type of object to use?
If for any reason you don't know the answer, you don't need to vote negative, you can just move on.
I used the Websocket.Client library (by Mariusz Kotas) found on NuGet
public class WebSocketService : IWebSocketService
{
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
private void FireMessageReceivedEvent(Message message) => MessageReceived?.Invoke(this, new MessageReceivedEventArgs(message));
public string Url { get => "ws://192.168.1.202:8082/chat-socket"; }
private WebsocketClient webSocketClient;
public async Task<SessionResoult> InitSession(string username)
{
string usernameSession = $"?username={username}";
string urlWithUsername = $"{Url}{usernameSession}";
try
{
webSocketClient = new WebsocketClient(new Uri(urlWithUsername));
await webSocketClient.Start();
if (webSocketClient.IsRunning)
{
SubscribeNewMessages();
return new SessionResoult.Success();
}
else
{
return new SessionResoult.Error("webSocketClient is not running");
}
}
catch(Exception ex)
{
return new SessionResoult.Error(ex.Message);
}
}
private void SubscribeNewMessages()
{
webSocketClient.MessageReceived.Subscribe(m =>
{
MessageDto message = JsonConvert.DeserializeObject<MessageDto>(m.Text);
FireMessageReceivedEvent(message.ToMessage());
});
}
public async Task SendMessageAsync(string message)
{
await Task.Run(() => webSocketClient.Send(message));
}
public void CloseSession()
{
webSocketClient.Dispose();
}
}
In the code, the interesting parts are:
1) initialization of the WebsocketClient object
2) the subscription of receiving messages ( Start() method immediately after initialization)
3) observation of message subscription -> webSocketClient.MessageReceived.Subscribe
4) the 'Fire' of the event linked to the observation of messages -> FireMessageReceivedEvent
5) those who use the class must subscribe to the event of the latter ->
webSocketService.MessageReceived + = (sender, e) => {OnMessageReceived (e.MessageReceived); };
MessageReceivedEventArgs -> Class describing the Arguments of the event
SessionResoult -> Class similar to an Enum but with the possibility of passing a string or not based on which subclass it is

Router with remote actors in akka.net

I'm trying to create sample router with two remote actors.
Here's my code
class Program
{
public const string AkkaConfig = #"{
akka {
actor {
provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
deployment {
/remoteecho1 {
remote = ""akka.tcp://Target#my1.lan:8090""
}
/remoteecho2 {
remote = ""akka.tcp://Target#my2.lan:8090""
}
}
remote{
helios.tcp{
port = 0
hostname = localhost
}
}
}
}";
static void Main(string[] args)
{
using (var system = ActorSystem.Create("Deployer", AkkaConfig))
{
var remoteEcho1 = system.ActorOf(Props.Create(() => new EchoActor()), "remoteecho1");
var remoteEcho2 = system.ActorOf(Props.Create(() => new EchoActor()), "remoteecho2");
var roundRobinGroup = new RoundRobinGroup(new[]
{
remoteEcho1,
remoteEcho2
});
var coordinator = system.ActorOf(Props.Empty.WithRouter(roundRobinGroup),"coordinator");
system.ActorOf(Props.Create(() => new HelloActor(coordinator)), "localactor");
system.ActorSelection("/user/localactor").Tell(new SayHelloMessage());
Console.ReadKey();
}
}
}
public class HelloActor:ReceiveActor
{
private readonly IActorRef remoteActor;
public HelloActor(IActorRef remoteActor)
{
this.remoteActor = remoteActor;
Context.Watch(remoteActor);
Receive<HelloMessage>(m =>
{
Console.WriteLine("Pingback from {1}: {0}", m.MessageText, Sender.Path);
});
Receive<SayHelloMessage>(m =>
{
var newMessage = new HelloMessage(Guid.NewGuid().ToString());
remoteActor.Tell(newMessage);
});
}
protected override void PreStart()
{
Context.System.Scheduler.ScheduleTellRepeatedlyCancelable(TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(1), Context.Self, new SayHelloMessage(), ActorRefs.NoSender);
}
}
public class SayHelloMessage
{
}
The problem is that remoteActor.Tell(newMessage) in the code below doesn't send message to my actor
Receive<SayHelloMessage>(m =>
{
var newMessage = new HelloMessage(Guid.NewGuid().ToString());
remoteActor.Tell(newMessage);
});
When I pass remoteEcho actor to HelloActor constructor instead of router instance everything works fine. How to make that example work with Router?

Disposing thrift client - remote side closed exception

When I put my thrift client reference in a using block I get a TTransportException : "Cannot read, Remote side has closed exception."
//THRIFT IDL
namespace csharp ReferenceData.API
exception EntityDoesNotExistException {
1: string Key;
}
service ReferenceDataService {
bool HelloWorld() throws (1: EntityDoesNotExistException entityDoesNotExistException);
}
namespace Server
{
public class Service: ReferenceDataService.Iface
{
public bool HelloWorld()
{
throw new EntityDoesNotExistException(){Key = "TEST KEY"};
}
}
}
namespace Server
{
class Program
{
static void Main(string[] args)
{
try
{
var processor = new ReferenceData.API.ReferenceDataService.Processor(new Service());
TServerTransport serverTransport = new TServerSocket(9094);
TServer server = new TThreadedServer(processor, serverTransport);
Console.WriteLine("Running the Payroll Service on port {0}...", "9094");
server.Serve();
}
catch (Exception x)
{
Console.WriteLine(x.StackTrace);
}
Console.ReadLine();
}
}
}
namespace Client
{
class Program
{
static void Main(string[] args)
{
var transport = new Thrift.Transport.TSocket("127.0.0.1", 9094);
transport.Open();
var service = new ReferenceDataService.Client(new Thrift.Protocol.TBinaryProtocol(transport));
using (service)
{
try
{
service.HelloWorld();
}
catch (EntityDoesNotExistException ex)
{
Console.WriteLine(ex.Key);
}
}
Console.ReadLine();
}
}
}
The remote method call actually succeeds but I have observed that the Processor.Process method is called twice and it is the second call that triggers the exception. Should the Process method be called twice? Should I be explicitly calling Dispose like this, I assumed that I should in order to close the socket as soon as possible.
The behaviour is by design.
The Process() method is called until the connection ends, typically because the client disconnects. In that case, ReadMessageBegin() fails with this exception which is expected and caught in TThreadedServer.cs, right below the Process() loop.
For the curious: The exception is thrown in TTransport.ReadAll()

C# TCP Sending Generic Objects

Ok so I'm working on a simple data entry software for work, using a 3-tier architecture. What I'm doing is basically using a common dll file to store classes with fields that are filled out when a request to the server is initialized. I have various user controls set up to take care of different ui forms, this works just fine if I open a connection and send the object directly from the form itself, but that creates a lot of redundant code. So I thought, lets make a MasterControl and create a public Connect_To_Server method to send objects over and then process the information sent back. Only problem is it keeps freezing my server.
Here is the code for my MasterControl:
public void Connect_To_Server(object obj)
{
using (TcpClient tcpClient = new TcpClient())
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("10.20.51.251"), 57657);
try
{
tcpClient.Connect(endPoint);
NetworkStream clientStream = tcpClient.GetStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(clientStream, obj);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " - " + ex.StackTrace);
}
}
}
Of course it's going to be a bit more complex later on but just for testing I've made it simple. Then from one of my ControlForms I create an object from one of the classes listed in the Common.dll, assign it it's values and then pass it to the Connect_To_Server method.
For instance a couple classes from my Common.dll
[Serializable]
public class Switch_Request // Switch class contains an integer describing a boolean request
{
public int switchID { get; set; }
}
[Serializable]
public class Send_String_List // Returns a list of strings
{
public int switchID { get; set; }
public List<string> stringsList { get; set; }
}
On my Server's side:
private void bt_StartServer_Click(object sender, EventArgs e) // Starts the server listening for clients
{
Set_String("System: Starting Services.");
tm_ActiveTime.Start();
serverListener = new TcpListener(IPAddress.Any, port);
serverThread = new Thread(new ThreadStart(Listen_For_Clients));
serverThread.Start();
}
private void Listen_For_Clients() // Listens for incoming client connections then redirects
{
serverListener.Start();
Set_String("System: Listening for connections...");
while (true)
{
tcpClient = serverListener.AcceptTcpClient();
clientThread = new Thread(new ParameterizedThreadStart(Handle_Client_Communication));
clientThread.Start(tcpClient);
}
}
private void Handle_Client_Communication(object client) // Handles incoming client communications
{
TcpClient tempClient = (TcpClient)client;
clientStream = tempClient.GetStream();
object sentObjet = formatter.Deserialize(clientStream);
Type objectType = sentObjet.GetType();
else if(objectType == typeof(Switch_Request)) // Handle - Switch Request
{
Switch_Request switchRequest = (Switch_Request)sentObjet;
object obj = new object();
if (switchRequest.switchID == 1)
{
}
else if (switchRequest.switchID == 2)
{
}
else if (switchRequest.switchID == 3)
{
}
else if (switchRequest.switchID == 4)
{
}
else if (switchRequest.switchID == 5)
{
}
else if (switchRequest.switchID == 6)
{
Send_String_List sendStringList = new Send_String_List();
sendStringList.switchID = 6;
sendStringList.stringsList = Get_Users();
obj = sendStringList;
}
else if (switchRequest.switchID == 7)
{
}
else if (switchRequest.switchID == 8)
{
}
else if (switchRequest.switchID == 9)
{
}
else if (switchRequest.switchID == 10)
{
}
formatter.Serialize(clientStream, obj);
Now I know that the object is being sent and received on the other end, as I set a little text display to popup when the object arrives on the other end, and it displays the correct object and it's type just before the server freezes. I'm just not sure why it keeps seizing up....

Sample code for JSON-RPC client in C#

I need a simple JSON-RPC 1.0 client in C#, preferably using .NET 2.0 or later.
I checked out JRock 0.9
They have several samples including Yahoo reader, but the samples demo JSON, not JSON-RPC.
I understand I could implement RPC part using any of the available JSON parsers, like JRock or two from Microsoft. I would prefer a ready sample.
2 Samples here
There are two different implementations. Read the whole thread + check the attachments
The samples above work with HTTP requests. Here's a variant that works with TCP (the Nil class is just an empty class used for requests with no return value):
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using Newtonsoft.Json.Linq;
using AustinHarris.JsonRpc;
using System.Linq;
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Reactive.Concurrency;
using System.Net.Sockets;
using System.Text;
namespace JsonRpc
{
public class JsonRpcClient
{
private static object idLock = new object();
private static int id = 0;
public Encoding encoding { get; set; }
public JsonRpcClient(IPEndPoint serviceEndpoint, Encoding encoding)
{
this.serviceEndPoint = serviceEndpoint;
this.encoding = encoding;
}
private static Stream CopyAndClose(Stream inputStream)
{
const int readSize = 256;
byte[] buffer = new byte[readSize];
MemoryStream ms = new MemoryStream();
int count = inputStream.Read(buffer, 0, readSize);
while (count > 0)
{
ms.Write(buffer, 0, count);
count = inputStream.Read(buffer, 0, readSize);
}
ms.Position = 0;
inputStream.Close();
return ms;
}
public IObservable<JsonResponse<T>> InvokeWithScheduler<T>(string method, object arg, IScheduler scheduler)
{
var req = new AustinHarris.JsonRpc.JsonRequest()
{
Method = method,
Params = new object[] { arg }
};
return InvokeRequestWithScheduler<T>(req, scheduler);
}
public IObservable<JsonResponse<T>> InvokeSingleArgument<T>(string method, object arg)
{
var req = new AustinHarris.JsonRpc.JsonRequest()
{
Method = method,
Params = new object[] { arg }
};
return InvokeRequest<T>(req);
}
public IObservable<JsonResponse<T>> InvokeWithScheduler<T>(string method, object[] args, IScheduler scheduler)
{
var req = new AustinHarris.JsonRpc.JsonRequest()
{
Method = method,
Params = args
};
return InvokeRequestWithScheduler<T>(req, scheduler);
}
public IObservable<JsonResponse<T>> Invoke<T>(string method, object[] args)
{
var req = new AustinHarris.JsonRpc.JsonRequest()
{
Method = method,
Params = args
};
return InvokeRequest<T>(req);
}
public IObservable<JsonResponse<T>> InvokeRequestWithScheduler<T>(JsonRequest jsonRpc, IScheduler scheduler)
{
var res = Observable.Create<JsonResponse<T>>((obs) =>
scheduler.Schedule(()=>{
makeRequest<T>(jsonRpc, obs);
}));
return res;
}
public IObservable<JsonResponse<T>> InvokeRequest<T>(JsonRequest jsonRpc)
{
return InvokeRequestWithScheduler<T>(jsonRpc, ImmediateScheduler.Instance);
}
private string sendAndReceive(string messageToSend) {
string res = null;
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try {
// Create a TCP/IP socket.
Socket socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Connect the socket to the remote endpoint. Catch any errors.
try {
socket.Connect(this.serviceEndPoint);
Console.Write("Socket connected to "+socket.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
byte[] msg = encoding.GetBytes(messageToSend);
// Send the data through the socket.
int bytesSent = socket.Send(msg);
// Receive the response from the remote device.
int bytesRec = socket.Receive(bytes);
res = encoding.GetString(bytes,0,bytesRec);
Console.Write("Server response = "+res);
// Release the socket.
socket.Shutdown(SocketShutdown.Both);
socket.Close();
} catch (ArgumentNullException ane) {
Console.Write("ArgumentNullException : "+ane.ToString());
} catch (SocketException se) {
Console.Write("SocketException : " + se.ToString());
} catch (Exception e) {
Console.Write("Unexpected exception : " + e.ToString());
}
} catch (Exception e) {
Console.Write(e.ToString());
}
return res;
}
private void makeRequest<T>(JsonRequest jsonRpc, IObserver<JsonResponse<T>> obs)
{
JsonResponse<T> rjson = null;
string sstream = "";
try
{
int myId;
lock (idLock)
{
myId = ++id;
}
jsonRpc.Id = myId.ToString();
}
catch (Exception ex)
{
obs.OnError(ex);
}
try
{
var json = Newtonsoft.Json.JsonConvert.SerializeObject(jsonRpc)+"\r\n";
if (typeof(T).Equals(typeof(Nil)))
{
sendAndReceive(json);
rjson = new JsonResponse<T>();
}
else
{
sstream = sendAndReceive(json);
rjson = Newtonsoft.Json.JsonConvert.DeserializeObject<JsonResponse<T>>(sstream);
}
}
catch (Exception ex)
{
obs.OnError(ex);
}
if (rjson == null)
{
string exceptionMessage = "";
try
{
JObject jo = Newtonsoft.Json.JsonConvert.DeserializeObject(sstream) as JObject;
exceptionMessage = jo["Error"].ToString();
}
catch(Exception ex){
exceptionMessage = sstream+"\r\n"+ex.Message;
}
obs.OnError(new Exception(exceptionMessage));
}
else
{
obs.OnNext(rjson);
}
obs.OnCompleted();
}
public IPEndPoint serviceEndPoint { get; set; }
}
}
Here is an example of a .net4 client exposed through Observables (Rx).
http://jsonrpc2.codeplex.com/SourceControl/changeset/view/13061#63133
Here is an almost identical wp7 client that is also exposed through Rx.
http://jsonrpc2.codeplex.com/SourceControl/changeset/view/13061#282775
Both of those examples do their work asynchronously so they may be more complicated then you are looking for, unless of course you wanted examples that were asynchronous. :)
Good Luck!

Categories

Resources