Unable to connect to multiple WCF services hosted in managed app - c#

I have a WCF service (service1). I host several instances of this service in managed application (simple .NET applacation). And I have another WCF service (service2) hosted in windows service.
When a run my application all service1 instances connect to service2 and everything goes fine. But when service2 tries to connect to any instance of service1 there is an exception "There was no endpoint listening at net.tcp://localhost:8732/TestComponent_6a4009df-cc68-4cd9-9414-16737c734548 that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details."
All services1 instances has unique addresses (see guid in uri) but similar service contracts and binding types. I use netTCP bindings with port sharing turned on.
Any advices?
Note: when I host the only one service1 instance in managed application everything goes fine. I can run several instances of my app and there are no errors too. And only when I hosted several service1 instances in one app I have problems.
There are some code:
Service1 instances creating:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Component = new TestComponent("net.tcp://localhost:8732/TestComponent", Component_OnMessageReceivedEvent);
Component.JoinServer();
Component2 = new TestComponent("net.tcp://localhost:8732/TestComponent", Component_OnMessageReceivedEvent);
//guids is added to addresses in TestComponent constructor
Component2.JoinServer();
}
How it works inside the component:
public void JoinServer()
{
this.StartComponentHosting();
if (ServerClient != null)
{
ServerClient.Close();
ServerClient = null;
}
ServerClient = new ServerClient();
ServerClient.Open(); //conneting to service2
ServerClient.JoinComponent(this.ProviderInfo); //calling some method on service2
}
private void StartComponentHosting()
{
if (ComponentHost != null)
{
ComponentHost.Close();
}
ComponentHost = new ServiceHost(this);
var portsharingBinding = new NetTcpBinding("NetTCPBindingConfig") { PortSharingEnabled = true };
ComponentHost.AddServiceEndpoint(typeof(IComponent), portsharingBinding, this.Address);
ComponentHost.Open();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
Component = new TestComponent("net.tcp://localhost:8732/TestComponent", Component_OnMessageReceivedEvent);
Component.JoinServer();
Component2 = new TestComponent("net.tcp://localhost:8732/TestComponent", Component_OnMessageReceivedEvent);
//guids is added to addresses in TestComponent constructor
Component2.JoinServer();
}
From this code section, it seems that all of your service1 instances are using the same port and adress. ASAP, it is not possible to host multiple instances on the same port, if you are not using IIS.

Related

C# Method in hosting application, turns into class in client application

I've been trying to create an application that can receive information from other running applications through WCF.
I've setup a void method in a separate class, created the interface, and hosted the service.
In my Host application I have the following method.
public Class ReceivingMethods : IReceivingMethods
{
Public void HelloWorld(string text)
{
MessageBox.Show(text);
}
}
and
[ServiceContract]
interface iReceivingMethods
{
[OperationContract]
void HelloWorld(string text);
}
In the client, I would like to do this:
HostService client = new HostService();
client.HelloWorld("Hello World");
client.close();
But it doesn't work and instead I have to do this.
HostService client = new HostService();
HelloWorld hi = new HelloWorld();
hi.text = "Hello World";
client.HelloWorld(hi);
client.close();
I've gotten it to work as the former previously in an Application/ASP combination, but not on this application and I cannot find any difference in the setup between the two applications.
Can anybody tell me what is required from the WCF setup to get it to work as the former?
HostService client = new HostService();
You haven't mention what endpoint or which class object to use.Typically the servicehost class must create the object of particular end point,something like below one.
using(System.ServiceModel.ServiceHost host =
new System.ServiceModel.ServiceHost(typeof(ReceivingMethodsnamespace.ReceivingMethods )))
{
host.Open();
Console.WriteLine("Host started # " + DateTime.Now.ToString());
Console.ReadLine();
}
Generally the hostservice must create an object of the class which is implementing servicecontract interface(servicename of AddressBindingContract file)
Turns out I found the issue somewhere else.
I configured the client service reference to "always generate message contracts"
Unchecking this and updating the service reference solved the issue.
I found the solution here.
https://social.msdn.microsoft.com/Forums/en-US/b9655eeb-cdbb-4703-87d8-00deac340173/add-service-reference-creates-message-contracts-requestresponse-objects-with-always-generate?forum=wcf

Do i need to open each client message in new thread?

