I have the following code to setup a WCF service in code:
namespace Serviceman
{
public class Hostman
{
public Uri VServicesTCPAddress = new Uri("net.tcp://localhost:8000/v-services");
public ServiceHost VServicesHost = new ServiceHost(typeof(MyDemoService), new Uri("net.tcp://localhost:8000/v-services"));
public void ConfigureTcpService()
{
NetTcpBinding tcpBinding = new NetTcpBinding();
ServiceMetadataBehavior sMBehavior = new ServiceMetadataBehavior();
VServicesHost.Description.Behaviors.Add(sMBehavior);
VServicesHost.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
VServicesHost.AddServiceEndpoint(typeof(IAccountsService), tcpBinding, VServicesTCPAddress);
}
}
}
I have started the service and it's working just fine, but when I connect multiple instances of my client, after some time I receive errors of having used all available channels. The question now is how can I increase the default value for connection pooling limit or even remove that?
Enable port sharing on your TCP binding like this,
tcpBinding.PortSharingEnabled = true;
Or,
Change maxConnections available on your TCP binding configuration to something of your choice.The default for Max connection is 10 out of the box.
Related
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.
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();
We have a long-running asynchronous WCF service operation that grabs log files from the different components in our service. Right now, everything works correctly, but there's one more "nice to have" feature we'd like to implement.
WCF will time out asynchronous services if they take too long, but if one of our components is misbehaving, it could take a longer to give out its log file than we allot for the timeout period. If this happens, it would be nice if the client application told the user that getting log files was taking a while and asked if the user wanted to keep on waiting. If the user says yes, is there some way to resume the operation in the state it was when it timed out and reset the timeout timer?
This psuedocode shows what we have in mind:
public void GetServiceLogFiles(Action<Object> callback)
{
try
{
var gotLogFilesDelegate = (result) =>
{ var answer = WcfService.EndGetLogFiles(result);
callback(answer); };
WcfService.BeginGetLogFiles(gotLogFilesDelegate, null);
}
catch(TimeoutException)
{
var dialog = new Dialog("The service is taking a while to get the log files. Would you like to keep on waiting for it to finish?");
if(dialog.response = Dialog.YES)
Magic_happens_here_and_lets_the_Wcf_Service_continue_working_on_Get_Log_Files();
}
}
There is a way to set the timeout values. Take a look at System.ServiceModel.Channels.Binding, which has the following properties:
ReceiveTimeout
OpenTimeout
SendTimeout
CloseTimeout
These can be set when creating a service proxy.
public static class MyWcfServiceProxyFactory
{
public static MyWcfService CreateMyWcfService(string endpointUrl)
{
EndpointAddress endpointAddress = new EndpointAddress(endpointUrl);
CustomBinding customBinding = new CustomBinding();
TimeSpan timeout = new TimeSpan(0, 5, 0);
customBinding.ReceiveTimeout = timeout;
customBinding.OpenTimeout = timeout;
customBinding.SendTimeout = timeout;
customBinding.CloseTimeout = timeout;
ChannelFactory<MyWcfService> channelFactory = new ChannelFactory<MyWcfService>(customBinding, endpointAddress);
return channelFactory.CreateChannel();
}
}
The same settings are available if the binding is creating in config.
<bindings>
<basicHttpBinding>
<binding name="MyWcfService"
receiveTimeout="0:05:00"
openTimeout="0:05:00"
sendTimeout="0:05:00"
closeTimeout="0:05:00">
I do not think the timeout can be changed after the fact, so you will have to create 2 channels, one with the "normal" timeout, and one with an extended timeout. If the normal one times out, the retry attempt can use the channel with the extended timeout.
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.
How do I set IncludeExceptionDetailInFaults in code without using App.Config?
Yes, sure - on the server side, before you open the service host. This would however require that you self-host the WCF service - won't work in IIS hosting scenarios:
ServiceHost host = new ServiceHost(typeof(MyWCFService));
ServiceDebugBehavior debug = host.Description.Behaviors.Find<ServiceDebugBehavior>();
// if not found - add behavior with setting turned on
if (debug == null)
{
host.Description.Behaviors.Add(
new ServiceDebugBehavior() { IncludeExceptionDetailInFaults = true });
}
else
{
// make sure setting is turned ON
if (!debug.IncludeExceptionDetailInFaults)
{
debug.IncludeExceptionDetailInFaults = true;
}
}
host.Open();
If you need to do the same thing in IIS hosting, you'll have to create your own custom MyServiceHost descendant and a suitable MyServiceHostFactory that would instantiate such a custom service host, and reference this custom service host factory in your *.svc file.
You can also set it in the [ServiceBehavior] tag above your class declaration that inherits the interface
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyClass:IMyService
{
...
}