Async two-way communication with Windows Named Pipes (.Net) - c#

I have a windows service and a GUI that need to communicate with each other. Either can send messages at any time.
I'm looking at using NamedPipes, but it seems that you cant read & write to the stream at the same time (or at least I cant find any examples that cover this case).
Is it possible to do this kind of two-way communication via a single NamedPipe?
Or do I need to open two pipes (one from GUI->service and one from service->GUI)?

Using WCF you can use duplex named pipes
// Create a contract that can be used as a callback
public interface IMyCallbackService
{
[OperationContract(IsOneWay = true)]
void NotifyClient();
}
// Define your service contract and specify the callback contract
[ServiceContract(CallbackContract = typeof(IMyCallbackService))]
public interface ISimpleService
{
[OperationContract]
string ProcessData();
}
Implement the Service
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class SimpleService : ISimpleService
{
public string ProcessData()
{
// Get a handle to the call back channel
var callback = OperationContext.Current.GetCallbackChannel<IMyCallbackService>();
callback.NotifyClient();
return DateTime.Now.ToString();
}
}
Host the Service
class Server
{
static void Main(string[] args)
{
// Create a service host with an named pipe endpoint
using (var host = new ServiceHost(typeof(SimpleService), new Uri("net.pipe://localhost")))
{
host.AddServiceEndpoint(typeof(ISimpleService), new NetNamedPipeBinding(), "SimpleService");
host.Open();
Console.WriteLine("Simple Service Running...");
Console.ReadLine();
host.Close();
}
}
}
Create the client application, in this example the Client class implements the call back contract.
class Client : IMyCallbackService
{
static void Main(string[] args)
{
new Client().Run();
}
public void Run()
{
// Consume the service
var factory = new DuplexChannelFactory<ISimpleService>(new InstanceContext(this), new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/SimpleService"));
var proxy = factory.CreateChannel();
Console.WriteLine(proxy.ProcessData());
}
public void NotifyClient()
{
Console.WriteLine("Notification from Server");
}
}

Using a single point to accumulate messages (a single pipe in this case) forces you to handle direction of the message yourself too (in addition to that you have to use a system-wide lock for the pipe).
So use 2 pipes with opposite directions.
(Another option would be using 2 MSMQ queues).

Your named pipe stream classes (server or client) have to be constructed with a PipeDirection of InOut. You need one NamedPipeServerStream, probably in your service, which can be shared by an arbitrary number of NamedPipeClientStream objects. Construct the NamedPipeServerStream with the name of the pipe and the direction, and the NamedPipeClientStream with the name of the pipe, the name of the server, and the PipeDirection, and you should be good to go.

Related

Communication between Topshelf service (acting as TCP server) and selfhosted OWIN WebAPI

I have a Topshelf windows service that acts as a TCP server. Inside this service, I also have a self-hosted (OWIN) WebAPI.
My goal is to somehow allow the WebAPI to communicate with the TCP server that's contained and running in the same service. Naturally I could simply use something like a "trigger" file or a shared DB that could be polled frequently, though I'd like to know of any more optimal/native ways to achieve this.
To get a better idea of the project, think of a single page application consuming my API and making certain calls with arbitrary string parameters. This data should then be passed to clients (C++ console apps using winsock) that are connected to the running TCP server.
The following Container is instantiated and passed to the Topshelf HostConfigurator
class ContainerService
{
private APIService _apiService;
private EngineService _engineService;
protected IDisposable WebAppHolder { get; set; }
public bool Start(HostControl hostControl)
{
var host = hostControl;
_apiService = new APIService();
_engineService = new EngineService();
// Initialize API service
if (WebAppHolder == null)
{
WebAppHolder = _apiService.Initialize();
}
// Initialize Engine service
_engineService.Initialize();
return true;
}
public bool Stop(HostControl hostControl)
{
// Stop API service
if (WebAppHolder != null)
{
WebAppHolder.Dispose();
WebAppHolder = null;
}
// Stop Engine service
_engineService.Stop();
return true;
}
}
Standard Topshelf stuff in program entry point (as mentioned above):
HostFactory.Run(hostConfigurator =>
{
hostConfigurator.Service<ContainerService>(containerService =>
{
containerService.WhenStarted((service, control) => service.Start(control));
containerService.WhenStopped((service, control) => service.Stop(control));
});
hostConfigurator.RunAsLocalSystem();
hostConfigurator.SetServiceName("Educe Service Host");
hostConfigurator.SetDisplayName("Communication Service");
hostConfigurator.SetDescription("Responsible for API and Engine services");
});
TCP Server:
public void Initialize()
{
_serverListener = new TcpListener(new IPEndPoint(hostAddress, (int)port));
_serverListener.Start();
_threadDoBeginAcceptTcpClient = new Thread(() => DoBeginAcceptTcpClient(_serverListener));
_threadDoBeginAcceptTcpClient.Start();
}
...
public void DoBeginAcceptTcpClient(TcpListener listener)
{
while(!_breakThread)
{
// Set the event to nonsignaled state.
TcpClientConnected.Reset();
// Start to listen for connections from a client.
Console.WriteLine("Waiting for a connection...");
// Accept the connection.
listener.BeginAcceptTcpClient(DoAcceptTcpClientCallback, listener);
// Wait until a connection is made and processed before continuing.
TcpClientConnected.WaitOne();
}
}
// Process the client connection.
public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
// Get the listener that handles the client request.
TcpListener listener = (TcpListener)ar.AsyncState;
// End the operation and display the received data on the console.
Console.WriteLine("Client connection completed");
Clients.Add(listener.EndAcceptTcpClient(ar));
// Signal the calling thread to continue.
TcpClientConnected.Set();
}
WebAPI Controller:
public class ValuesController : ApiController
{
// GET api/values/5
public string Get(int id)
{
return $"Foo: {id}";
}
}
As mentioned earlier, what I seek is "communication" between the WebAPI and the windows service. How can I pass the "id" parameter from the WebAPI call to the _engineService object in my windows service? Perhaps something similar to WPF's MVVM Light Messenger? The idea is that it would then be parsed and sent to the appropriate TcpClient that is stored in the Clients List.
Any advice on how to achieve this will be appreciated. Please feel free to ask for clarification/more code.
Did you find any answer to your issue yet ?
I don't quite understand what you try to achieve looking for a communication between the two of them ? Do you want to somehow rely on TCP/IP to relay this id or in-memory ?
Potentially, you could consider a Mediator pattern and use this kind of library that seems quite useful in the case I understood : https://github.com/jbogard/MediatR
In a simpler approach, I would rely on events to achieve what you are trying to do, which is having a reactive communication from the HTTP request to the c++ users.
Did I understand you needs ? I am quite curious about the solution
I'm assuming you are trying to take an HTTP GET request's ID parameter and send it to TCP clients who are connected to the EngineService. If your EngineService is initialized before your ApiService, I think this is a question of how to get a handle to the one-and-only EngineService instance from within an ApiService's controller instances.
If I'm following you, you could make the EngineService a public static property of your ContainerService and reference it as ContainerService.EngineService from the controller (or anywhere in the app for that matter) or better register your EngineService as a singleton in a DI container an inject it into the ApiService.
Solution (calls to WebAPI trigger EngineService)
I now use RabbitMQ/EasyNetQ to achieve communication between the WebApi and the EngineService object containing my TCP clients.
I have incidentally split them into two separate Projects/Topshelf services now.
The following is the new "communication" component and it is instantiated in the EngineService constructor.
public class Communication
{
private readonly Logger _logger;
private readonly IBus _bus;
public delegate void ReceivedEventHandler(string data);
public event ReceivedEventHandler Received;
protected virtual void OnReceive(string data)
{
Received?.Invoke(data);
}
public Communication()
{
_logger = new Logger();
_bus = RabbitHutch.CreateBus("host=localhost", reg => reg.Register<IEasyNetQLogger>(log => _logger));
SubscribeAllQueues();
}
private void SubscribeAllQueues()
{
_bus.Receive<Message>("pipeline", message =>
{
OnReceive(message.Body);
});
}
public void SubscribeQueue(string queueName)
{
_bus.Receive<Message>(queueName, message =>
{
OnReceive(message.Body);
});
}
}
An event handler is then added.
This means that as soon as a message arrives to the bus, the data will be relayed to the event handler which will subsequently relay it to the first connected TCP client in the list.
public void Handler(string data)
{
//Console.WriteLine(data);
_clients[0].Client.Send(Encoding.UTF8.GetBytes(data));
}
...
_comPipe.Received += Handler;
And finally on the WebApi's controller:
public string Get(int id)
{
ServiceCom.SendMessage("ID: " + id);
return "value";
}
ServiceCom class. Allows sending a string message on the bus.
public static class ServiceCom
{
public static void SendMessage(string messageBody)
{
var messageBus = RabbitHutch.CreateBus("host=localhost");
messageBus.Send("pipeline", new Message { Body = messageBody });
}
}
Now that this is done, I am now looking to implement a way for the connected TCP clients to trigger updates/events in an additional SPA project that will act as a Portal / Client Management App.
My approach will probably make use of KnockOut.js and SignalR to achieve dynamic Views where TCP client events are displayed immediately and similarly actions on to WebAPI will trigger events in the TCP clients. I know it sounds like a bizarre combination of processes but it is all according to plan and working out as expected :)

