Send data to client OnMessage with WebSocket-sharp server - c#

I've been trying to solve this simple problem, but I cannot make it work.
I am using WebSocketSharp.Server. The code can be seen below.
In my NetworkClass I have someData I would like to send to the client when a message is received. The problem is the OnMessage event gets fired in a different class, and I don't know how the access the instance of this class.
Broadcasting to all clients form the NetworkClass works fine and receiving messages form the client works fine as well.
public class IndexRoute : WebSocketBehavior {
protected override void OnMessage(MessageEventArgs e) {
Console.WriteLine("Received message form client: "+e.Data);
//TODO: send someData string to client
}
}
public class NetworkClass {
String someData = "TestData";
WebSocketServer server = new WebSocketServer("ws://127.0.0.1:5000");
public NetworkClass() {
server.AddWebSocketService<IndexRoute>("/");
server.Start();
Console.WriteLine("Server started");
}
public void broadcastData() {
server.WebSocketServices["/"].Sessions.Broadcast(someData);
Console.WriteLine("Broadcast");
}
}

I combined the answers of Jeroen van Langen and Jesper. The key was to pass the instance of the NetworkClass to the IndexRoute class and access the variables from there.
server.AddWebSocketService<IndexRoute>("/", () => new IndexRoute(this));
works but is marked as obsolete.
public class IndexRoute : WebSocketBehavior {
private NetworkClass _instanceOfNetworkClass;
public IndexRoute(NetworkClass instanceOfNetworkClass)
{
_instanceOfNetworkClass = instanceOfNetworkClass;
}
protected override void OnMessage(MessageEventArgs e) {
Console.WriteLine("Received message form client: "+e.Data);
//Broadcast someData string to clients
Sessions.Broadcast(_instanceOfNetworkClass.someData);
}
}
public class NetworkClass {
public String someData = "TestData";
WebSocketServer server = new WebSocketServer("ws://127.0.0.1:5000");
public NetworkClass() {
server.AddWebSocketService<IndexRoute>("/", () => new IndexRoute(this));
server.Start();
Console.WriteLine("Server started");
}
public void broadcastData() {
server.WebSocketServices["/"].Sessions.Broadcast(someData);
Console.WriteLine("Broadcast");
}
}

