text: This tutorial will introduce the concepts of publishing and subscribing data over a network using the C# programming language and will hopefully provide not only an understanding of how publish and subscribe applications work but should provide the reader with the tools needed to develop a publish and subscribe style application of their own. The demo code is split into five separate projects. To start with we will look at the mechanics of how the project works and then move on to the details of each of the projects components.
  The projects were developed with Microsoft Development Environment version 7 on Windows XP.
  The project is actually run through the use of timers that at set intervals will in the case of the Publisher project the timer fires an instance that will publish anything that has registered an interest in subscribing to the information. It should be noted that in a real application there would be some kind of identifier so that the Publisher would only send certain information to certain subscribers. So at the moment the publisher will send all the subscribed information to all the subscribers. The subscriber/s have a timer that once fired redraws all the subscribed items that it has information on and then waits for the timer to fire again. At this point I am deliberately avoiding how the information gets from the publisher to the subscriber but we will get to that, first we need to see how to set up the timers correctly.
  In order to set up a timer you declare it like any other C# object,
  private Timer timer; timer = new Timer(); /// set up the timer event handler timer.Tick += new EventHandler( TimerEvent ); /// set the interval timer.Interval = 5000; /// start the timer timer.Start();
  The Timer is declared as a private member of the class which is then
  instantiated during the setting up of the project ( The above code is from the
  Publish project. ) The Timer has an Interval value that is set at the number of
  milliseconds between the timer firing and a Tick function that is an
  EventHandler object that indicates the function that is to be called when the
  timer is fired. Once these have been set the timer start can be called and the
  function will be called whenever the timer fires.
  An
  EventHandler is a special function type that is called whenever an event is
  fired be it through the use of a timer or as we will see later a callback
  function. In the case of the Timer class the Tick member is an event that takes
  a an
  EventHandler function to call when the Tick event is fired every
  Timer.Interval milliseconds. The function for the event handler is delegated to
  the function defined with the following properties,
  private void TimerEvent( object PassedObject, EventArgs TimerArgs )
  In the function declaration above both the class specification of private and
  the name of the function are up to the developer but the function must have a
  return type of void and take the two parameters defined above. The object
  variable
  PassedObject is the sender or the source of the event, because this is
  used to implement the calling of a timer function this will be the timer object
  that is defined in the class although to use it to say change the frequency of
  the call you would be required to cast it back to the type of a Timer. e.g.
  Timer tempTimer = ( Timer )PassedObject; tempTimer.Interval = ( tempTimer.Interval - 1000 );
  The
  EventArgs parameter is the event argument. That is, it is the object that
  the event is fired for. The
  EventArgs class is stateless which means that by
  itself it will hold no data. If we wish to pass data to an
  EventHandler
  function, a class must be created that inherits from
  EventArgs. This is exactly
  what will be happening with the
  FakeTicker class later. But for now that is how
  the timer works first by declaring a Timer object and a function that follows
  the
  EventHandler definition of having a void return type and takes an object as
  its first parameter and a
  EventArgs object as its second parameter. All that is
  needed then is to set up the function so that it is called when the event is
  fired by declaring a new
  EventHandler for the
  Timer.Tick event and passing the
  name of the declared function as a parameter.
  Having gotten an idea of events we now want to to do something a bit more interesting than fire them within projects. That's all well and good but what if we could use these things to get programs to talk to each other? I'm sure it would be even better if we could do it in such a way that the programs could be running on different computers at the same time, but what exactly would that involve? The answer is basically Channels. Get to love them as from now on they'll be part of every Windows release.
  The sample code uses two
  TcpChannel objects, both of which are used in the
  Windows Form classes. One is used to advertise the Publisher object and one is
  used to get the Publisher object. This means that if the code is run on two
  computers the Publish object can be fired up on one and the when the client is
  ready it can get the Publisher object. As long as the Publish application is
  running and the client knows where to find it there will be no problems.
  Naturally when publishing an object on one computer an receiving it on another the code is going to be slightly different. So let's look at Publishing an object first.
  private TcpChannel Channel; /// create the channel on port 8090 Channel = new TcpChannel( 8090 ); /// register the channelwith the runtime ChannelServices.RegisterChannel( Channel ); /// register the remote type and pass in a uri identifying string RemotingConfiguration.RegisterWellKnownServiceType( typeof( Publisher ), "PublishSubscribe", WellKnownObjectMode.Singleton );
  To start with the
  TcpChannel is created as a private member of the class and
  when it is constructed using new. the constructor is passed the value of 8090
  which is the Tcp Channel that the code will make the Publisher object available
  on. Once the
  TcpChannel is created it needs to be registered with the .NET
  runtime
  ChannelServices using the
  ChannelServices.RegisterChannel which will
  then allow the channel to be broadcast or to receive or even do both at the
  same time. Then all that has to be done is to either make the class object
  available to other computers or processes on the same machine. This is done
  using the
  RemotingConfiguration class that allows the registration of the
  object using either of the
  RegisterWellKnownType functions which come in two
  flavors the Service and the Client. To publish an object, the
  RegisterWellKnownServiceType is used. This takes the type of the object to be
  published, in this case the Publisher object, the Uri name of the published
  object and the publication type. The publication type can be either the
  WellKnownObjectMode.Singleton or the
  WellKnownObjectMode.SingleCall. The
  WellKnownObjectMode is an enumeration that contains only these two options, the
  Singleton means that every client that accesses the Publisher object will receive
  the same Publisher object and the
  SingleCall option means that for
  every client that calls into the service a new object of type Publisher will be
  created. For this project the Publisher Object is published as a Singleton as
  the Publish project that broadcasts the Publisher object later gets the object
  that it publishes itself so that it can call into the Publisher object when the
  timer is fired. Admittedly this is a fudge to make the project work and in the
  real world you would expect more than one object to be involved in the
  publication of data and the receiving of the information to be published.
  Once the object is published there needs to be a mechanism to use it. Ignoring for a moment that the publishing project subscribes to the object it publishes, lets look at the client code in the Subscribe project.
  ClientChannel = new TcpChannel( 0 ); /// register the acceptance of the required channel ChannelServices.RegisterChannel( ClientChannel ); /// get the serverobject from the required channel try { NewPublisher = ( Publisher )Activator.GetObject( typeof( Publisher ), "tcp://localhost:8090/PublishSubscribe" ); } catch( NullReferenceException nullExp ) { MessageBox.Show( "The url for the object is invalid " + nullExp.Message ); } catch( RemotingException remExp ) { MessageBox.Show( "The object type is not defined properly, " + "it needs to be derived for a remoting class " + remExp.Message ); }
  Aws with publishing an object it is necessary to first of all create a
  TcpChannel object that can be used to receive information. The important thing
  to note about the objects creation here is that the channel is created on a
  port of 0 because if at this point you try to register the Channel on the port
  8090 the application will throw an exception that says that the channel is
  already in use. Using 0 allows the client to listen on any channel the
  actual channel that the client uses is passed when we get the object from the
  publisher.
  "tcp://localhost:8090/PublishSubscribe"
  Before we can do this though we need to register the client channel in exactly the same way that the publisher is registered by calling
  ChannelServices.RegisterChannel( ClientChannel );
  Once the client is registered the publisher object is obtained by using the Activator.GetObject function.
  NewPublisher = ( Publisher )Activator.GetObject( typeof( Publisher ), "tcp://localhost:8090/PublishSubscribe" );
  The Activator class is effectively a helper class for creating objects
  remotely. The
  GetObject function returns an object that is of the type
  specified by the first parameter and the second parameter is the url of the
  object in this case the full url for the object is
  "tcp://localhost:8090/PublishSubscribe" where "tcp" is the channel protocol,
  "localhost" is the current machine address this can be Localhost as it is here
  or an actual address such as 192.2.2.2. The "PublishSubscribe" is the name of
  the project that the publisher is publishing on. Finally the object that is
  returned is cast back to its object type and the
  Publisher object
  NewPublisher
  is made equal to it. Well its made equal to the proxy of the object and not the
  actual object itself but as far as the
  NewPublisher object is concerned it is
  all the same.
  A publish and subscribe set up is based around two functions.
  /// /// declare the definition for the function /// public delegate void PublishedTickerFunction( object SourceOfEvent, FakeTicker FakeTickerArg ); /// /// declare the event to be triggered when a fake ticker is updated /// public event PublishedTickerFunction OnUpdatedFakeTicker;
  There are two keywords to take notice of here the first is a delegate and the
  second is the event keyword. A delegate is a template to a function. By
  declaring something as a delegate you are telling the compiler that at some
  point you are going to be using a function with this signature. This is used in
  much the same way as you would use the timer only in this case the delegate
  function that will be used will be in a separate project, across process
  boundaries and even across computers. As with the timer two parameters are
  declared for the function the first is the object that represents the source of
  the event . In this case whenever a function of the
  PublishedTickerFunction
  type is called the object parameter
  SourceOfEvent is equal to the Singleton
  Publisher object declared when the Publisher is published. If the call to
  RemotingConfiguration.RegisterWellKnownServiceType had taken the
  WellKnownObjectMode.SingleCall as its third parameter then the
  SourceOfEvent
  object would be equal to the individual Publisher object that would have been
  created whenever a client made a connection to the object being broadcast. The
  second parameter for the function is of the
  FakeTicker type this is an object
  that is derived from the
  EventArgs class that is used in the timer. Being a
  delegate the
  PublishedTickerFunction is not called in the way that you would
  expect if you are new to the concept of delegates. The function is not called
  this way
  Publisher.PublishedTickerFunction( object SourceOfEvent, FakeTicker FakeTickerArg );
  It is however called this way.
  NewPublisher.OnUpdatedFakeTicker += new Publisher.PublishedTickerFunction( NewSubscriber.OnSubscriberUpdate );
  The code line above from the Subscribe project shows that the Singleton
  NewPublisher object adds the the required function to be called back from the
  publisher to its event definition in the same way that the timer adds an event
  handler to its
  timer.Tick EventHandler. What is happening here is exactly the
  same as with the timer only it will go across process boundaries. The function
  to be called back when and an event is triggered is called naturally enough a
  callback function and this is declared as,
  public void OnSubscriberUpdate( object SourceOfEvent, FakeTicker fakeTickerArg )
  It can be seen from the above line that the function above declared in the
  Subscriber class takes exactly the same parameters that the
  PublishedTickerFunction specifies but the call to the
  PublishedTickerFunction
  which you will notice is called as though it were a static function, takes as
  its parameters not the arguments it specifies but a function that itself has
  the same declaration signature as declared by the
  PublishedTickerFunction.
  Which in practice means that whenever the code,
  foreach( FakeTicker fake in FakeTickerList ) { /// give it a new value fake.Calculate(); /// publish it OnUpdatedFakeTicker( this, fake ); }
  is executed all the clients that have registered with the Publisher application
  will be notified of the updates to each
  FakeTicker in the
  FakeTickerList. Which
  means that every time that the loop is run not just one but all clients will be
  called as the
  OnUpdatedFakeTicker is an event handler list and not a single
  call as it is with the time. Though seeing as the
  timer.Tick function uses the
  same += way of adding the function that is called by the timer it is theoretically
  possible at least to have more than one function being called
  whenever the timer event is triggered.
  The
  FakeTicker project is a dll that is referenced by all the other projects.
  The reason for this is that the file could either be included in every project
  which would lead to circular references where the compiler would never be able
  to release any resources allocated to the
  FakeTicker class or only included in
  some of the projects which wouldn't have the desired result for the program.
  The
  FakeTicker class is declared as,
  [Serializable] public class FakeTicker : EventArgs {
  The reason for this is that to be included in the event firing function the
  FakeTicker class must be derived from the
  EventArgs class. This is a class
  which has the Serializable attribute which means it can be passed across the
  wire, which is just a away of saying that it can be passed between processes wherever
  those processes are running. This in any case is what we are using
  the Serializable attribute for in this project, though it can be used for
  writing the object to any medium that can receive it.
  The Publish project contains the
  PublishService class that controls the Publish
  form. The class sets up a timer that fires every five seconds and publishes any
  events that the clients have subscribed to. This class publishes the Publisher
  object as a Singleton as described above and then subscribes to it itself
  using,
  NewPublisher = ( Publisher )Activator.GetObject( typeof( Publisher ), "tcp://localhost:8090/PublishSubscribe" );
  The Publisher Project is the main part of the application that contains
  the declarations of the delegate and the event functions that drive the
  application. This class also contains the
  PublishNewEvents function that
  controls calls the
  OnUpdatedTicker function which ensures that all the
  subscribed clients are called back with the latest data. This class inherits
  from
  MarshalByRefObject which is a framework class that will set up the proxies
  or code that will allow the process boundaries to be crossed while as far as
  the local code is concerned there are no process boundaries being crossed.
  The Subscribe project contains the
  SubscibeClient class that runs the Subscribe
  form and sets up the callback function with the publisher so that the
  OnSubscriberUpdate function will be called whenever the publisher fires an
  event. The
  SubscribeClient class subscribes to the published Publisher object
  and sets up a timer that runs every three seconds to check if the data has
  been updated. This is set to a shorter time than the class that publishes
  the data so that the clients always have the most relevant data but it is set at
  not too short a time so that if you have more than one Subscribe project
  running you can see the clients update at slightly different times.
  The Subscriber project contains the Subscriber class that also inherits from the
  MarshalByRefObject class that allows the callbacks that are set up in the code
  to be called when a new event is published. The class is quite simple in that
  it mainly contains the callback function that is triggered from the publisher.
  All this class does once the function is called is save the data that the
  function receives so that the Subscribe form can display it when it's own timer
  is fired.
  To run the project press F5 and the Publish application will start in debug mode. Then right click on the Subscribe Project go to Debug and left click on start new instance. Then type in a name and give it a starting value. No attempt is made for numeric accuracy so it doesn't really matter what number you set. Note there is no set limit on how many Subscribe projects you can run.
  With any luck this will enlighten more people than it confuses but as with many things in programming sometimes you just don't get them until you try them so try it. Remoting with C# can open up whole new ways of programming with server banks containing ready to use classes that only have to be picked up. Of course this probably wont happen like that as the requirements will always change slightly from project to project but think about it for a minute using this technology you can run a security database from a separate server that checks people's security access in realtime by simply getting a security object from the server and questioning it or if you're running from a large firm where a lot of things are standardised. you can programmatically setup computers just by running a small program that gets everything from the server. And the most important thing of all is that once you understand the concepts writing the code is really easy.
  General
  News
  Question
  Answer
  Joke
  Rant
  Admin