WCF defines it's own version of a DataObject in the Service Reference

I’ve created an object that I would like to pass in a WCF call… but inside ServiceReference1… this object is redefined… is there a way to just use the original object everywhere… it seems like people have done this but I can’t figure out what I am doing wrong.
The object is used as a parameter to a function in the service contract.
[OperationContract(IsOneWay = true)]
void UpdateInformation(MyObject myObject);
The error that I get when I try to call the function from my client is “Argument 1: cannot convert from ‘MyNameSpaceDTO.MyObject' to ‘MyNameSpace.ServiceReference1.MyObject’”
The object is in it’s own class library dll and it is marked with [DataObject] and [DataMember] attributes.
namespace MyNameSpaceDTO
{
[DataContract]
public class MyObject
{
[DataMember]
public string Name { get; set; }
….
But, also ends up in Reference.cs after adding the Service Reference as:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="MyObject", Namespace="http://schemas.datacontract.org/2004/07/MyNameSpaceDTO")]
[System.SerializableAttribute()]
public partial class MyObject : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string NameField;
...
Also, I do have the following set in the Advanced section of the Add Service Reference:
[x] Reuse types in referenced assemblies
(o) Reuse types in all referenced assemblies
For consuming a WCF service you often see samples (and they're undoubtedly advisable!) where you're instructed to add that service via the Add Service Reference dialog. By referencing a service that way your client application creates proxy classes form the WSDL exposed by the service.
As a result you end up having e.g. a class MyNameSpaceDTO.MyObject in your contract-assembly and a MyNameSpace.ServiceReference1.MyObject in your client application which was generated form the WSDL. This may seem somewhat redundant.
One situation in which you may need this behaviour could be the following: Imagine you'd want to consume an arbitrary public web service which you don't control. You have no access to the contract-assembly which defines the types etc. In that situation creating your own local proxy classes from the exposed WSDL is optimal since it's your only way to get the needed types and so on.
But your concrete situation seems to be a little bit different. I think what you're looking for is a shared contract. Since you're in control of the client and server code (and both live happily side by side in the same solution), you're in the comfortable situation to just share the contract:
So instead of adding a service reference within your client-app (via Add Service Reference), you'd just reference the contract-assembly (via the usual Add Reference dialogue). By doing this there'll by only one MyNameSpaceDTO.MyObject since the second one is never created and not needed. This approach is called contract sharing.
Please take a look at that example:
EDIT:
Please note some changes: The most important one is that you usually wouldn't want to share the assembly which holds your implementation logic of your service. So I extracted that part from the Contract-assembly and put it in a separate Implementation-assembly. By doing so, you simply share the interfaces and types and not the implementation logic. This change is reflected in the screenshot above, too.
You could set up that small solution with the following classes:
Contract - IService1.cs:
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
}
Implementation - Service1.cs:
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
Host - Program.cs:
class Program
{
static void Main(string[] args)
{
var baseAddress = new Uri("http://localhost:8732/Design_Time_Addresses/Service1/");
using (var host = new ServiceHost(typeof(Service1), baseAddress))
{
// Enable metadata publishing.
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
// Open the ServiceHost to start listening for messages. Since no endpoints are
// explicitly configured, the runtime will create one endpoint per base address
// for each service contract implemented by the service.
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
host.Close();
}
}
}
Client - Program.cs:
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press <Enter> to proceed.");
Console.ReadLine();
var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress("http://localhost:8732/Design_Time_Addresses/Service1/");
var channelFactory = new ChannelFactory<IService1>(binding, endpoint);
// Create a channel.
IService1 wcfClient1 = channelFactory.CreateChannel();
string s = wcfClient1.GetData(42);
Console.WriteLine(s);
((IClientChannel)wcfClient1).Close();
Console.WriteLine("Press <Enter> to quit the client.");
Console.ReadLine();
}
}