I don't have any experience with WebSocketSharp, but the docs says you can give an alternate WebSocketBehavior construction function to the AddWebSocketService<>
Let me know if it works: (else i'll remove it)
public class IndexRoute : WebSocketBehavior {
private string _someData;
// define the constructor which accepts the someData
// save it in a field.
public IndexRoute(string someData)
{
_someData = someData;
}
protected override void OnMessage(MessageEventArgs e) {
Console.WriteLine("Received message form client: "+e.Data);
//TODO: send someData string to client
// do something with _someData
}
}
public class NetworkClass {
String someData = "TestData";
WebSocketServer server = new WebSocketServer("ws://127.0.0.1:5000");
public NetworkClass() {
// pass the construction function.
// (construct the IndexRoute and pass the someData to it.)
server.AddWebSocketService<IndexRoute>("/", () => new IndexRoute(someData));
server.Start();
Console.WriteLine("Server started");
}
public void broadcastData() {
server.WebSocketServices["/"].Sessions.Broadcast(someData);
Console.WriteLine("Broadcast");
}
}
I didn't tested it, but it might give you a step in the right direction to solve it.

When you inherit WebSocketBehavior, you get methods and properties that allow you to find out information about the connection you are currently talking to. In this case, just use one of the Send methods to send to the connection that sent the message:
protected override void OnMessage(MessageEventArgs e) {
Console.WriteLine("Received message form client: "+e.Data);
Send(/* pick one of the overloads to suit your needs */);
}
You can also use the property Context to get a WebSocketContext with information about the connection, or ID to find the session (connection) ID, which you could pass to another object. If the question is how you find your instance of NetworkClass, you are already constructing the IndexRoute yourself, just pass this in as an additional parameter.

Related

Fire events from ServiceHost interface

I'm followed this example to create a WCF interface between two C# projects:
https://dopeydev.com/wcf-interprocess-communication/
as you can see in the "TestService.cs" code, there is an implementation of this function:
public void SendMessage(string message)
{
MessageBox.Show(message);
}
which actually shows the received message on the server. I know the name is quite confusing, but it's the same name the client would use.
My goal is to change this function in order to fire an event to be consumed in another class.
This is what I tried to do:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class IServer : Interfaces.IService
{
public void Connect()
{
Callback = OperationContext.Current.GetCallbackChannel<Interfaces.ICallbackService>();
}
public static Interfaces.ICallbackService Callback { get; set; }
public void SendMessage(string message)
{
MessageReceivedEventArgs args = new MessageReceivedEventArgs();
args.json = message;
OnMessageReceived(this, args);
}
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
protected virtual void OnMessageReceived(object sender, MessageReceivedEventArgs e)
{
MessageReceived?.Invoke(this, e);
}
}
public class MessageReceivedEventArgs : EventArgs
{
public string json;
}
then in my other class:
class Comm
{
IServer m_server = new IServer();
public Engine()
{
var host = new ServiceHost(typeof(IServer), new Uri("net.pipe://localhost"));
host.AddServiceEndpoint(typeof(IService), new NetNamedPipeBinding(), "ipc");
host.Open();
m_server.MessageReceived += Server_MessageReceived;
}
private void Server_MessageReceived(object sender, MessageReceivedEventArgs e)
{
// this event handler is never executed!
}
}
As far as I understand, the problem is I create a new instance of the IServer class with the event handler added, but the ServiceHost which actually uses the IServer code is another instance.
Am I wrong?
I need to retrieve the instance used by ServiceHost to get the event working?
ServiceHost has an overload where you can provide your own instance for the service:
var host = new ServiceHost(m_server, new Uri("net.pipe://localhost"));
Also, you should bind the event before starting the service, otherwise you could miss requests:
m_server.MessageReceived += Server_MessageReceived;
host.Open();

Instantiating a delegate method to be used in a class library

I'm building an email-monitoring framework that I'll be using for a handful of users, so I'm building a class library to wrap everything in. I'm instantiating the configuration (sender, subject, last-received, ...) in a static class. Therefore, I have something like this.
public static class MyConfig
{
public static int Sender { get; set; }
// and so on and so forth
public static void BuildMyConfig(string theSender, string theRecipient, ...)
{
Sender = theSender;
// yada yada yada...
}
}
public class Monitoring
{
public delegate void DoSomethingWithEmail(EmailContents theContents);
public void StartMonitoring() {
//When I get an email, I call the method
DoSomethingWithEmail(theEmailWeJustGot);
}
}
Obviously, what we do with the email will be something completely different in each case. What I'm trying to is instantiate that delegate. Where would I do that? The MyConfig class and then invoke it from there as a static method? The instance of the Monitoring class?
An application would look like...
public class SpecificMonitor
{
Monitoring.BuildMyConfig("foo#bar.com", "bar#foo.com", ...);
Monitoring m = new Monitoring();
m.StartMonitoring();
//But where do I build the delegate method???
}
I've gotten compiling errors with every option I've tried so far. I've also tried overriding a method instead of using a delegate, using interfaces... but I think delegation is where it's at.
Thanks in advance!
Consistent with the rest of your design (although I do not necessarily agree that the design is great) you could allow for the callback to be set in the configuration class
public static class MyConfig
{
public static string Sender { get; set; }
public static DoSomethingWithEmail EmailReceivedCallback { get; set; }
public static void BuildMyConfig(string theSender, string theRecipient,
DoSomethingWithEmail callback)
{
Sender = theSender;
EmailReceivedCallback = callback;
}
}
// Make sure you bring the delegate outside of the Monitoring class!
public delegate void DoSomethingWithEmail(string theContents);
When an incoming email is acknowledged by your application you can now pass the email to the callback assigned to the configuration class
public class Monitoring
{
public void StartMonitoring()
{
const string receivedEmail = "New Answer on your SO Question!";
//Invoke the callback assigned to the config class
MyConfig.EmailReceivedCallback(receivedEmail);
}
}
Here is an example of usage
static void Main()
{
MyConfig.BuildMyConfig("...", "...", HandleEmail);
var monitoring = new Monitoring();
monitoring.StartMonitoring();
}
static void HandleEmail(string thecontents)
{
// Sample implementation
Console.WriteLine("Received Email: {0}",thecontents);
}
Define the constructor so that when people instantiate a Monitoring object, they must define the delegate:
public class Monitoring
{
public delegate void DoSomethingWithEmail(EmailContents theContents);
public Monitoring(Delegate DoSomethingWithEmail)
{
this.DoSomethingWithEmail = DoSomethingWithEmail;
}
public void StartMonitoring() {
//When I get an email, I call the method
DoSomethingWithEmail(theEmailWeJustGot);
}
}
Then pass in the delegate you want when you instantiate each Monitoring:
Monitoring m = new Monitoring(delegate(EmailContents theContents)
{
/* Do stuff with theContents here */
});
m.StartMonitoring();

How to send and receive from MSMQ in the same project with WCF?

I want to use WCF to get and send from/to MSMQ. FeedWorker method will take message from MQ(from queue1) and give to a thread that will process the message and then save the result to queue2. FeedWorker and ProcessCustomer in the same project.
public void FeedWorker()
{
while(true)
{
var msg = GetFromMQ();
ThreadPool.QueueUserWorkItem(ProcessCustomer, msg);
}
}
public void ProcessCustomer(object o)
{
// Do some work
// ...
SentToMQ(result);
}
To achieve this I thought to do the following using netMsmqBinding.
namespace Test
{
public class WcfService : IWcfService
{
public void Get(Customer customer)
{
ThreadPool.QueueUserWorkItem(ProcessCustomer, customer);
}
public void SaveResult(string result)
{ }
}
public void FeedWorker()
{
using (var serviceHost = new ServiceHost(typeof(WcfService)))
{
serviceHost.Open();
}
}
public void ProcessCustomer(object o)
{
// Do some work
// ...
WcfServiceClient.SaveResult(result);
}
}
I feel that I do something wrong. And as I did it I cannot receive and send to different queues. How to implement this?

Is it possible to pass a class as an argument when the same class has initialized?

Class:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)]
public class MainService : IChat
{
IChatCallback ChatCallback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
Chat chat = new Chat(this);
public void ShowChat()
{
chat.Show();
}
public void SendInstantMessage(string user, string message)
{
chat.RaiseMsgEvents(user, message);
ChatCallback.InstantMessage(user, message);
}
}
Form:
public partial class Chat : Form
{
MainService service;
public Chat(MainService service)
{
InitializeComponent();
OnMsgReceivedEvent += new OnMsgReceived(callback_OnMsgReceivedEvent);
this.service = service;
}
private void btnSend_Click(object sender, EventArgs e)
{
service.SendInstantMessage("Admin", txtMsg.Text);
}
}
The mainForm use the class like this:
public partial class Form1 : Form
{
ServiceHost host;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
host = new ServiceHost(typeof(WCF_Server.MainService));
host.Open();
}
}
In the main form, i just pass the class, no initializing, but in the class when ShowChat() called i need to show the chat form and get to this class method so i can send messages.
.NET is an object oriented language. In fact, every class is an object.
The error you are getting is because you're instantiating an object with "this" on the global level.
UPDATE
Based on your update you could do the following and it will work. You might want to refactor this some more to ensure that it's not going to break any business rules etc.
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)]
public class MainService : IChat
{
IChatCallback ChatCallback = OperationContext.Current.GetCallbackChannel<IChatCallback>();
//Changed this to be just a declaration. This will be null,
// as there is no object yet, this is really just a pointer to nothing.
//This tells the system that you might/are planning to use an object called
//chat, but it doesn't exist yet.
Chat chat;
// Get your default constructor going. This will create the actual chat object, allowing the rest of your class to access it.
public MainService()
{
//instantiate it! (or as some of our co-ops say "We're newing it")
chat = new Chat(this);
}
//now that chat is actually instantiated/created you can use it.
public void ShowChat()
{
chat.Show();
}
public void SendInstantMessage(string user, string message)
{
chat.RaiseMsgEvents(user, message);
ChatCallback.InstantMessage(user, message);
}
}
This is just a personal pet peeve, but having a function parameter the same name as a global variable is... well for me a no no. I noticed this on your Chat.Chat(MainService) function.
Of course it is, just create a method that takes this class of yours as a parameter and call it...
As other posts have suggested, you'll want to re-consider how you instantiate your chat field within your example class. I would consider lazy loading the property, like so...
private ChatForm _Chat = null;
private ChatForm Chat
{
get
{
if (this._Chat == null)
{
this._Chat = new ChatForm(this);
}
return this._Chat;
}
set { this._Chat = value; }
}
Using lazy-loading will ensure you're able to use the keyword this upon request.