I have application that host WCF service:
namespace ServiceLibrary
{
public delegate void StatusEventHandler(Capture capture);
// You have created a class library to define and implement your WCF service.
// You will need to add a reference to this library from another project and add
// the code to that project to host the service as described below. Another way
// to create and host a WCF service is by using the Add New Item, WCF Service
// template within an existing project such as a Console Application or a Windows
// Application.
[ServiceContract()]
public interface IService1
{
[OperationContract]
string ClientMsg(string str);
}
[ServiceBehavior(
ConcurrencyMode = ConcurrencyMode.Multiple,
InstanceContextMode = InstanceContextMode.PerSession)]
public class service1 : IService1
{
public event StatusEventHandler CapturingEvent;
public event StatusEventHandler OnProcessExitedEvent;
public event StatusEventHandler OnFinishEvent;
public string ClientMsg(string str)
{
return DoWork(str);
}
private DoWork(string str)
}
MyClass obj = New MyClass();
obj.Start(str); /// Do my job
}
}
}
The client send string to my server and i am opening instance of my class and this class open process, do my job and return to the client the process id number.
this server received messages from multiple clients so i wonder if i need to open new thread each time i received client message to avoid situation that several clients send message to the server in the same time.
This is how i am open the server connection in main form:
private void connect()
{
try
{
if (!isConnected)
{
// Returns a list of ipaddress configuration
IPHostEntry ips = Dns.GetHostEntry(Dns.GetHostName());
// Get machine ipaddress
IPAddress _ipAddress = IPAddress.Parse(tbServerIp.Text);
// Create the url that is needed to specify where the service should be started
urlService = "net.tcp://" + _ipAddress.ToString() + ":8000/CapturesService";
// Instruct the ServiceHost that the type that is used is a ServiceLibrary.service1
host = new ServiceHost(typeof(ServiceLibrary.service1));
//ServiceLibrary.service1 serviceInstance = new ServiceLibrary.service1();
//serviceInstance.CapturingEvent += serviceInstance_StartCapturingEvent;
//serviceInstance.OnProcessExitedEvent += serviceInstance_OnProcessExitedEvent;
//host = new ServiceHost(serviceInstance);
host.Opening += new EventHandler(host_Opening);
host.Opened += new EventHandler(host_Opened);
host.Closing += new EventHandler(host_Closing);
host.Closed += new EventHandler(host_Closed);
// The binding is where we can choose what transport layer we want to use. HTTP, TCP ect.
NetTcpBinding tcpBinding = new NetTcpBinding();
tcpBinding.TransactionFlow = false;
tcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
tcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
tcpBinding.Security.Mode = SecurityMode.None; // <- Very crucial
// Add a endpoint
host.AddServiceEndpoint(typeof(ServiceLibrary.IService1), tcpBinding, urlService);
// A channel to describe the service. Used with the proxy scvutil.exe tool
ServiceMetadataBehavior metadataBehavior;
metadataBehavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (metadataBehavior == null)
{
// Create the proxy object that is generated via the svcutil.exe tool
metadataBehavior = new ServiceMetadataBehavior();
metadataBehavior.HttpGetUrl = new Uri("http://" + _ipAddress.ToString() + ":8001/CapturesService");
metadataBehavior.HttpGetEnabled = true;
metadataBehavior.ToString();
host.Description.Behaviors.Add(metadataBehavior);
urlMeta = metadataBehavior.HttpGetUrl.ToString();
}
host.Open();
isConnected = true;
}
else
{
if (asyncWorker.IsBusy)
{
// Notify the worker thread that a cancel has been requested.
// The cancel will not actually happen until the thread in the
// DoWork checks the bwAsync.CancellationPending flag, for this
// reason we set the label to "Cancelling...", because we haven't
// actually cancelled yet.
asyncWorker.CancelAsync();
}
host.Close();
isConnected = false;
}
}
catch (Exception ex)
{
isConnected = false;
MessageBox.Show(ex.Message);
return;
}
}
private int StartTsharkProcess(Capture capture)
{
ProcessExitedEvent += Capture_ProcessExitedEvent;
string args = string.Format("-i {0} host {1} {2} -a duration:300 -w {3}",
Interface.interfaceNumber,
capture.machineIpAddress,
getTsharkFilter(),
Path.Combine(LocalPath.localPath, capture.fileName));
int processId = InvokeProcess(WiresharkProcesses.Tshark, args);
return processId;
}
this server received messages from multiple clients so i wonder if i need to open new thread each time i received client message to avoid situation that several clients send message to the server in the same time.
ServiceBehavior attribute has ConcurrencyMode Property.
This property indicates whether an instance of a service can handle one thread or multiple threads that execute concurrently, and if single-threaded, whether reentrancy is supported.
The default service behavior has ConcurrencyMode with ConcurrencyMode.Single value. So, if it is necessary to allow multiple calls at once, please use ConcurrencyMode.Multiple with notice:
No synchronization guarantees are made. Because other threads can change your service object at any time, you must handle synchronization and state consistency at all times.
Note: if service methods perform long-running tasks, clients might have a timeout.

