[en] Can an event/method be restricted to on recipient? And data returning events?

Topics: Technical Support
Aug 31, 2014 at 9:17 PM
Hi yallie,

I have a couple of questions referring to an intended project implementation with Zyan:

Given that I have an event which many clients hook up to can I just inform a specific one? and if so, how?
The same questions comes up for methods. In your WhisperChat you demonstrate on solution. But I wonder if it is possible to give Zyan a target information for the communication? This becomes even more important if the event handler is returning an information. This information would only be of relevance for the event firing party, wouldn't it?

If I understand the WhisperChat correctly than every client has to register the methods it wants to be callable with the host service and than the host can identify the client and its methods. The client through a key (name in WhisperChat) and the method? In WhisperChat it is only one method so there is no need for any identification. Would that be another key?

I hope that I made my questions clear enough for you to understand.

Coming back to your request to identify the areas were the documentation lacks some.

An API documentation is fine but very cumbersome to read. A more complex example with commented code would do a great job. And BTW repeating the brief explanations on multiple levels of the API reference does not help either. I know it is a major effort to do the documentation but the tools can only collect what you have provided them.

Again I think that this Framework is staggering and I really would like to use in my new project but I have to understand the implications. If I use WCF I kinda know them - and I don't want to get into it.

Looking forward to hear from you!
Peter
Coordinator
Sep 1, 2014 at 8:08 PM
Given that I have an event which many clients hook up to can I just inform a specific one? and if so, how?
 
That depends on how your clients are identified for server.
If a client has a unique name, add Name property to your EventArgs class.
Events can then be filtered at either client-side:
// client-side code
if (eventArgs.Name == myName)
{
      // react on event
}
or server-side (using event filters):
// client-side code
EventHandler<MyEventArgs> handler = myHandlerMethod;
handler.AddFilter((s, e) => e.Name == myName);
proxy.MyEvent += handler;
 
This becomes even more important if the event handler is returning an information.
This information would only be of relevance for the event firing party, wouldn't it?
 
It's impossible to return information in an event handler.
Events are asynchronous notifications, they are one-way, fire-and-forget.
When you need a return value, use a method.
Use events to notify clients about the data you want from them, and have them call a server method.
 
If I understand the WhisperChat correctly than every client has to register the methods
 
WhisperChat is just an example created to answer specific question about using callback delegates.
You don't need to replicate it in your project.
 
An API documentation is fine but very cumbersome to read.
A more complex example with commented code would do a great job.
 
That's a tough question... Sample project is a bad place to explain technical details: it's the way to demonstrate the API.
Also, complex examples aren't linear, and certainly not easy to read. Most users don't bother reading them at all.
If you have an idea of a good sample project to dissect, please share it (but not another chat application, please).
It would be great to consolidate our efforts and write an article for, say, CodeProject.
 
I have to understand the implications
 
I think that the most straightforward way to find out the implications is asking questions on this forum :)

Regards, Alex
Sep 2, 2014 at 12:24 AM
Edited Sep 2, 2014 at 8:31 PM
Thanks yallie for the quick answer.

a) I understand that events are fire & forget and shall have two parameters (object sender, xxxEventArgs e). The later should be derived from EventArgs and enriched with specific information needed on server side to identify the client and potential other payload.
b) Events are asynchronous.
c) If communication needs to be initiated bi-directional that one needs a server on each side.

That leads to a question. In such a case both server are behind firewalls were the public IP addresses of all parties are are known. Does Zyan allow
a) one server to call methods or fire events through a firewall? and
b) What connection type would be advisable for that?

What about methods? Are those asynchronous by virtue or do I have to use a TAP pattern, e.g. returning some sort of Task?
If a remote method is called I assume that Zyan is taking care of the correct return of the answer, is it? And if so are there specific request to the protocol to use?

Can I define in an Interface something like the following? (i.e. to allow a client to access a file on the server)
   Task<FileStream> GetFile (string name);
And would that be 'awaitable' on the client like
   using (var file = await GetFile (filename);
   {
       // do something
   }
Thank you for the support again! :-)

Happy Holiday!

Peter

PS.: While thinking about it I came across one issue: How are Exceptions (in methods) handled? Only local or are they propagated back to the initiating party? On events I suppose one has to deal with them locally due to the fire and forget structure of events. But on methods?
Sep 2, 2014 at 11:57 AM
Edited Sep 2, 2014 at 3:51 PM
very helpful, thanks
Sep 3, 2014 at 5:50 PM
Edited Sep 3, 2014 at 7:17 PM
hm...Yallie. here is a quesstion appeared:
That depends on how your clients are identified for server.
If a client has a unique name, add Name property to your EventArgs class.
Events can then be filtered at either client-side:
I'm using custom authentication system, based on my own authentication logic.
Hmm..okay, let's imagine, i've a lot of operations, and many clients connected to the server, does it means, that every client will receive a tons of useless traffic?
Maybe it's possible to send a message to the certain client, by sessionId? I've a list of client sessions linked with my account manager. So i simple can select specific account, and get it's session.
Sep 3, 2014 at 6:42 PM
@ Jesset3r:
As far as I understand it, this holds true for events! But NOT for method calls.
For events it seems to work exactly like standard events. Multiple subscribers and the event originator can not identify 'easily' a specific subscriber (other than through some magic in the invocation list). Therefore the originator does not really care who is interested in the event. He just broadcasts it.
So my thinking is limit the events to exactly such an use case.
If I need more control over the call and its flow I intend to use methods which can carry a payload AND return information and, I hope, are asynchronous, i.e. are 'awaitable'.