sending/receiving objects through tcpclient

I have to send/recieve objects (of a custom class made by me) in my C# .NET 4.0 application and I would like a good tutorial to get me started because I've searched on Google and there seem to be a lot of problems with serialization/deserialization and although the problems were solved, there are a lot of ugly hacks.
Regards,
Alexandru Badescu
I've made a transport that does just this:
http://fadd.codeplex.com/SourceControl/changeset/view/58859#1054822
The library is work in progress, but the BinaryTransport works. It will also attempt to reconnect if it get disconnected.
Example:
public class Example
{
private BinaryTransport<Packet> _client;
private ServerExample _server;
public void Run()
{
// start server
_server = new ServerExample();
_server.Start(new IPEndPoint(IPAddress.Loopback, 1234));
// start client
_client = new BinaryTransport<Packet>(new IPEndPoint(IPAddress.Loopback, 1234));
// send stuff from client to server
_client.Send("Hello world!");
// send custom object
_client.Send(new User { FirstName = "Jonas", LastName = "Gauffin" });
}
}
public class ServerExample
{
private readonly List<BinaryTransport<Packet>> _clients = new List<BinaryTransport<Packet>>();
private SimpleServer _server;
private void OnClientAccepted(Socket socket)
{
var client = new BinaryTransport<Packet>(socket);
client.Disconnected += OnDisconnected;
client.ObjectReceived += OnObject;
_clients.Add(client);
}
private void OnDisconnected(object sender, EventArgs e)
{
var transport = (BinaryTransport<Packet>) sender;
transport.Disconnected -= OnDisconnected;
transport.ObjectReceived -= OnObject;
}
private void OnObject(object sender, ObjectEventArgs<Packet> e)
{
Console.WriteLine("We received: " + e.Object.Value);
}
public void Start(IPEndPoint listenAddress)
{
_server = new SimpleServer(listenAddress, OnClientAccepted);
_server.Start(5);
}
}
[Serializable]
public class Packet
{
public object Value { get; set; }
}
[Serializable]
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Update
I've made a new framework: http://blog.gauffin.org/2012/05/griffin-networking-a-somewhat-performant-networking-library-for-net/
If you have control over the objects you could decorate them with the [Serializable] attribute and use BinaryFormatter for serialization/deserialization.
For TCP/IP communication I highly recommend Stephen Cleary's FAQ, you should pay special attention to Message Framing. You might also want to take a look at his NitoSockets implementation.
All that assuming you can't just use WCF, of course.

Categories

Resources