Chat Client API: how to tell when a message arrived - c#

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.

Related

.NET Remoting TCPChannel analog for .NET Core

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.

Which is the better approach to launch Heavy Task from MVC .NET?

The scenario is a SQL Server that has to be updated regularly with data obtained from some API calls. Each request to the API may take about 30-200 minutes so they are not instant, and it has to be always asking the API for the new data.
The calls to the API are performed with some input parameters the user of the MVC App(like dates or names)
I was thinking in doing it as a Windows Service, that is launched/stopped from the MVC, but i donĀ“'t know if it is the best approach, cause i don't know if they can easely communicate.
An better approach will be like a Task Item that can perform heavy operations and communicate with the mvc directly. It would be so useful to see a log.
What you, experts, would recommend?
Thanks
I would use a windows service and execute a command from the website. It's quite easy:
MVC
sth like
using System.ServiceProcess;
...
public ActionResult Update()
{
int updateCommandId = 1; //example
ServiceController sc = new ServiceController("windowsServiceName");
sc.ExecuteCommand(updateCommandId);
}
and for your windows service just override OnCustomCommand:
protected override void OnCustomCommand(int commandId)
{
if(commandId == 1)
{
//do your update
}
}

Signalr with a desktop based applications in real time

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
}
}

MassTransit - Update Messages to Client

I don't have very much experience using MSMQ and someone recommended I look at MassTransit to help implement a solution but I am having a hard time trying to figure out if using MassTransit + MSMQ is the right tool for the job.
We have a WPF application (3.5) that is used by multiple users. Persistence is done from the application (via NHibernate) to the database. Up until now, users would periodically refresh there view's in order to ensure they had the latest updates. However, we now want to send notification to each application instance when an entity is persisted using pub/sub messaging. The client applications are all run within the same domain and should be able to fulfill most dependencies required (e.g. installation of MSMQ on client machines).
To summarize: Client1 publishes an update message ---> ????? ----> All other active clients receive it.
As I am new to MSMQ, I'm not even sure what the architecture should look like.
Does each client machine need to have a local MSMQ queue to receive messages?
Do we just need to create a queue on a server and all clients listen for messages there? If so, will just a queue(s) suffice or do we need to create a service in order to distribute the messages correctly?
Is this even the right tool for the job?
I created a little POC hoping that it would work, but I ended up with what I think is termed "Competing Consumer". What I would like to happen is one application instance sends a message, and all application instances receive it.
Any suggestions, direction or advice would be greatly appreciated!
Here is the POC view model code (note - in my mind localhost would be replaced with a server that each app instance would send messages to):
Update: Added Network Key (kittens)
Update: I've uploaded the sample code https://docs.google.com/viewer?a=v&pid=explorer&chrome=true&srcid=0ByDMJXKmYB7zMjBmYzYwNDEtYzMwOC00Y2RhLTk1MDYtZjc0NTI2M2E3Y2Qy&hl=en_US
public class MainViewModel : IDisposable, INotifyPropertyChanged
{
private Guid id;
public MainViewModel()
{
id = Guid.NewGuid();
Publish = new RelayCommand(x => OnExecutePublishCommand(), x => !string.IsNullOrEmpty(Message));
Messages = new ObservableCollection<MessagePayload>();
Bus.Initialize(sbc =>
{
sbc.UseMsmq();
sbc.SetNetwork("Kittens");
sbc.VerifyMsmqConfiguration();
sbc.UseMulticastSubscriptionClient();
sbc.ReceiveFrom(string.Format("msmq://localhost/{0}", ConfigurationManager.AppSettings["queue"]));
sbc.Subscribe(subs => subs.Handler<MessagePayload>(OnReceiveMessage));
});
}
public ICommand Publish { get; private set; }
private string message;
public string Message
{
get { return message; }
set
{
message = value;
SendPropertyChanged("Message");
}
}
public ObservableCollection<MessagePayload> Messages { get; private set; }
private void OnReceiveMessage(MessagePayload msg)
{
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background,
new Action(() => Messages.Add(msg)));
}
private void OnExecutePublishCommand()
{
Bus.Instance.Publish(new MessagePayload{ Sender= id, Message = Message});
Message = null;
}
public event PropertyChangedEventHandler PropertyChanged;
private void SendPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public void Dispose()
{
Bus.Instance.Dispose();
}
}
Update: Just in case anyone is interested we ended up splitting our "Event Bus" into two. For the server, we are using MassTransit. However, because Mass Transit requires "full profile" (.NET 4.0) and we wanted to stick with "client profile" for our WPF instances we are using SignalR for the client side event bus. An "observer" on the server event bus forwards messages to the client event bus.
All the machines on the same network can subscribe to given messages. They all need a local queue to read off of. Don't read off remote queues unless there's absolutely no other way.
What you described generally seems right. There's an message that gets published to all subscribers, they'll receive it and update their state. I have not worked with WPF in a while but generally how you're handling it seems acceptable. Note that it might take a little time to spin up the MT configuration, so you might want to do that on a background thread so you aren't blocking the UI.
Additionally, using the Multicast Subscription, you need to set a network key. It's automatically set to the machine name if not provided. You'll want to make sure they can talk to each other successfully.

Enterprise Library Logging: Custom trace listener which sends messages to arbitrary WCF endpoint

I'm trying to write a custom trace listener for Enterprise Library Logging which sends all log messages to an arbitrary WCF endpoint. The idea behind this is that I can set up a simple console app, etc at the other end which prints out all log messages in real time.
My question is in two parts:
Is there a mechanism to do this already? I already looked at the MSMQ listener and I'm not interested in using that because I may have a need to use a different protocol/binding at some point.
The way I have it implemented below - is it efficient enough or is there a better way? My concern is that every time a message comes through from the Logger (which may be frequent) I'm opening a new channel and then slamming it shut. Will this cause performance issues?
In my sample RemoteClient derives from ClientBase<T>.
[ConfigurationElementType(typeof(CustomTraceListenerData))]
public class RemoteTraceListener : CustomTraceListener
{
public override void Write(string message)
{
RemoteClient client = new RemoteClient();
client.Open();
client.Write(message);
client.Close();
}
public override void WriteLine(string message)
{
RemoteClient client = new RemoteClient();
client.Open();
client.WriteLine(message);
client.Close();
}
public override void TraceData(TraceEventCache eventCache, string source, TraceEventType eventType, int id, object data)
{
if (data is LogEntry && this.Formatter != null)
{
WriteLine(this.Formatter.Format(data as LogEntry));
}
else
{
WriteLine(data.ToString());
}
}
}
How often is this writing? I suggest WCF streaming as a better alternative of you're going to be logging frequently.
Failing that, it's probably a good idea to keep the client instance around as long as possible. You could try pooling it.
I found an open-source project called 'CLog' which does exactly what I'm looking for: http://clog.codeplex.com/.
A brief glance at the source code shows that he's using a singleton object to keep track of all the open channels that will receive log messages, and he's going with ChannelFactory<TChannel> as opposed to ClientBase<T> to instantiate each channel proxy. There are some threading implications that need to be addressed but I still think this is the way to fly.
It shouldn't be too hard to use this as a starting point for the implementation of my own custom trace listener which logs to WCF endpoints.
I think you should use a SQL database on witch you should log to because if you logg in a console app you could not see for examle something before 2 days.While in SQL you can make a quote and get the right data you need.
Another solution is to use the log4net project.

Categories