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?
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
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
Related
fighting with the ServiceStack library since a while to get a basic "stream" of string to work in C#.
In short, I'm trying to replicate the basic example from "native" gRPC.
Proto buf
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (stream HelloReply);
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings.
message HelloReply {
string message = 1;
}
Server
public override async Task SayHello(HelloRequest request, IServerStreamWriter<HelloReply> responseStream, ServerCallContext context)
{
foreach (var x in Enumerable.Range(1, 10))
{
await responseStream.WriteAsync(new HelloReply
{
Message = $"Hello {request.Name} {x}"
});
await Task.Delay(200);
}
}
Client
var replies = client.SayHello(new HelloRequest { Name = "Laurent" });
await foreach (var reply in replies.ResponseStream.ReadAllAsync())
{
Console.WriteLine(reply.Message);
}
Then with the ServiceStack library, I'm not able to get the server piece done correctly. I always get a message telling me my function 'SayHello' isn't defined.
Let me know, thx !
ServiceStack gRPC implementation adopts a code-first implementation where your existing ServiceStack Services can be called from gRPC endpoints.
So instead of manually authoring a .proto file you would instead create Services using standard Request / Response DTOs and Service implementation for normal Request/Reply gRPC Services.
For Server Stream gRPC Services you would need to implement IStreamService interface in addition to inheriting from ServiceStack's Service base class.
An example of this is covered in Implementing Server Stream Services in the docs:
public class StreamFileService : Service, IStreamService<StreamFiles,FileContent>
{
public async IAsyncEnumerable<FileContent> Stream(StreamFiles request,
CancellationToken cancel = default)
{
var i = 0;
var paths = request.Paths ?? TypeConstants.EmptyStringList;
while (!cancel.IsCancellationRequested)
{
var file = VirtualFileSources.GetFile(paths[i]);
var bytes = file?.GetBytesContentsAsBytes();
var to = file != null
? new FileContent {
Name = file.Name,
Type = MimeTypes.GetMimeType(file.Extension),
Body = bytes,
Length = bytes.Length,
}
: new FileContent {
Name = paths[i],
ResponseStatus = new ResponseStatus {
ErrorCode = nameof(HttpStatusCode.NotFound),
Message = "File does not exist",
}
};
yield return to;
if (++i >= paths.Count)
yield break;
}
}
}
You would also need to register your Stream Service implementation in RegisterServices:
Plugins.Add(new GrpcFeature(App) {
RegisterServices = {
typeof(StreamFileService)
}
});
If you're using the smart C# generic gRPC Service Client you can avoid .proto descriptors and protoc generated classes entirely as you can reuse the Server DTOs in your ServiceModel project to enable an end-to-end API without code-gen:
var request = new StreamFiles {
Paths = new List<string> {
"/js/ss-utils.js",
"/js/hot-loader.js",
"/js/not-exists.js",
"/js/hot-fileloader.js",
}
};
var files = new List<FileContent>();
await foreach (var file in client.StreamAsync(request))
{
files.Add(file);
}
An alternative to sharing your ServiceModel.dll you can use C# Add ServiceStack Reference to generate your C# DTOs on the client.
For protoc generated clients you can use the x dotnet tool to Generate protoc Dart gRPC Client
$ x proto-dart https://todoworld.servicestack.net -out lib
Where you can use the serverStreamFiles API stubs to invoke the server stream Service:
var stream = client.serverStreamFiles(StreamFiles()..paths.addAll([
'/js/ss-utils.js',
'/js/hot-loader.js',
'/js/hot-fileloader.js',
]));
await for (var file in stream) {
var text = utf8.decode(file.body);
print('FILE ${file.name} (${file.length}): ${text.substring(0, text.length < 50 ? text.length : 50)} ...');
}
The todo-world/clients repo contains a number of gRPC test examples in different langauges.
In the end, here's what I end up doing as a simple POC of a stream, if this can help anyone else. No more proto-file either !
Client Program.cs :
private async static Task GetBotStream()
{
var res = client.StreamAsync(new BotStreamRequest { });
await foreach (var textReceived in res)
{
Console.WriteLine(textReceived.Result);
}
}
Client dtos.cs
[DataContract]
public partial class BotStreamRequest : IReturn<BotStreamReply>
{
}
[DataContract]
public partial class BotStreamReply
{
[DataMember(Order = 1)]
public virtual string Result { get; set; }
[DataMember(Order = 2)]
public virtual ResponseStatus ResponseStatus { get; set; }
}
Server Program.cs
public async IAsyncEnumerable<BotStreamReply> Stream(BotStreamRequest request, [EnumeratorCancellation]CancellationToken cancel = default)
{
foreach (var x in Enumerable.Range(1, 10))
{
yield return new BotStreamReply { Result = $"My stream {x}" };
}
}
Sorry, if this is a stupid question but I don't find any useful information in the internet.
Has anyone ever tried to implement the observer pattern in C# using gRPC as communication?
If yes, please show me the link.
Many thanks in advance and best regards.
I have implemented a client convenience class wrapper to turn server streaming calls into regular events for a project I am working. Not sure if this is what you are after. Here is a simple gRPC server that just publishes the time as a string once every second.
syntax = "proto3";
package SimpleTime;
service SimpleTimeService
{
rpc MonitorTime(EmptyRequest) returns (stream TimeResponse);
}
message EmptyRequest{}
message TimeResponse
{
string time = 1;
}
The server implementation, which just loops once a second returning the string representation of the current time until canceled, is as follows
public override async Task MonitorTime(EmptyRequest request, IServerStreamWriter<TimeResponse> responseStream, ServerCallContext context)
{
try
{
while (!context.CancellationToken.IsCancellationRequested)
{
var response = new TimeResponse
{
Time = DateTime.Now.ToString()
};
await responseStream.WriteAsync(response);
await Task.Delay(1000);
}
}
catch (Exception)
{
Console.WriteLine("Exception on Server");
}
}
For the client, I created a class that contains the gRPC client and exposes the results of the server streaming MonitorTime call as a plain ole .net event.
public class SimpleTimeEventClient
{
private SimpleTime.SimpleTimeService.SimpleTimeServiceClient mClient = null;
private CancellationTokenSource mCancellationTokenSource = null;
private Task mMonitorTask = null;
public event EventHandler<string> OnTimeReceived;
public SimpleTimeEventClient()
{
Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
mClient = new SimpleTime.SimpleTimeService.SimpleTimeServiceClient(channel);
}
public void Startup()
{
mCancellationTokenSource = new CancellationTokenSource();
mMonitorTask = Task.Run(() => MonitorTimeServer(mCancellationTokenSource.Token));
}
public void Shutdown()
{
mCancellationTokenSource.Cancel();
mMonitorTask.Wait(10000);
}
private async Task MonitorTimeServer(CancellationToken token)
{
try
{
using (var call = mClient.MonitorTime(new SimpleTime.EmptyRequest()))
{
while(await call.ResponseStream.MoveNext(token))
{
var timeResult = call.ResponseStream.Current;
OnTimeReceived?.Invoke(this, timeResult.Time);
}
}
}
catch(Exception e)
{
Console.WriteLine($"Exception encountered in MonitorTimeServer:{e.Message}");
}
}
}
Now create the client and subscribe to the event.
static void Main(string[] args)
{
SimpleTimeEventClient client = new SimpleTimeEventClient();
client.OnTimeReceived += OnTimeReceivedEventHandler;
client.Startup();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
client.Shutdown();
}
private static void OnTimeReceivedEventHandler(object sender, string e)
{
Console.WriteLine($"Time: {e}");
}
Which when run produces
I have left out a lot of error checking and such to make the example smaller. One thing I have done is for gRPC interfaces with many server streaming calls that may or may not be of interest to call clients, is to implement the event accessor (add,remove) to only call the server side streaming method if there is a client that has subscribed to the wrapped event. Hope this is helpful
I am using this test method (and helper class) to verify the response from an external web service:
[TestMethod]
public void WebServiceReturnsSuccessResponse()
{
using (var provider = new Provider(new Info()))
using (var result = provider.GetHttpResponseMessage())
{
Assert.IsTrue(result.IsSuccessStatusCode);
}
}
private class Info : IInfo
{
public string URL { get; set; } =
"https://notreallythe.website.com:99/service/";
public string User { get; set; } = "somename";
public string Password { get; set; } = "password1";
}
I can't get this test to pass; I always get a 500 - Internal Server Error result. I have connected via an external utility (Postman) - so the web service is up and I can connect with the url & credentials that I have.
I think the problem is in my instantiation of the HttpClient class, but I can't determine where. I am using Basic authentication:
public class Provider : IProvider, IDisposable
{
private readonly HttpClient _httpClient;
public Provider(IInfo config){
if (config == null)
throw new ArgumentNullException(nameof(config));
var userInfo = new UTF8Encoding().GetBytes($"{config.User}:{config.Password}");
_httpClient = new HttpClient
{
BaseAddress = new Uri(config.URL),
DefaultRequestHeaders =
{
Accept = { new MediaTypeWithQualityHeaderValue("application/xml")},
Authorization = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(userInfo)),
ExpectContinue = false,
},
};
}
public HttpResponseMessage GetHttpResponseMessage()
{
return _httpClient.GetAsync("1234").Result;
}
}
The response I get back appears to go to the correct endpoint; the RequestUri in the response looks exactly like I expect, https://notreallythe.website.com:99/service/1234.
You need to load up Fiddler and do a recording of the HTTP traffic when this operation succeeds (through the browser).
Then, load up your code, stand up another instance (or window) of Fiddler, and do the same thing with your code. Now, compare the two Fiddler windows to see what is different.
You only need to compare those things in Fiddler that are highlighted in blue. You can ignore the other communications.
I have made 2 Akka.NET solutions in the hope of testing out Remoting on a simple hello world example, however, I keep getting a Disassociated exception when the communication attempt is made. I have reason to believe that this is because of the shared class Greet which should be a message that both systems should understand. Unfortunately, they don't. How can I fix this?
This is the code of the "Server" application:
namespace Shared
{
public class Greet
{
public string Who { get; set; }
public Greet(string who)
{
Who = who;
}
}
}
namespace AkkaTest
{
using Shared;
class GreeterActor : ReceiveActor
{
public GreeterActor()
{
Receive<Greet>(x => Console.WriteLine("Hello {0}", x.Who));
}
}
class Program
{
static void Main(string[] args)
{
var config = ConfigurationFactory.ParseString(#"
akka {
actor.provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
remote {
helios.tcp {
port = 9099
hostname = 127.0.0.1
}
}
}
");
using (ActorSystem system = ActorSystem.Create("MyServer", config))
{
system.ActorOf<GreeterActor>("greeter");
Console.ReadLine();
system.Shutdown();
}
}
}
}
Here is the code for the client:
namespace Shared
{
public class Greet
{
public string Who { get; set; }
public Greet(string who)
{
Who = who;
}
}
}
namespace AkkaTest
{
using Shared;
class Program
{
static void Main(string[] args)
{
var config = ConfigurationFactory.ParseString(#"
akka {
actor.provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
remote {
helios.tcp {
port = 9090
hostname = 127.0.0.1
}
}
}
");
using (var system = ActorSystem.Create("MyClient", config))
{
//get a reference to the remote actor
var greeter = system
.ActorSelection("akka.tcp://MyServer#127.0.0.1:9099/user/greeter");
//send a message to the remote actor
greeter.Tell(new Greet("Roger"));
Console.ReadLine();
}
}
}
}
EDIT: Putting both client and server in the same solution but different projects, and the GreetingActor and Greet in a shared projects fixes the issues. However, I would like to have completely separate solutions.
If you are using Greet messages on both sides, you need to provide some way do share this message schema between them. Usually this is done as a separate project shared between other projects or solutions.
While default Akka.NET serializer uses fully qualified type name with assembly to serialize/deserialize messages, it's also version tolerant - you can modify message schema and gradually update it's assembly node by node.
Other option is to use custom serializer. This way you'll be able to determine by yourself, how message will be serialized/deserialized on both ends. You can read more about this topic here.
I am using the ServiceStack.Redis C# client to talk to Redis.
With few request everything is ok, but when I get LoadRunner to request it or use multi-threading to make requests, I get some errors that say I am using the wrong command.
I check the errors, and it seems that it cut off the command, or it mess up.
Here is my code, very simple. Has anyone come across this problem? The errors happen when I call the Push method using multi-threading.
public class ImpresstionQueueService : IQueueService<InsertImpressionRequest>
{
private string _queueName;
private string _host;
private static IRedisClient redisClient = new RedisClient(ConfigHost);
private static string ConfigHost
{
get
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
private string Host
{
get
{
if (!string.IsNullOrEmpty(_host))
return _host;
else
{
return ConfigurationManager.AppSettings.Get("redis_host");
}
}
}
public ImpresstionQueueService(string queue_name)
{
this._queueName = queue_name;
}
public ImpresstionQueueService(string host, string queu_name)
{
this._queueName = queu_name;
this._host = host;
}
#region IQueueService<InsertImpressionRequest> Members
class testData
{
}
public int Push(InsertImpressionRequest value)
{
try
{
//using (var redisClient = new RedisClient(this.Host))
{
//ser
string ser_value = TypeSerializer.SerializeToString<InsertImpressionRequest>(value);
//push
redisClient.AddItemToList(this._queueName, ser_value);//here will be error
}
}
catch (Exception ex)
{
HLogger.GetLogger("RedisLogger").Error(ex.Message + ex.StackTrace);
}
//throw new NotImplementedException();
return 1;
}
public InsertImpressionRequest Pop()
{
InsertImpressionRequest request = null;
//using (var redisClient = new RedisClient(this.Host))
{
string pop_string_value = redisClient.PopItemFromList(this._queueName);
//deseri
if (pop_string_value != null)
{
request = TypeSerializer.DeserializeFromString<InsertImpressionRequest>(pop_string_value);
}
}
return request;
}
#endregion
}
You are probably using the same Redis connection simultaneously from multiple threads. Both threads could possibly send commands or wait for replies at the same time. When this happens, one thread receives data intended for the other thread. This causes your error.
If you use one Redis client per thread (instead of one client per ImpresstionQueueService), each thread can send commands at the same time without interfering with each other.
Alternatively, you can create a client just for the single request (which you commented out just above the error location). The disadvantage of this alternative is the overhead of a new connection every time (which might be large or small or unnoticeable).