Cheers,
Peter
Sep 4, 2014 at 8:37 AM
Edited Sep 4, 2014 at 10:44 AM
Well... Here is a solution for my case:

Create new
 HashSet<IClient> _clients = new HashSet<IClient>();
   public interface IClient : IDisposable
    {
        /// <summary>
        /// Gets the SessionID of the client.
        /// </summary>
        Guid SessionId { get; }
        ServerSession Session { get; }

        /// <summary>
        /// Gets the IP address of the client.
        /// </summary>
        IPAddress ClientAddress { get; }

        /// <summary>
        /// Gets the port the client is communicating on.
        /// </summary>
        int Port { get; }

        /// <summary>
        /// Gets the Server Registered component
        /// </summary>
        IServerBehaviour ServerBehaviour { get; }

        /// <summary>
        /// Connects the client to the server at the specified address and port.
        /// </summary>
        /// <remarks>This function uses IPv4.</remarks>
        /// <param name="host">The IP address of the server to connect to.</param>
        /// <param name="port">The port to use when connecting to the server.</param>
        void Connect(string host, int port);
    }
Where IClient interface contains session information and the referrence of the session's registered component, which one wrapped with necessary methods like Send, Notify etc. (and they're will fire events, listened on the client side). On new client authenticated and logged on, where are basically creating new instance of the IClient implementation, and then adding it to the our HashSet
Coordinator
Sep 7, 2014 at 4:18 PM
Hi all and sorry guys for my late response!
I'll try to answer one by one.
Coordinator
Sep 7, 2014 at 4:29 PM
Edited Sep 7, 2014 at 4:30 PM
@phmerk
In such a case both server are behind firewalls were the public IP addresses of all parties are are known.
 
If both servers are behind firewalls, there is no way to initiate a connection between them
without a third party acting as an intermediate server, not hidden behind a firewall.

I remember an article on CodeProject demonstrating this techique using a cumbersome combination of transport
sinks and proxy servers. It might work for certain types of applications, but I suspect it wouldn't scale well.
Anyway, Zyan doesn't support such a setup where both servers are behind firewalls.
 
Does Zyan allow
a) one server to call methods or fire events through a firewall? and
b) What connection type would be advisable for that?
 
This is only possible when a server is publicly accessible and the client is behind NAT or firewall.
Duplex TCP channel allows this (TcpDuplexClientProtocolSetup/TcpDuplexServerProtocolSetup classes).
When the connection is established, both parties can use the channel to initiate communication
from the application's point of view, i.e. the client can call server's method, and the server can fire an event
or call a client's delegate.
Coordinator
Sep 7, 2014 at 4:47 PM
@phmerk
What about methods? Are those asynchronous by virtue or do I have to use a TAP pattern,
e.g. returning some sort of Task? If a remote method is called I assume that Zyan is taking care
of the correct return of the answer, is it? And if so are there specific request to the protocol to use?
 
There is no built-in support for TAP pattern (i.e. automatic handling of Task types).
But it's very easy to emulate at application level:
// shared project
public interface IMyServer
{
      int MyVeryLongMethod();
}

// client project (requires .NET 4.5)
var proxy = connection.CreateProxy<IMyServer>();
var result = await Task.Run(() => proxy.MyVeryLongMethod());
You can use extension methods if you prefer not to spoil your code with these pesky Task.Run(() => ...) snippets.
Also, you can use Zyan.Async T4 templates to generate extension methods for all interfaces in your project.
The code will look like this:
// shared project
public interface IMyServer
{
      int MyVeryLongMethod();
}

// generated code
public static class IMyServerAsyncExtensions
{
     public static Task<int> MyVeryLongMethodAsync(this IMyServer self)
     {
          return Task.Run(() => self.MyVeryLongMethod());
     }
}

// client project (requires .NET 4.5)
var proxy = connection.CreateProxy<IMyServer>();
var result = await proxy.MyVeryLongMethodAsync();
The code is here: https://github.com/yallie/Zyan.Async

Please note that Zyan.Async templates is still in beta stage, I've got no documentation for them, etc.
I use them internally, but I don't have much time to present and document them properly.
I'm planning to write an article for CodeProject about Zyan.Async generators, but I can't announce any timeframe.
Let me know if you really need it.
 