Pattern to Add Behaviour using New Methods at Runtime

I would like to be able to use a pattern to add behaviour (by virtue of additional methods/properties) to an existing class at runtime.
This seems very similar to the well-known decorator pattern, however, the examples that I have been able to find of the decorator pattern do not allow for the nested addition of new methods. This is best illustrated with an example:
namespace Decorator {
// classes and types
// - component:
// - concrete component:
// - decorator:
// - concrete decorator:
class Program {
static void Main(string[] args) {
IServer serverA = new Server(); // has database services
IServer serverB = new Server(); // has web services
IServer serverC = new Server(); // has both database services and web services
// add behaviour using the decorator pattern
serverA = new DatabaseServerDecorator(serverA);
serverB = new WebServerDecorator(serverB);
serverC = new DatabaseServerDecorator(serverA);
serverC = new WebServerDecorator(serverA); // note the 2nd level which causes loss of 'awareness' of the DbDecorator
// test restart of servers
serverA.RestartServer();
serverB.RestartServer();
serverC.RestartServer();
// test restart of web services
var webServerB = serverB as WebServerDecorator;
var webServerC = serverB as WebServerDecorator;
webServerB.RestartWebServices();
webServerC.RestartWebServices();
// test restart of database services
var databaseServerA = serverA as DatabaseServerDecorator;
var databaseServerC = serverC as DatabaseServerDecorator; // this will not work (HOW TO FIX??)
databaseServerA.RestartDatabaseServices();
databaseServerC.RestartDatabaseServices();
Console.ReadKey();
}
}
// IComponent
public interface IServer {
void RestartServer();
}
// Component
public class Server : IServer {
public void RestartServer() {
Console.WriteLine("Server restarted.");
}
}
// DecoratorA
public class WebServerDecorator : IServer {
IServer _server;
public WebServerDecorator(IServer server) {
_server = server;
}
public void RestartServer() {
_server.RestartServer();
}
public void RestartWebServices() {
Console.WriteLine("Web services restarted.");
}
}
public class DatabaseServerDecorator : IServer {
IServer _server;
public DatabaseServerDecorator(IServer server) {
_server = server;
}
public void RestartServer() {
_server.RestartServer();
}
public void RestartDatabaseServices() {
Console.WriteLine("Database services restarted.");
}
}
}
(The real code would use "if object is Type" for identification, but this has been removed for conciseness/clarity)
Is this possible? In the example above, it may be possible for a server to have more than one 'service', so it would not be desirable to have to create every possible permutation (which would become unmanageable as the number of services grow).
Calls to Console.WriteLine("database service ..") should belong to RestartServer() as it's logically belongs to "interface contract". That's the goal of Decorator pattern - you decorate behavior of what is provided by interface (but no more). Creating new methods (extending interface contract) is not what Decorator is meant to do. Not sure what you're trying to achieve but maybe you shouldn't over-abstracting it? How about having different interfaces like IWebServer, IDatabaseServer (implementing IServer) and decorate IWebServer, IDatabaseServer instead of IServer?

