This post has been imported from the old blog and has not yet been converted to the new syntax yet.
When the Windows Service was successfully running, a way had to be found to control it. There was a ServiceController class which allowed controlling a service and sending messages to it trough the ExecuteCommand method. This method was limited to sending integers without getting anything back. A better solution was to use Remoting to control the service.
Remoting allows for interproces communication, making objects available between different processes. An object is passed from server to client by reference, where the client can work with it as if it was a real object at the client. Remoting takes care of collecting information about the client calls and sending it to the server, where it is passed to the server object which performs the action on the client’s behalf. The result of this operation is then sent back to the client.
Remoting can transport this information over different channels, such as TCP and HTTP for example. In the project, a TCP channel was used, with the following code:
[csharp]
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace MediaService.Player {
public class PlayerService : System.ServiceProcess.ServiceBase {
private TcpChannel tcpChannel;
private void SetupRemoting() {
this.tcpChannel = new TcpChannel(this.configData.RemotingPort);
ChannelServices.RegisterChannel(this.tcpChannel);
RemotingConfiguration.ApplicationName = "MediaServicePlayer";
[/csharp]
After a channel had been setup, there were different possibilities to make a certain object available. But first, the object had to be created. This was a simple class, which inherited from MarshalByRefObject, and implemented a custom interface.
[csharp]
using System;
namespace MediaService.Player {
public class PlayerServiceController: MarshalByRefObject,
IPlayerServiceController {
[/csharp]
The interface was used, to make it possible to only make the assembly with the interface available to consumers of the remote object, instead of the implementation.
After an object was created, it was possible to register this type as a WellKnowType. There were two possibilities for this. It could be registered as a Singleton, which would make sure only instance of the object lived on the server at a given time. The other possibility was to register it as SingleCall, which would create a new object for each call. None of these two proved to be successful, because they both were unable to call methods from the service. The solution was to instantiate a new object when the service started, and to make this instance remotely available. This allowed the object to be in contact with the Windows Service, making it possible to control it. The following code published the object on tcp://host:port/MediaServicePlayerController:
[csharp]
RemotingServices.Marshal(this.playerController,
"MediaServicePlayerController");
[/csharp]
At the end, when the service was stopped, everything had to be cleaned up. The published object got disconnected and the channel got unregistered.
[csharp]
private void TearDownRemoting() {
RemotingServices.Disconnect(this.playerController);
ChannelServices.UnregisterChannel(this.tcpChannel);
} /* TearDownRemoting */
[/csharp]
Remoting allows for interproces communication, making objects available between different processes. An object is passed from server to client by reference, where the client can work with it as if it was a real object at the client. Remoting takes care of collecting information about the client calls and sending it to the server, where it is passed to the server object which performs the action on the client’s behalf. The result of this operation is then sent back to the client.
Remoting can transport this information over different channels, such as TCP and HTTP for example. In the project, a TCP channel was used, with the following code:
[csharp]
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace MediaService.Player {
public class PlayerService : System.ServiceProcess.ServiceBase {
private TcpChannel tcpChannel;
private void SetupRemoting() {
this.tcpChannel = new TcpChannel(this.configData.RemotingPort);
ChannelServices.RegisterChannel(this.tcpChannel);
RemotingConfiguration.ApplicationName = "MediaServicePlayer";
[/csharp]
After a channel had been setup, there were different possibilities to make a certain object available. But first, the object had to be created. This was a simple class, which inherited from MarshalByRefObject, and implemented a custom interface.
[csharp]
using System;
namespace MediaService.Player {
public class PlayerServiceController: MarshalByRefObject,
IPlayerServiceController {
[/csharp]
The interface was used, to make it possible to only make the assembly with the interface available to consumers of the remote object, instead of the implementation.
After an object was created, it was possible to register this type as a WellKnowType. There were two possibilities for this. It could be registered as a Singleton, which would make sure only instance of the object lived on the server at a given time. The other possibility was to register it as SingleCall, which would create a new object for each call. None of these two proved to be successful, because they both were unable to call methods from the service. The solution was to instantiate a new object when the service started, and to make this instance remotely available. This allowed the object to be in contact with the Windows Service, making it possible to control it. The following code published the object on tcp://host:port/MediaServicePlayerController:
[csharp]
RemotingServices.Marshal(this.playerController,
"MediaServicePlayerController");
[/csharp]
At the end, when the service was stopped, everything had to be cleaned up. The published object got disconnected and the channel got unregistered.
[csharp]
private void TearDownRemoting() {
RemotingServices.Disconnect(this.playerController);
ChannelServices.UnregisterChannel(this.tcpChannel);
} /* TearDownRemoting */
[/csharp]