Zero application endpoint error when I try to start a service

I think I've literally checked for all possibilities but I still keep getting this error (written in eventvwr) when I attempt to start my service:
Service cannot be started. System.InvalidOperationException: Service
'NexolNotifierWinService.NexolNotifier' has zero application
(non-infrastructure) endpoints. This might be because no configuration
file was found for your application, or because no service element
matching the service name could be found in the configuration file, or
because no endpoints were defined in the service element.
Service installation goes smoothly using installutil.
I'm genuinely not sure why I'm having this error. It's just a simple Windows Service project, so there's no app.config to mess around with either.
Here's my code:
Program.cs
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new NexolNotifierService()
};
ServiceBase.Run(ServicesToRun);
}
}
NexolNotifierService.cs
public partial class NexolNotifierService : ServiceBase
{
private ServiceHost host;
public NexolNotifierService()
{
InitializeComponent();
this.ServiceName = "NexolNotifierService";
}
protected override void OnStart(string[] args)
{
Type serviceType = typeof(NexolNotifier);
host = new ServiceHost(serviceType);
host.Open();
}
protected override void OnStop()
{
if (host != null)
host.Close();
}
}
ProjectInstaller.Designer.cs (For installing service)
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
//
// serviceProcessInstaller1
//
this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem;
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
//
// serviceInstaller1
//
this.serviceInstaller1.ServiceName = "NexolNotifierService";
this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic;
//
// ProjectInstaller
//
this.Installers.AddRange(new System.Configuration.Install.Installer[] {
this.serviceProcessInstaller1,
this.serviceInstaller1});
}
and my actual service:
NexolNotifier.cs
public class NexolNotifier
{
public NexolNotifier()
{
....
}
Service was added from add new project->Windows Service in Visual Studio 2008.
I'm just trying to get a very simple windows service working. From what I can see, there is zero reason why this shouldn't work.
What do you want to do?
If you want just a plain Windows Service - no communication, nothing - then you don't need ServiceHost! You just need to derive from the ServiceBase class in the .NET framework and implement/override some of the methods - that's all. Read values from a database, do something with them, send e-mails - whatever - you will never need a ServiceHost for this!
If you use ServiceHost then you're using the WCF infrastructure, which means, you're writing a self-hosted web service.
So what do you want to do, really??
What's the task/job that your Windows Service is supposed to do?? ServiceHost has nothing to do with a plain Windows Service! ServiceHost == WCF - always. You don't need a ServiceHost for just a plain Windows service
For just plain Windows service (no WCF), see e.g.
Creating a Basic Windows Service
Simple Windows Service Sample
and many, many more samples. Both samples show just a plain Windows service, no WCF, no ServiceHost anywhere in sight.
Add service endpoint from code like this
Uri baseAddress = new Uri("http://localhost:8095/Service");
serviceHost = new ServiceHost( typeof(YourService), baseAddress );
serviceHost.AddServiceEndpoint( typeof(IYourService), new BasicHttpBinding(), baseAddress );
serviceHost.Open();

connecting to ServiceContract?

Continuing to learn WCF, I'm trying to write a small program that would with a click of a button take the work from texbox1 , pass it to ServiceContract and get back its length.
Here's how far I got.
Form1.cs:
...
wcfLib.Service myService = new wcfLib.Service();
private void button1_Click(object sender, EventArgs e)
{
textBox2.Text = Convert.ToString( myService.go(textBox1.Text) );
}
...
and the wcf file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace wcfLib
{
[ServiceContract]
public interface IfaceService
{
[OperationContract]
int wordLen(string word);
}
public class StockService : IfaceService
{
public int wordLen(string word)
{
return word.Length;
}
}
public class Service
{
public int go( string wordin )
{
ServiceHost serviceHost = new ServiceHost(typeof(StockService), new Uri("http://localhost:8000/wcfLib"));
serviceHost.AddServiceEndpoint(typeof(IfaceService), new BasicHttpBinding(), "");
serviceHost.Open();
int ret = **///// HOW SHOULD I PASS wordin TO StockService to get word.Length in return?**
serviceHost.Close();
return ret;
}
}
}
what I can't figure out right now, is how do I pass the wordin variable above into the ServiceContract?
You need to create the client in your form and call wordLen() directly... only a class that inherits from IfaceService can be called as a WCF service. So:
// You'll have to create references to your WCF service in the project itself...
// Right-click your form project and pick 'Add Service Reference', picking
// 'Discover', which should pick up the service from the service project... else
// enter http://localhost:8000/wcfLib and hit 'Go'.
// You'll have to enter a namespace, e.g. 'MyWcfService'... that namespace is
// used to refer to the generated client, as follows:
MyWcfService.wcfLibClient client = new MyWcfService.wcfLibClient();
private void button1_Click(object sender, EventArgs e) {
// You really shouldn't have the client as a member-level variable...
textBox2.Text = Convert.ToString(client.wordLen(textBox1.Text));
}
If your Service class is meant to host the WCF Service, it needs to be its own executable and running... put the code you have in go() in Main()
Or host your WCF Service in IIS... much easier!
Edit
IIS = Internet Information Services... basically hosting the WCF Service over the web.
To host in IIS, create a new project, "WCF Service Application". You'll get a web.config and a default interface and .svc file. Rename these, or add new items, WCF Service, to the project. You'll have to read up a bit on deploying to IIS if you go that route, but for debugging in Visual Studio, this works well.
To split into two applications, just make the form its own project... the service reference is set through the application's config file; you just point it to the address of the machine or website, e.g. http://myintranet.mycompany.com:8000/wcflib or http://myserver:8000/wcflib.
Thanks for the vote!
You've definitely got things back-to-front. You don't want to create the ServiceHost in your Go method, or at least, you'd never create it in any method invoked by the client, because how could the client call it if the service hasn't been created yet?
A service in WCF is started, and THEN you can invoke its methods from a remote client. EG, this is your Main() for the service:
ServiceHost serviceHost = new ServiceHost(typeof(StockService), new Uri("http://localhost:8000/wcfLib"));
serviceHost.AddServiceEndpoint(typeof(IfaceService), new BasicHttpBinding(), "");
serviceHost.Open();
Console.WriteLine("Press return to terminate the service");
Console.ReadLine();
serviceHost.Close();
Then for your client you'd use "Add Service Reference" in Visual Studio (right-click on the Project in Solution Explorer to find this menu option) and enter the address for the service. Visual Studio will create a proxy for your service, and this is what you'd instantiate and use on the client. EG:
MyServiceClient client = new MyServiceClient();
textBox2.Text = Convert.ToString( client.wordLen(textBox1.Text) );

How can i initialise a server on startup?

I need to make some connections on startup of a server. I'm using the wcf technology for this client-server application. The problem is that the constructor of the server isn't called at any time, so for the moment, i initialize the connections when the first client makes a connection. But this generates problems in a further part.
This is my server setup:
private static ServiceHost _svc;
static void Main(string[] args)
{
NetTcpBinding binding = new NetTcpBinding(SecurityMode.Message);
Uri address = new Uri("net.tcp://localhost:8000");
_svc = new ServiceHost(typeof(MonitoringSystemService), address);
publishMetaData(_svc, "http://localhost:8001");
_svc.AddServiceEndpoint(typeof(IMonitoringSystemService), binding, "Monitoring Server");
_svc.Open();
Console.WriteLine("Listener service gestart op net.tcp://localhost:8000/Monitoring");
Console.ReadLine();
}
private static void publishMetaData(ServiceHost svc, string sEndpointAddress)
{
ServiceMetadataBehavior smb = svc.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb != null)
{
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(sEndpointAddress);
}
else
{
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.HttpGetUrl = new Uri(sEndpointAddress);
svc.Description.Behaviors.Add(smb);
}
}
How can i start the server without waiting for a client to logon so i can initialize it.
Thanks in advance.
WCF will instantiate your MonitoringSystemService class as needed. It won't instantiate it until the first client makes a connection, and if you get a lot of client connections all at once, it will instantiate a few MonitoringSystemServices to deal with the load.
You can disable this behaviour, and instead just use one instance of MonitoringSystemService that gets created when your program starts. Instead of telling WCF which type it should be automatically instantiating, you just instantiate it yourself and pass it in:
_svc = new ServiceHost(new MonitoringSystemService()), address);
You gain control of when the MonitoringSystemService contructor runs, at the expense of scalability.
Alternatively (if you need the scalability), you could "initialize the connections" in your Main method, but be aware that WCF could instantiate multiple MonitoringSystemServices that would need to share those connections.
There are two ways I can immediately think of.
One - you can implement your solution as windows service
and Second - let a dummy client program call your server at start-up.

Categories