WCF service hosted Windows Service not saving state between calls

I am trying to make a simple windows service that maintains a queue of integers and accepts new integers from other applications via a WCF call. My current implementation seems to maintain separate queues for each application which communicates with it, which is not what I want.
I started by following the instructions at from Microsoft on How to: Host a WCF Service in a Managed Windows Service.
My WindowsService class looks like this:
public class MyWindowsService : ServiceBase{
public ServiceHost serviceHost = null;
public MyWindowsService(){
ServiceName = "AdHocReportService";
}
public static void Main(){
ServiceBase.Run(new MyWindowsService());
}
protected override void OnStart(string[] args){
if (serviceHost != null)
serviceHost.Close();
serviceHost = new ServiceHost(typeof(MyService));
serviceHost.Open();
}
protected override void OnStop(){
if (serviceHost != null){
serviceHost.Close();
serviceHost = null;
}
}
}
In my Service class I have a queue and an Add method. The add method returns the count of items in the queue after the add. The code looks like this:
public class MyService : IMyService
{
private Queue<int> myQueue= new Queue<int>();
public int Add(int reportId)
{
myQueue.Enqueue(reportId);
return myQueue.Count;
}
}
Lastly, I test my service using the following code in a ConsoleApp:
MyServiceClient client = new MyServiceClient();
int count = client.Add(10);
Console.WriteLine(count); //prints 1
count = client.Add(25);
Console.WriteLine(count); //prints 2
Console.ReadLine();
I would expect this to print 1 and 2 the first time my test is run, then 3 and 4 the second time, and then 5 and 6 the third and so on. However, it simply returns 1 and 2 each time, as if the Console App is instantiating the object itself and not operating on the object inside the Windows Service. What am I not understanding?
I think you want a singleton WCF service. See here.
By default, the instance mode for a WCF service is per-call. So an instance of your service is being created by the host for each call you make.
Note: When using a singleton service, your operations need to be thread safe. So I suggest switching from a Queue to a ConcurrentQueue, so you can handle multiple concurrent clients.
Alternative: Use a MSMQ binding. This will ensure you that all of your incoming messages are queued out of process, therefore persisted between restarts too.

