As .NET Remoting has been removed from .NET Core framework, I tried to use NetTcpBinding from the WCF library, but it's not included in .NET Core.
Is there some other analog of TCPChannel that I can use?
I would try to adopt a different RPC framework instead - ideally a platform-neutral one instead of one which is tightly coupled to .NET.
There are lots of options available. Just off the top of my head:
You could implement a Web API using ASP.NET Core, probably (but not necessarily) with a JSON payload.
You could use gRPC, probably (but not necessarily) using Protocol Buffers as the payload
You could use Thrift
Those are just examples - there are an awful lot of RPC and RPC-like frameworks available. None of these will be as "transparent" as using remoting, but:
They'll make it a lot clearer when you're making a network call
They'll allow you to evolve between service versions more easily
They'll allow you to use a mixture of platforms for servers and clients - which you may not need right now, but is good for future-proofing
If you have a large codebase that is based on .NET Remoting, then switching to WebAPI or gRPC could lead to rewrite half of your application.
CoreRemoting (MIT licensed) may be an alternative: https://github.com/theRainbird/CoreRemoting
It makes is possible to migrate .NET Remoting based Client/Server applications to .NET Core / .NET 5.
In contrast to gRPC or WebAPI, the procedure for CoreRemoting is very similar to .NET Remoting. Only remote method calls are made between .NET objects. A conversion of the calls to HTTP calls (building URLs with string concatenation) as with WebAPI is not necessary. Interfaces between client and server are defined in shared .NET assemblies instead of in a special interface language as with gRPC. Events and callbacks are supported out-of-the-box and can be used in a natural way for a C# developer (Compared to gRPC's more complex streaming approach).
The following example shows how a simple client/server chat application can be created using CoreRemoting.
Shared Contract Assembly
namespace HelloWorld.Shared
{
public interface ISayHelloService
{
event Action<string, string> MessageReceived;
void Say(string name, string message);
}
}
Server
using System;
using CoreRemoting;
using CoreRemoting.DependencyInjection;
using HelloWorld.Shared;
namespace HelloWorld.Server
{
public class SayHelloService : ISayHelloService
{
// Event to notify clients when users post new chat messages
public event Action<string, string> MessageReceived;
// Call via RPC to say something in the chat
public void Say(string name, string message)
{
MessageReceived?.Invoke(name, message);
}
}
public static class HelloWorldServer
{
static void Main(string[] args)
{
using var server = new RemotingServer(new ServerConfig()
{
HostName = "localhost",
NetworkPort = 9090,
RegisterServicesAction = container =>
{
// Make SayHelloSevice class available for RPC calls from clients
container.RegisterService<ISayHelloService, SayHelloService>(ServiceLifetime.Singleton);
}
});
server.Start();
Console.WriteLine("Server is running.");
Console.ReadLine();
}
}
}
Client
using System;
using CoreRemoting;
using HelloWorld.Shared;
namespace HelloWorld.Client
{
public static class HelloWorldClient
{
static void Main(string[] args)
{
using var client = new RemotingClient(new ClientConfig()
{
ServerHostName = "localhost",
ServerPort = 9090
});
client.Connect();
// Create a proxy of the remote service, which behaves almost like a regular local object
var proxy = client.CreateProxy<ISayHelloService>();
// Receive chat messages send by other remote users by event
proxy.MessageReceived += (senderName, message) =>
Console.WriteLine($"\n {senderName} says: {message}\n");
Console.WriteLine("What's your name?");
var name = Console.ReadLine();
Console.WriteLine("\nEntered chat. Type 'quit' to leave.");
bool quit = false;
while (!quit)
{
var text = Console.ReadLine();
if (text != null && text.Equals("quit", StringComparison.InvariantCultureIgnoreCase))
quit = true;
else
{
// Post a new chat message
proxy.Say(name, text);
}
}
}
}
}
CoreRemoting is only working from .NET to .NET. If you need to communicate with Javascript, Java, Python, ..., then it is not the right tool.
But if you only want to do RPC in a pure .NET environment and you want to do it in a comfortable way, thean CoreRemoting may be very helpful.
I would like to note that I am the developer of the CoreRemoting project.
Related
I'm writing 2 WPF .Net Framework applications and have various protos, clients and implementations ready to use.
The problem:
App 1 sends first request (startup routine for App 2).
App 2 receives, handles, creates object to return, returns it.
App 3 throws Grpc.Core.RpcException: {"Status(StatusCode=Cancelled, Detail=\"Cancelled\")"}
I got the desired output, didn't set a timeout, and gave no cancellation token to even be called.
My channel is setup as follows, with 127.0.0.1 and 50052 as IP and Port.
_channel = new Channel($"{MyIP}:{MyPort}, ChannelCredentials.Insecure);
My server is setup by new'ing it up, iteratively adding services, then adding a port as:
_server.Ports.Add(new ServerPort({MyIP}, {MyPort},
ServerCredentials.Insecure));
protos were compiled using grpc's auto compile methods, with `syntax="proto3". I'll add a snippet below.
service Hardware
{
// A Simple RPC.
//
// Request for the hardware to initialise.
//
// Returns the state in an enum.
rpc Initialise(StateChangeRequest) returns (State) {}
}
// Requests the change, with context coming from the command being sent.
message StateChangeRequest
{
}
// Returns the state enum, showing the different states of the hardware.
message State
{
enum Status {
UNKNOWN = 0;
INITIALISED = 1;
INITFAILED = 2;
}
Status status = 1;
}
The call is made as follows:
public async Task<bool> Initialise()
{
try
{
// Initialise hardware via client.
if (await _client.InitialiseAsync() != State.Types.Status.Initialised)
{
return false;
}
}
catch (Exception ex)
{
_logger.Error(ex);
return false;
}
return true;
}
Any further information I can think of that may help:
Target Framework is .NET Framework 4.6.2
The Google Protobuf version I'm using is 3.9.1.0
The Grpc Core version I'm using is 2.0.0.0
The Grpc Core Api version I'm using is 2.0.0.0
These versions are identical in all projects used.
Any help is greatly appreciated.
Hi I was wondering if there is an analogous API in the .NET library for creating a topic, the same way
AdminUtils.createTopic(zkClient, myTopic, 10, 1, new Properties());
is available for the java client? Otherwise, how would i go about programmatically creating a topic?
Thank you.
There is currently no Admin API in the client libraries that would allow you to do this. See issue #48 on the .NET client's GitHub.
Depending on how you configure your broker (auto.create.topics.enable), you can let topics be created automatically once you attach a producer or a consumer to them. The downside to this approach is that you can't easily set up topics with different settings, since they will be set up using the default settings configured in the broker.
A less nice, but currently the only full-featured, way to create topics is to simply call the command-line management tools (e.g. kafka-topics) from your code, and pass the settings as arguments.
You can use a simple method like below:
private void CraeteTopic(string eventName)
{
try
{
IAdminClient adminClient = new AdminClientBuilder(this._consumerConfig).Build();
TopicSpecification topicSpecification = new TopicSpecification();
topicSpecification.Name = eventName;
adminClient.CreateTopicsAsync(new[] { topicSpecification });
}
catch (CreateTopicsException createTopicsException)
{
Console.WriteLine(createTopicsException);
}
catch (Exception exception)
{
Console.WriteLine(exception);
throw;
}
}
I am writing a chat server and client in C# and a client API.
I would like to know how to allow the user of the API to be aware when a new message arrived.
I could do
while(true){
messages = clientAPI.getMessages();
// do stuff
}
but then, it will receive several time the same message.
Thanks
A common approach would be to use events to notify users when "things happen".
You could have a MessageReceived event of a custom type which provided the actual message, for example.
Without any further information on what the client API is would SignalR be a viable solution? It certainly is a perfect fit for this type of project.
If you're working under ASP.NET and have the appropriate infrastructure, I'd strongly recommend looking at the SignalR library.
SignalR on ASP.NET
I promised to post a simple event-sample. So your server-code should be something like this:
public class ClientApi
{
public EventHandler SomethingHappened;
public void StartWorkerMethod()
{
var i = 0;
while (i < 10)
{
System.Threading.Thread.Sleep(2000);
if (SomethingHappened != null)
SomethingHappened(this, EventArgs.Empty);
i++;
}
}
}
So your client would use this as follows:
var clientApi = new ClientApi();
clientApi.SomethingHappened += (s, e) => Console.WriteLine("Something happened on the server!");
clientApi.StartWorkerMethod();
If you implement this inside a console application you'll see the result coming 10 times with waits between the events.
I always knew SignalR as fitting perfectly with browser based applications in real time.
In general to pushing server side processing messages to the client, that is a "listening" web page.
It is possible to do the same with client that is not a web application, but a desktop application, pushing it in real-time?
In short, yes. The samples on github show you how, for instance the console client sample, and the documentation in the wiki shows you how you can build a .NET client. To quote that documentation (warning, version dependent, it works right now, but may be different in the future):
var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
stockTickerHub.On("notify", () =>
// Context is a reference to SynchronizationContext.Current
Context.Post(delegate
{
textBox.Text += "Notified!\n";
}, null)
);
await hubConnection.Start();
// or do the following for a synchronous method:
// connection.Start().Wait();
See ASP.NET: ASP.NET SignalR Hubs API Guide for the above code.
I have made a wrapper around the .NET client that makes it really easy to implement listeners on the local client
https://github.com/AndersMalmgren/SignalR.EventAggregatorProxy/wiki/.NET-Client
Once set up you just add a listener like
public class MyViewModel : IHandle<MyEvent>
{
public MyViewModel(IEventAggregator eventAggregator)
{
eventAggregator.Subscribe(this);
}
public void Handle(MyEvent message)
{
//Act on MyEvent
}
}
I have an interface in C#, something like this:
interface ITest
{
int Method1(int something);
}
All methods have parameters of basic types (integer, string, enum).
Now I want the implementation and the client to run on different machines communicating over a socket. What I could do manually is to make an implementation like this:
class Test : ITest
{
int Method1(int something)
{
m_Serializer.Serialize(something, m_Socket);
int result = (int)m_Serializer.Deserialize(m_Socket, typeof(int));
return result;
}
}
Is there a way to automate it, i.e. to generate such a wrapper for a given interface automatically?
I could generate it manually via Reflection.Emit, but that's quite complex. Any easy way?
WCF (Windows Communication Foundation) would be what you're looking for. It does pretty much exactly this - it does however have a somewhat steep learning curve.
I like to think of it as a framework that automatically generates a network "protocol" that is defined by your interface - the service contract. The "protocol" is also independent of the underlying network transport - there are bindings for raw TCP, HTTP, HTTPS, all with different use cases in mind.
You never have to actually care about what the network traffic actually looks like at the protocol or byte level - the whole lot is done for you seamlessly.
Clever stuff, worth learning.
Complete example of a WCF client and server over plain TCP, with no config files (all programmatic)
Create a class library which will be shared between two other programs, your client and server, containing an interface.
[ServiceContract]
public interface IMyApi
{
[OperationContract]
string SayHello(string s);
}
In program one, the server:
Add a reference to the class library above.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyApi : IMyApi
{
public string SayHello(string s)
{
return "Hello " + s;
}
}
static void Main()
{
var api = new MyApi();
var svcHost = new ServiceHost(api, new Uri("net.tcp://localhost:12345/MyService"));
svcHost.Open();
Thread.CurrentThread.Join();
}
Program two, the client:
Add a reference to the class library above.
static void Main()
{
var binding = new NetTcpBinding();
var endpoint = new EndpointAddress("net.tcp://localhost:12345/MyService");
var cf = new ChannelFactory<IMyApi>(binding, endpoint);
var client = cf.CreateChannel();
Console.WriteLine(client.SayHello("Tom")); // output on the console should be "Hello Tom"
}
While you could just serialize the data yourself (see Serialization) and deserialize on the other side, there are better options.
Windows Communication Foundation is a technology in the .NET framework which handles this for you. It automatically manages all of the communication (sockets) as well as the transfer of objects across multiple transport technologies.