Can I define in an Interface something like the following? (i.e. to allow a client to access a file on the server)
 
No, that won't work. Use extension methods to emulate this as shown above.
Coordinator
Sep 7, 2014 at 4:54 PM
@phmerk
PS.: While thinking about it I came across one issue: How are Exceptions (in methods) handled?
Only local or are they propagated back to the initiating party? On events I suppose one has to
deal with them locally due to the fire and forget structure of events. But on methods?
 
Exceptions in methods are propagated to the calling party.
You can try/catch them on the client side (just make sure they are serializable
and don't have non-serializable inner exceptions, properties or data slots).

Exceptions in event handlers are ignored: the server doesn't care if a client fails to handle an event
because the main purpose of server is to serve all clients, even if some of them are bad guys :)
Coordinator
Sep 7, 2014 at 4:59 PM
@Jesset3r
Hmm..okay, let's imagine, i've a lot of operations, and many clients connected to the server,
does it means, that every client will receive a tons of useless traffic?
Maybe it's possible to send a message to the certain client, by sessionId?
I've a list of client sessions linked with my account manager.
So i simple can select specific account, and get it's session.
 
No, your clients won't receive any useless traffic.
That's exactly what event filters are designed for.
Please search for "event filters" at this wiki page:

https://zyan.codeplex.com/wikipage?title=What%C2%B4s%20new%20in%20Zyan%202.0%3f&referringTitle=English%20Documentation

I believe event filters deserve a dedicated page... But no one has requested it so far :)
Coordinator
Sep 7, 2014 at 5:04 PM
@phmerk
For events it seems to work exactly like standard events.
Multiple subscribers and the event originator can not identify 'easily' a specific subscriber
(other than through some magic in the invocation list). Therefore the originator does not really care
who is interested in the event. He just broadcasts it.
 
Generally speaking, no :)

This is only true if event handler has no filters attached to it.
But this isn't true for filtered events and session-bound events.
I'll try my best to describe these two on a separate documentation page and post a link here.
Coordinator
Sep 7, 2014 at 5:19 PM
Edited Sep 7, 2014 at 5:22 PM
@Jesset3r
Well... Here is a solution for my case:
 
If all you need is to route events to specific sessions, use session-bound events.
Session-bound events are events using EventArgs derived from SessionEventArgs:
// shared code
[Serializable]
public class SqlTraceEventArgs : SessionEventArgs // <--- session-bound!
{
      public string SqlQuery { get; set; }
}

public interface IServer
{
     event EventHandler<SqlTraceEventArgs> SqlQueryExecuted { get; set; }

     int ExecuteNonQuery(string sql);
}

// server code
internal class Server : IServer
{
     public event EventHandler<SqlTraceEventArgs> SqlQueryExecuted { get; set; }

     public int ExecuteNonQuery(string sql)
     {
         var handler = SqlQueryExecuted;
         if (handler != null)
         {
             handler(null, sql);
         }
     }
}
When your IServer implementation fires a SqlQueryExecuted event, by default it will be
routed to the current session owner. This is particularly useful for tracing:
// client-side code
var proxy = connection.CreateProxy<IServer>();
proxy.SqlQueryExecuted += (s,e) => Console.WriteLine("SQL: {0}", e.SqlQuery);

// this will fire a trace event, but only the current client will receive it!
var rowsAffected = proxy.ExecuteNonQuery("DELETE FROM USERS WHERE DATE_CREATED < SYSDATE - 365");
Coordinator
Sep 7, 2014 at 6:38 PM
Edited Sep 7, 2014 at 6:38 PM
Here is a fresh article about event filters:

https://zyan.codeplex.com/wikipage?title=Event%20filters
Sep 9, 2014 at 6:04 PM
hi yallie,

Thank you for the clarifications on events.

If the servers are connected via VPN then it should not be a problem for Zyan, should it?

I assume that if a communication is initiated and the network connection does not work (went down after initiating a session) an exception s thrown. Is that true for events and methods alike?
Coordinator
Sep 10, 2014 at 1:11 PM
If the servers are connected via VPN then it should not be a problem for Zyan, should it?
 
That shouldn't be a problem, but it might depend on your VPN type and configuration.
Generally speaking, if it's not a problem for plain tcp or http server, then it's not a problem for Zyan.
 
I assume that if a communication is initiated and the network connection does not work (went down
after initiating a session) an exception s thrown. Is that true for events and methods alike?
 
Yes, that's true.
When you call a method and your connection is down, you get an exception.
And when a server fires an event, it automatically cancels subscriptions of disconnected clients to save server resources.

When clients get reconnected, they re-subscribe to server events automatically.
Re-subscription of clients also happens when a server is restarted.
Marked as answer by phmerk on 9/23/2014 at 7:27 AM