WCF swap service interfaces

I'm new with WCF and still experimenting.
I have two ServiceContract like this:
[ServiceContract]
public interface IFirst
{
[OperationContract(IsOneWay = true)]
void First();
}
[ServiceContract]
public interface ISecond
{
[OperationContract(IsOneWay = true)]
void Second();
}
On server side Client class implementing those interfaces:
public class Client : IFirst, ISecond
{
static int count = 0;
int id;
public Client()
{
count++;
id = count;
Console.WriteLine("{0} client created.", id);
}
public void First()
{
Console.WriteLine("First from: " + id.ToString());
}
public void Second()
{
Console.WriteLine("Second: " + id.ToString());
}
}
and host:
ServiceHost host = new ServiceHost(typeof(Client), new Uri("net.tcp://localhost:8000"));
NetTcpBinding binding = new NetTcpBinding();
host.AddServiceEndpoint(typeof(IFirst), binding, "");
host.AddServiceEndpoint(typeof(ISecond), binding, "");
host.Open();
On client side:
ChannelFactory<IFirst> firstFactory = new ChannelFactory<IFirst>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8000"));
IFirst iFirst = firstFactory.CreateChannel();
iFirst.First();
ChannelFactory<ISecond> secondFactory = new ChannelFactory<ISecond>(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8000"));
ISecond iSecond = secondFactory.CreateChannel();
iSecond.First();
This works fine. It calls First and then Second method but for each call creates new instance of Client class. It is obvious because when client creates channel, service creates new instance of Client object. What I wish to achieve is call Second after First but for the same instance of Client. Is it even possible? I know I can put this two methods in one service but it is not what I wish for.
As per my understanding you want to call the two methods while creating only one client.
In WCF you can control Instancing by setting InstanceContextMode property of Service Behavior Attribute. There are three possible values
-PerCall
-PerSession
-Single
You can use PerSession as it keeps the object active for the next calls from client.
The object is released when the session ends
You can decorate your class
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerSession)]
Hope this helps.
At first I was a little confused by you calling your Service Implementation "Client" :P
But anyway, by default, WCF uses InstanceContextMode.PerCall, which means that it will instantiate a new Service implementation instance for every request into the Service.
If you want for subsequent service calls to be handled within the same service instance, you will have to use either PerSession or Single InstanceContextModes.
http://msdn.microsoft.com/en-us/library/ms731193.aspx summarises Sessions, Instances and Concurrency in WCF pretty well.

Categories

Resources